func main() { s := sseserver.NewServer() // create a server instance // broadcast the time every second to the "/time" namespace go func() { ticker := time.Tick(time.Duration(1 * time.Second)) for { // wait for the ticker to fire t := <-ticker // create the message payload, can be any []byte value data := []byte(t.Format("3:04:05 pm (MST)")) // send a message without an event on the "/time" namespace s.Broadcast <- sseserver.SSEMessage{"", data, "/time"} } }() // simulate sending some scoped events on the "/pets" namespace go func() { time.Sleep(time.Duration(5 * time.Second)) s.Broadcast <- sseserver.SSEMessage{"new-dog", []byte("Corgi"), "/pets"} s.Broadcast <- sseserver.SSEMessage{"new-cat", []byte("Persian"), "/pets"} time.Sleep(time.Duration(1 * time.Second)) s.Broadcast <- sseserver.SSEMessage{"new-dog", []byte("Terrier"), "/pets"} s.Broadcast <- sseserver.SSEMessage{"new-dog", []byte("Dauchsand"), "/pets"} time.Sleep(time.Duration(2 * time.Second)) s.Broadcast <- sseserver.SSEMessage{"new-cat", []byte("LOLcat"), "/pets"} }() s.Serve(":8001") // bind to port and beging serving connections }
func main() { // set up SSE server interface s := sseserver.NewServer() clients := s.Broadcast // get us some data from redis log.Println("Connecting to Redis...") initRedisPool() scoreUpdates, detailUpdates := myRedisSubscriptions() // fanout the scoreUpdates to two destinations rawScoreUpdates := make(chan RedisMsg) epsfeeder := make(chan RedisMsg) go func() { for scoreUpdate := range scoreUpdates { rawScoreUpdates <- scoreUpdate epsfeeder <- scoreUpdate } }() // Handle packing scores for eps namespace. // // This first goroutine basically grabs just the data field of a Redis msg, // and converts it to a string, because that's what my generic scorepacker // function expects to receive. // // Then, we just pipe that chan into a ScorePacker. scoreVals := make(chan string) epsScoreUpdates := ScorePacker(scoreVals, time.Duration(17*time.Millisecond)) go func() { for { scoreVals <- string((<-epsfeeder).data) } }() // goroutines to handle passing messages to the proper connection pool. // // I could use a select here and do as one goroutine, but having each be // independent could be slightly better for concurrency as these actually do // have a small amount of overhead in creating the SSEMessage so this is // theoretically better if we are running in parallel on appropriate hardware. // rawPublisher go func() { for msg := range rawScoreUpdates { clients <- sseserver.SSEMessage{ Event: "", Data: msg.data, Namespace: "/raw", } } }() // epsPublisher go func() { for val := range epsScoreUpdates { clients <- sseserver.SSEMessage{ Event: "", Data: val, Namespace: "/eps", } } }() // detailPublisher go func() { for msg := range detailUpdates { dchan := "/details/" + strings.Split(msg.channel, ".")[2] clients <- sseserver.SSEMessage{ Event: msg.channel, Data: msg.data, Namespace: dchan, } } }() // start the monitor reporter to periodically send our status to redis go adminReporter(s) gorelicMonitor() // share and enjoy port := envPort() log.Println("Starting server on port " + port) log.Println("HOLD ON TO YOUR BUTTS...") // this method blocks by design s.Serve(port) }