Exemple #1
0
/**
* 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)
		}
	}

}
Exemple #2
0
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
}
Exemple #3
0
/**
* Http request handler
 */
func (h *Hub) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	defer func() {
		if x := recover(); x != nil {
			l.Ef("request %s caused error from %s {%s}: %v", r.URL.Path, r.RemoteAddr, r.Form.Encode(), x)
		}
	}()
	w.Header().Set("Access-Control-Allow-Origin", "*")
	parts := strings.Split(r.URL.Path, "/")
	command := parts[1]
	r.ParseForm()
	startTime := time.Now()
	l.If("http serving request %s from %s {%s}", r.URL.Path, r.RemoteAddr, r.Form.Encode())
	mediator := HttpDataMediator{w: w, r: r}
	h.route(command, &mediator)
	delay := float64(time.Now().Sub(startTime).Nanoseconds()) / 1000000.0
	l.If("http Served request %s from %s {%s} took %f ms", r.URL.Path, r.RemoteAddr, r.Form.Encode(), delay)
}
Exemple #4
0
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()
}
Exemple #5
0
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")
}
Exemple #6
0
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)
	}

}
Exemple #7
0
func httpServerProcess(hub *comet.Hub, restartListener chan string) {
	var ip = flag.String("ip", "0.0.0.0", "ip address to listen on")
	var port = flag.Int("port", 8080, "port to listen on")
	flag.Parse()
	var addr = fmt.Sprintf("%s:%d", *ip, *port)
	l.If("listening on %s", addr)
	http.HandleFunc("/", hub.ServeHTTP)
	http.Handle("/ws", websocket.Handler(hub.ServeWebsocket))
	err := http.ListenAndServe(addr, nil)
	restartListener <- err.Error()
}
Exemple #8
0
func (h *Hub) createSubscriber(channels []string) Subscriber {
	l.If("subscriber creating with channels %s", channels)
	var id, err = newUUID()
	if err != nil {
		l.Ef("Error creation new uuid %s", err.Error())
	}

	subscriber := Subscriber{
		id:              id,
		commandListener: make(chan SubscriberControlCommand, 10),
		feedListener:    make(chan SubscriberFeedCommand, subscriberQueueSize),
		channels:        make(map[string]*SubscriberChannel),
	}
	channels = append(channels, fmt.Sprintf("private_%s", id))
	h.addChannelsToSubscriber(channels, &subscriber)
	subscriber.lastRequest = time.Now().Unix()
	go subscriber.subscriberCommandProcess(h)
	h.subscribers[id] = &subscriber
	l.If("subscriber %s created with channels %s", id, channels)
	return subscriber
}
Exemple #9
0
func (m *WebSocketHandler) writer() {
	l.If("wswriter process - %s - starting", m.subscriber.id)

	defer close(m.send)
	defer close(m.closeListener)
	defer m.ws.Close()
	defer l.If("wswriter process - %s - stopped", m.subscriber.id)

	for {
		select {
		case message := <-m.send:
			jsonData, _ := json.Marshal(message)
			l.If("wswriter process - %s - serve json %s", m.subscriber.id, jsonData)
			err := websocket.Message.Send(m.ws, string(jsonData))
			if err != nil {
				l.Ef("wswriter process - %s - error writing to socket: %s", m.subscriber.id, err.Error())
			}
		case command := <-m.subscriber.feedListener:
			var response = SubscriberResponse{Status: 1, Commands: command.data}
			jsonData, _ := json.Marshal(response)
			l.If("wswriter process - %s - serve data: %s", m.subscriber.id, string(jsonData))
			err := websocket.Message.Send(m.ws, string(jsonData))
			if err != nil {
				l.Ef("wswriter process - %s - error writing to socket: %s", m.subscriber.id, err.Error())
			}
		case <-m.closeListener:
			l.If("wswriter process - %s - received close command", m.subscriber.id)
			return
		case <-time.After(30 * time.Second):
			l.If("wswriter process - %s - alive", m.subscriber.id)
		}
	}

}
Exemple #10
0
/**
* receive and feed data from a channel
**/
func (r *HubRepository) dataProcess(channelName string) {
	l.If("data process - %s - start", channelName)
	for {
		select {
		// on new data
		case newData := <-r.newDataListener[channelName]:
			l.If("data process - %s - new data: %s ", channelName, newData.ToJson())
			var channel = r.channels[newData.ChannelName]
			if channel == nil {
				channel = new(Channel)
				channel.ChannelName = newData.ChannelName
				channel.DataVersion = 0
				channel.Data = ""
				r.channels[newData.ChannelName] = channel
			}
			channel.addNewData(DataOperation(newData.Command), newData.Data, newData.responseListener)
			if !strings.HasPrefix("private", channel.ChannelName) {
				// persist data
				var js, _ = json.Marshal(channel)
				var err = ioutil.WriteFile("data/"+channel.ChannelName+".json", js, 0644)
				if err != nil {
					log.Panic(err)
				}
			}
		// on data feed request
		case newRequest := <-r.getDataListener[channelName]:
			l.If("data process - %s - get data", channelName)
			var channel = r.channels[newRequest.channelName]
			var result Channel
			if channel == nil {
				result = Channel{newRequest.channelName, 0, "", time.Now(), make([]ChannelData, 0)}
			} else {
				result = channel.Copy()
			}
			newRequest.responseReceiver <- result
		}
	}
	l.If("data process - %s - stop", channelName)
}
Exemple #11
0
/**
* 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")
}