/** * process subscriber commands * when feed command is received, data must be received within 30 seconds or subscriber will unsubscribe */ func (s *Subscriber) subscriberCommandProcess(h *Hub) { l.If("subscriber process - %s - start", s.id) defer l.If("subscriber process - %s - end", s.id) for { select { case subscriberCommand := <-s.commandListener: switch subscriberCommand.command { case SubscriberStop: l.If("subscriber process - %s - stop", s.id) return case SubscriberFeed: l.If("subscriber process - %s - feed", s.id) select { case s.feedListener <- subscriberCommand.SubscriberFeedCommand: case <-time.After(30 * time.Second): l.Wf("subscriber process - %s - feed timedout", s.id) h.subscriberCommandListener <- HubSubscriberRequest{Unsubscribe, s.id, nil, nil} return } } case <-time.After(30 * time.Second): l.If("subscriber process - %s - alive", s.id) } } }
/** * handles adding, removing, cleaning and feeding subscribers */ func (h *Hub) subscribersProcess() { l.I("subscribers process - starting") for { select { case newData := <-h.subscriberFeedListener: l.If("subscribers process - newData", newData) for _, subscriber := range h.subscribers { if subscriber.channels[newData.channelData.ChannelName] != nil { select { case subscriber.commandListener <- SubscriberControlCommand{SubscriberFeed, CreateSingleFeedCommad(string(newData.operation), newData.channelData.ChannelName, newData.channelData.Data, newData.channelData.DataVersion)}: default: l.Wf("subscribers process - did not deliver new data to %s - queue full", subscriber.id) } } } case subscriberCommand := <-h.subscriberCommandListener: switch subscriberCommand.command { case Subscribe: l.I("subscribers process - subscribe") newSubscriber := h.createSubscriber(subscriberCommand.channels) subscriberCommand.responseListener <- newSubscriber case Unsubscribe: l.If("subscribers process - %s - unsubscribe", subscriberCommand.subscriberId) h.deleteSubscriber(subscriberCommand.subscriberId) subscriberCommand.responseListener <- Subscriber{} case SubscribeToChannels: l.If("subscribers process - %s - subscribe to channels", subscriberCommand.subscriberId, subscriberCommand.channels) if subscriber, found := h.subscribers[subscriberCommand.subscriberId]; found == true { h.addChannelsToSubscriber(subscriberCommand.channels, subscriber) subscriberCommand.responseListener <- *subscriber } else { subscriberCommand.responseListener <- Subscriber{} } case UnsubscribeFromChannels: l.If("subscribers process - %s - unsubscribe from channels", subscriberCommand.subscriberId, subscriberCommand.channels) if subscriber, found := h.subscribers[subscriberCommand.subscriberId]; found == true { h.removeChannelsFromSubscriber(subscriberCommand.channels, subscriber) subscriberCommand.responseListener <- *subscriber } else { subscriberCommand.responseListener <- Subscriber{} } case CleanupSubscribers: var cleanupStartTime = time.Now().Unix() for id, subscriber := range h.subscribers { if cleanupStartTime-subscriber.lastRequest > secondsToKeepSubscriberAlive { l.If("subscribers process - found dead subscriber %s", id) h.deleteSubscriber(id) } } } case <-time.After(30 * time.Second): l.If("subscribers process - alive") } } l.I("subscribers process - stopped") }
func (h *Hub) onServeFileRequest(m DataMediator, file string) { b, err := ioutil.ReadFile("web/" + file) if err != nil { l.Wf("file not found %s", "web/"+file) } if err == nil { l.Df("found file %s", file) m.WriteResponse(string(b), "plain") } }
func (m *WebSocketHandler) reader() { l.I("wsreader process - starting") var subscriberId string = "anonymous" for { var message string err := websocket.Message.Receive(m.ws, &message) if err != nil { l.If("wsreader process - %s - error reading from socket: %s", subscriberId, err.Error()) break } l.If("wsreader process - read from socket %s", string(message)) var command = new(WebSocketCommand) err = json.Unmarshal([]byte(message), command) if err != nil { l.Ef("wsreader process - %s - error unmarshal commad %s", subscriberId, err.Error()) break } var mediator = WebSocketDataMediator{send: m.send, command: *command, RequestId: command.RequestId} // special commands - keep alive and subscribe if command.Command == "keepAlive" { var subscriber = m.hub.subscribers[m.subscriber.id] // subscriber not found if subscriber == nil { l.Wf("wsreader process - %s - timed out!", subscriberId) break } else { subscriber.lastRequest = time.Now().Unix() } } else if command.Command == "subscribe" { var channels = strings.Split(mediator.ReadParameter("channels"), ",") var responseListener = make(chan Subscriber) m.hub.subscriberCommandListener <- HubSubscriberRequest{command: Subscribe, channels: channels, responseListener: responseListener} m.subscriber = <-responseListener subscriberId = m.subscriber.id go m.writer() mediator.WriteResponse(map[string]interface{}{"command": "subscribe", "subscriberId": m.subscriber.id}, "json") close(responseListener) } else { m.hub.route(command.Command, &mediator) } } m.closeListener <- true l.If("wsreader process - %s - stopped", subscriberId) m.ws.Close() }
func main() { path, err := os.Getwd() if err != nil { panic(err) } l.If("current app path: %s", path) var processes = runtime.NumCPU() runtime.GOMAXPROCS(processes) l.If("using processes %d", processes) l.I("server started.") restartLisnener := make(chan string) hub := comet.NewHub() for { go httpServerProcess(hub, restartLisnener) reason := <-restartLisnener l.Wf("web server restarted: %s", reason) } }