func NewHubRepository() *HubRepository { var repository = new(HubRepository) repository.channels = make(map[string]*Channel) repository.getChannelListener = make(chan HubRepositoryChannelGetCommand, expectedMaxSubscribers) repository.newDataListener = make(map[string]chan ChannelDataInputCommand, expectedMaxSubscribers) repository.getDataListener = make(map[string]chan ChannelDataRequestCommand, expectedMaxSubscribers) if restoreData { l.I("restoring channels") // read previous data var files, err = ioutil.ReadDir("data") if err == nil { for i := 0; i < len(files); i++ { var file = files[i] if !strings.HasSuffix(file.Name(), ".json") { continue } var data, err = ioutil.ReadFile("data/" + file.Name()) if err == nil { l.If("restoring channel %s", file.Name()) var channel = new(Channel) var err = json.Unmarshal(data, channel) if err == nil && strings.Trim(channel.ChannelName, "") != "" { repository.addCreatedChannel(channel) } } } } l.I("restoring channels completed.") } // start channel process go repository.channelProcess() return repository }
/** * 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) refreshStatusProcess() { l.I("status process - start") defer l.I("status process - end") for { var data, _ = json.Marshal(createHubStatus(h)) h.subscriberCommandListener <- HubSubscriberRequest{CleanupSubscribers, "", nil, nil} h.AddNewDataToChannel("create", "system", string(data)) l.I("status process - checked system") time.Sleep(refreshStatusPeriod) } }
func (r *HubRepository) channelProcess() { l.I("channels process - start") for { var channelRequest = <-r.getChannelListener var channel = r.channels[channelRequest.channelName] if channel == nil { l.If("channels process - add channel %s", channelRequest.channelName) channel = new(Channel) channel.ChannelName = channelRequest.channelName channel.DataVersion = 0 channel.Data = "" r.addCreatedChannel(channel) } l.If("channels process - served channel %s", channelRequest.channelName) channelRequest.resultListener <- HubRepositoryChannelFeeds{newDataListener: r.newDataListener[channel.ChannelName], getDataListener: r.getDataListener[channel.ChannelName]} } l.I("channels process - end") }
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) } }