func (p WsMessageReceiver) handlePublish(im interceptorMessage, msg *gowamp.Publish) (interface{}, error) {

	if string(msg.Topic) == "wamp.session.on_leave" {
		args := msg.Arguments
		if len(args) == 0 {
			return nil, nil
		}

		if leavingSessionId, ok := args[0].(gowamp.ID); ok {
			log.Info("Broadcasting session leave:", leavingSessionId)
			p.broadcaster.Broadcast(leavingSessionId)
			return nil, nil
		}

		log.Info("Leave:", args)
		return nil, nil
	}

	if string(msg.Topic) == "wamp.session.on_join" {
		return nil, nil
	}

	if len(msg.Arguments) == 0 {
		return nil, nil
	}

	m, ok := msg.Arguments[0].(string)
	if !ok {
		m = models.String(msg.Arguments[0])
	}

	var clientMessage messaging.Message
	converError := clientMessage.FromString(m)
	if converError != nil {
		log.Error(converError)
		return nil, converError
	}

	if clientMessage.Origin == messaging.ORIGIN_API {
		return nil, nil
	}

	log.Info("Websocket message received:", clientMessage)
	data, apiError := p.ClientProcessor.Process(clientMessage)
	if apiError != nil {
		log.Error(apiError)
	}

	return data, apiError
}
Beispiel #2
0
func main() {
	r.SetVerbose(true)

	defer utils.Recover()
	utils.ListenSignals()
	utils.Liveness()

	if os.Getenv("DEBUG_N") != "true" {
		gin.SetMode(gin.ReleaseMode)
	}

	engine := gin.New()

	engine.Use(gin.Recovery())
	engine.Use(func() gin.HandlerFunc {
		return func(c *gin.Context) {
			defer c.Next()
			log.Info(c.Request.Method, c.Request.URL.Path, c.Writer.Status())
		}
	}())

	api.Initialize(engine)

	engine.Run(config.Get(config.KEY_API_PORT))
}
Beispiel #3
0
func NewWebSocketServer() (*gowamp.WebsocketServer, *gowamp.Client, *wsInterceptor, error) {
	interceptor := NewWsInterceptor()

	r := gowamp.Realm{}
	r.Interceptor = interceptor

	realms := map[string]gowamp.Realm{}
	realms[config.CONST_DEFAULT_REALM] = r
	wsServer, err := gowamp.NewWebsocketServer(realms)
	if err != nil {
		return nil, nil, nil, err
	}

	wsServer.Upgrader.CheckOrigin = func(r *http.Request) bool {
		//allow connections from any origin
		return true
	}

	c, err := wsServer.GetLocalClient(config.CONST_DEFAULT_REALM, nil)
	if err != nil {
		log.Error(err)
		return nil, nil, nil, err
	}

	http.Handle("/", wsServer)
	http.HandleFunc("/_status", func(w http.ResponseWriter, r *http.Request) {
		log.Info("_status check")
		//we are fine
	})

	return wsServer, c, interceptor, nil
}
Beispiel #4
0
func processHeadersMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		optionsHeader := c.Request.Header.Get(CONTEXT_HEADER_OPTIONS)
		if optionsHeader == "" {
			optionsHeader = "{}"
		}

		var options models.Options
		options.FromString(optionsHeader)

		if options.Notify == nil {
			notify := true
			options.Notify = &notify
		}

		if options.Filter == nil {
			options.Filter = models.JSON{}
		}

		if options.Origin == "" {
			options.Origin = messaging.ORIGIN_API
		}

		log.Info("Request options:", optionsHeader)

		c.Set(CONTEXT_HEADER_OPTIONS, options)
		c.Next()
	}
}
func (p RpcMessageReceiver) handleRpc(args []interface{}, kwargs map[string]interface{}) *gowamp.CallResult {
	defer utils.Recover()

	var msg messaging.Message

	if msgStr, ok := args[0].(string); ok {
		err := msg.FromString(msgStr)
		if err != nil {
			return p.makeErrorResult(err)
		}
	} else {
		err := models.Convert(args[0], &msg)
		if err != nil {
			return p.makeErrorResult(err)
		}
	}

	log.Info("RPC message received:", msg)
	res, err := p.MessageProcessor.Process(msg)
	if err != nil {
		return p.makeErrorResult(err)
	}

	return p.makeResult(res)
}
Beispiel #6
0
func validateAppMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		appId := c.Param("appId")
		log.Info(appId)
		if appId == "" {
			log.Error(RestError(c, "Invalid app id."))
		} else {
			c.Next()
		}
	}
}
Beispiel #7
0
func (b *Broadcaster) Broadcast(v interface{}) {
	defer func() {
		if err := recover(); err != nil {
			log.Error(err)
		}
	}()

	log.Info(b.listeners)
	for _, ch := range b.listeners {
		ch <- v
	}
}
Beispiel #8
0
func GetNewRedisClient() *redis.Client {
	redisAddr := config.Get(config.KEY_REDIS_ADDR)
	//TODO: check if will reconnect automatically on lost connection
	redisClient := redis.NewClient(&redis.Options{
		Addr:     redisAddr,
		Password: "",
		DB:       0,
	})

	log.Info("Connected to redis client on:", redisAddr)
	return redisClient
}
Beispiel #9
0
func (c *Client) Connect() {
	for {
		conn, err := c.connect()
		if err == nil {
			c.isConnected = true
			c.connection = conn
			log.Info("Connected to", c.Addr)
			break
		} else {
			log.Error("Error connecting to", c.Addr, err)
			time.Sleep(time.Second * 5)
		}
	}
}
Beispiel #10
0
func main() {
	r.SetVerbose(true)

	defer utils.Recover()
	utils.ListenSignals()
	utils.Liveness()

	err := server.Initialize()
	if err != nil {
		panic(err)
	}

	log.Info("Realtime service listening")
	log.Error(http.ListenAndServe(config.Get(config.KEY_REALTIME_PORT), nil))
}
Beispiel #11
0
func BlacklistFields(fields []string, data interface{}) map[string]interface{} {
	if obj, ok := data.(map[string]interface{}); ok {
		for _, k := range fields {
			delete(obj, k)
		}

		return obj
	} else if obj, ok := data.(models.JSON); ok {
		for _, k := range fields {
			delete(obj, k)
		}

		return obj
	}

	log.Info("Invalid object to blacklist", data)
	return make(map[string]interface{})
}
Beispiel #12
0
func NewNatsClient(addr string) *NatsClient {
	connect := func() (interface{}, error) {
		log.Info("Connecting to nats:", addr)
		n, err := nats.Connect(addr)

		if err != nil {
			return nil, err
		}

		conn, err := nats.NewEncodedConn(n, nats.JSON_ENCODER)
		if err != nil {
			return nil, err
		}

		return conn, nil
	}

	c := NewClient(connect, addr)

	natsClient := &NatsClient{c}
	natsClient.handleConnection()
	return natsClient
}
func (p WsMessageReceiver) processDatabaseUpdate(
	val map[string]interface{},
	builder *messaging.MessageBuilder,
	opts models.SubscribeOptions,
) {
	messageBuilder := *builder

	pld := models.JSON{}
	var dbOp string
	newVal := val["new_val"]
	oldVal := val["old_val"]

	if newVal != nil && oldVal == nil {
		dbOp = messaging.OP_CREATE
	} else if newVal == nil && oldVal != nil {
		dbOp = messaging.OP_DELETE
	} else {
		dbOp = messaging.OP_UPDATE
	}

	//only emit messages with the same operation as the subscriber
	if dbOp != opts.Operation {
		return
	}

	var dbVal map[string]interface{}
	if dbOp == messaging.OP_CREATE {
		if newVal == nil {
			log.Error("Invalid message:", val)
			return
		}

		dbVal = newVal.(map[string]interface{})
	} else if dbOp == messaging.OP_DELETE && oldVal != nil {
		if oldVal == nil {
			log.Error("Invalid message:", val)
			return
		}

		dbVal = oldVal.(map[string]interface{})
	} else {
		//update
		if newVal == nil {
			log.Error("Invalid message:", val)
			return
		}

		dbVal = newVal.(map[string]interface{})
	}

	pld = pld.FromMap(dbVal)
	pld = utils.BlacklistFields([]string{db.TYPE_FIELD, db.APP_ID_FIELD}, pld)

	msg := messageBuilder.Build(
		dbOp,
		messaging.ORIGIN_API,
		pld,
		models.Options{},
		opts.Type,
		opts.AppId,
		"", //TODO: token?
	)
	msg.Topic = opts.Topic

	log.Info("Publishing database feed: ", strings.ToUpper(msg.Operation), opts, val, msg)

	publishArgs := []interface{}{msg}
	p.WsClient.Publish(opts.Topic, publishArgs, nil)
}
func (p WsMessageReceiver) handleSubscribe(im interceptorMessage, msg *gowamp.Subscribe) {
	opts := models.SubscribeOptions{}
	err := models.Convert(msg.Options, &opts)
	if err != nil {
		log.Error(err)
		return
	}

	topic := fmt.Sprintf("%v", msg.Topic)
	topicArguments := strings.Split(topic, ".")

	opts.Topic = topic
	if opts.IsSpecial() {
		baseTopic := messaging.BuildTopicArbitrary(topicArguments[:len(topicArguments)-1]...)
		opts.BaseTopic = baseTopic
	} else {
		opts.BaseTopic = topic
	}

	log.Info("Listening for changefeed:", opts)
	d := db.NewDbService()
	newValuesChan := make(chan map[string]interface{})

	//for create and delete we want to listen for changes for the whole collection, for update only for the specific item
	if opts.Operation == messaging.OP_CREATE || opts.Operation == messaging.OP_DELETE {
		err = d.Changes(opts.AppId, opts.Type, opts.Filter, newValuesChan)
	} else if opts.Operation == messaging.OP_UPDATE {
		opts.ItemId = topicArguments[len(topicArguments)-1]
		err = d.ChangesId(opts.ItemId, newValuesChan)
	}

	if err != nil {
		log.Error(err)
		return
	}

	messageBuilder := messaging.GetMessageBuilder()
	go func() {
		leaveChan := make(chan interface{})
		p.broadcaster.Subscribe(leaveChan)

		for {
			select {
			case val := <-newValuesChan:
				p.processDatabaseUpdate(val, &messageBuilder, opts)
			case leaveVal := <-leaveChan:
				sessionId := leaveVal.(gowamp.ID)
				if im.sess.Id == sessionId {
					//TODO: newValuesChan seems to be automatically closed by the rethinkdb driver
					//investigate whether we need to do something else

					_, leaveChanOpened := <-leaveChan
					if leaveChanOpened {
						close(leaveChan)
					}

					p.broadcaster.Remove(leaveChan)
					return
				}
			}
		}
	}()
}
Beispiel #15
0
func (c *ApiClient) SendRequest(url, method string, body interface{}, isArray bool) (interface{}, error) {
	log.Info(
		"Sending request",
		"BaseUrl:", c.BaseUrl,
		"Url:", url,
		"Method:", method,
		"Body:", body,
		"Token:", c.Token,
		"AppId:", c.AppId,
		"NotifyRealtime", c.NotifyRealTime,
	)

	var bodyStr = ""
	if body != nil {
		b, err := json.Marshal(body)
		if err != nil {
			log.Error(err)
			return nil, err
		}

		bodyStr = string(b)
	}

	req, err := http.NewRequest(method, c.BaseUrl+url, strings.NewReader(bodyStr))
	if err != nil {
		log.Error(err)
		return nil, err
	}

	opts := models.Options{}

	//todo: in app and not in app token
	if c.Token != "" {
		req.Header.Set("Authorization", "Bearer "+c.Token)
	}

	if c.ClientId != "" {
		opts.ClientId = &c.ClientId
	}

	opts.Notify = &c.NotifyRealTime
	opts.Filter = c.Filter
	//opts.Origin = c.Origin

	optsS, err := opts.String()
	if err != nil {
		log.Error(err)
		return nil, err
	}

	req.Header.Set("NeutrinoOptions", optsS)

	client := http.Client{}
	res, err := client.Do(req)
	if err != nil {
		log.Info(err)
		return nil, err
	}

	if res == nil {
		log.Error("Unknown error")
		return nil, nil
	}

	if res.StatusCode != http.StatusOK {
		log.Info(res, err)
		return nil, err
	}

	defer res.Body.Close()
	if err != nil {
		log.Error(err)
		return nil, err
	}

	bodyRes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	if string(bodyRes) == "" {
		log.Info("Empty body response!")
		return nil, nil
	}

	var result interface{}
	log.Info("API response: ", string(bodyRes))
	if isArray {
		jsonArray := make([]models.JSON, 0)
		err = json.Unmarshal(bodyRes, &jsonArray)
		result = jsonArray
	} else {
		m := models.JSON{}
		err = json.Unmarshal(bodyRes, &m)
		result = m
	}

	if err != nil {
		log.Error(err)
		return nil, err
	}

	return result, nil
}