Пример #1
0
func (service *Service) Stop() error {
	errors := make(map[string]error)
	for _, stopable := range service.stopListener {
		name := reflect.TypeOf(stopable).String()
		stoppedChan := make(chan bool)
		errorChan := make(chan error)
		guble.Info("stopping %v ...", name)
		go func() {
			err := stopable.Stop()
			if err != nil {
				errorChan <- err
				return
			}
			stoppedChan <- true
		}()
		select {
		case err := <-errorChan:
			guble.Err("error while stopping %v: %v", name, err.Error)
			errors[name] = err
		case <-stoppedChan:
			guble.Info("stopped %v", name)
		case <-time.After(service.StopGracePeriod):
			errors[name] = fmt.Errorf("error while stopping %v: not returned after %v seconds", name, service.StopGracePeriod)
			guble.Err(errors[name].Error())
		}
	}
	if len(errors) > 0 {
		return fmt.Errorf("Errors while stopping modules %q", errors)
	}
	return nil
}
Пример #2
0
func (c *Client) startWithReconnect() {
	for {
		if c.Connected {
			err := c.readLoop()
			if err == nil {
				return
			}
		}

		if c.shouldStop() {

			return
		}

		var err error
		c.ws, err = c.WSConnectionFactory(c.url, c.origin)
		if err != nil {
			c.Connected = false
			guble.Err("error on connect, retry in 50ms: %v", err)
			time.Sleep(time.Millisecond * 50)
		} else {
			c.Connected = true
			guble.Err("connected again")
		}
	}
}
Пример #3
0
func StartupService(args Args) *server.Service {
	router := server.NewPubSubRouter()
	router.SetAccessManager(server.NewAllowAllAccessManager(true))
	router.Go()
	service := server.NewService(
		args.Listen,
		CreateKVStoreBackend(args),
		CreateMessageStoreBackend(args),
		server.NewMessageEntry(router),
		router,
		server.NewAllowAllAccessManager(true))

	for _, module := range CreateModules(args) {
		service.Register(module)
	}

	if err := service.Start(); err != nil {
		guble.Err(err.Error())
		if err := service.Stop(); err != nil {
			guble.Err(err.Error())
		}
		os.Exit(1)
	}

	return service
}
Пример #4
0
func (gcmConnector *GCMConnector) handleJsonError(jsonError string, gcmId string, route *server.Route) {
	if jsonError == "NotRegistered" {
		guble.Debug("remove not registered cgm registration cgmid=%v", gcmId)
		gcmConnector.removeSubscription(route, gcmId)
	} else if jsonError == "InvalidRegistration" {
		guble.Err("the cgmid=%v is not registered. %v", gcmId, jsonError)
	} else {
		guble.Err("unexpected error while sending to cgm cgmid=%v: %v", gcmId, jsonError)
	}
}
Пример #5
0
func (c *Client) handleIncommoingMessage(msg []byte) {
	parsed, err := guble.ParseMessage(msg)
	if err != nil {
		guble.Err("parsing message failed %v", err)
		c.errors <- clientErrorMessage(err.Error())
		return
	}

	switch message := parsed.(type) {
	case *guble.Message:
		c.messages <- message
	case *guble.NotificationMessage:
		if message.IsError {
			select {
			case c.errors <- message:
			default:
			}
		} else {
			select {
			case c.statusMessages <- message:
			default:
			}
		}
	}
}
Пример #6
0
func writeLoop(client *client.Client) {
	shouldStop := false
	for !shouldStop {
		func() {
			defer guble.PanicLogger()
			reader := bufio.NewReader(os.Stdin)
			text, _ := reader.ReadString('\n')
			if strings.TrimSpace(text) == "" {
				return
			}

			if strings.TrimSpace(text) == "?" || strings.TrimSpace(text) == "help" {
				printHelp()
				return
			}

			if strings.HasPrefix(text, ">") {
				fmt.Print("header: ")
				header, _ := reader.ReadString('\n')
				text += header
				fmt.Print("body: ")
				body, _ := reader.ReadString('\n')
				text += strings.TrimSpace(body)
			}

			if args.Verbose {
				log.Printf("Sending: %v\n", text)
			}
			if err := client.WriteRawMessage([]byte(text)); err != nil {
				shouldStop = true
				guble.Err(err.Error())
			}
		}()
	}
}
Пример #7
0
func Main() {
	defer func() {
		if p := recover(); p != nil {
			guble.Err("%v", p)
			os.Exit(1)
		}
	}()

	args := loadArgs()
	if args.LogInfo {
		guble.LogLevel = guble.LEVEL_INFO
	}
	if args.LogDebug {
		guble.LogLevel = guble.LEVEL_DEBUG
	}

	if err := ValidateStoragePath(args); err != nil {
		os.Exit(1)
	}

	service := StartupService(args)

	waitForTermination(func() {
		service.Stop()
	})
}
Пример #8
0
func (rec *Receiver) fetchOnlyLoop() {
	err := rec.fetch()
	if err != nil {
		guble.Err("error while fetching: %v, %+v", err.Error(), rec)
		rec.sendError(guble.ERROR_INTERNAL_SERVER, err.Error())
	}
}
Пример #9
0
func (gcmConnector *GCMConnector) sendMessageToGCM(msg server.MsgAndRoute) {
	gcmId := msg.Route.ApplicationId

	payload := gcmConnector.parseMessageToMap(msg.Message)

	var messageToGcm = gcm.NewMessage(payload, gcmId)
	guble.Info("sending message to %v ...", gcmId)
	result, err := gcmConnector.sender.Send(messageToGcm, 5)
	if err != nil {
		guble.Err("error sending message to cgmid=%v: %v", gcmId, err.Error())
		return
	}

	errorJson := result.Results[0].Error
	if errorJson != "" {
		gcmConnector.handleJsonError(errorJson, gcmId, msg.Route)
	} else {
		guble.Debug("delivered message to gcm cgmid=%v: %v", gcmId, errorJson)
	}

	//we only send to one receiver, so we know that we can replace the old id with the first registration id (=canonical id)
	if result.CanonicalIDs != 0 {
		gcmConnector.replaceSubscriptionWithCanonicalID(msg.Route, result.Results[0].RegistrationID)
	}
}
Пример #10
0
func (gcmConnector *GCMConnector) broadcastMessage(msg server.MsgAndRoute) {
	topic := msg.Message.Path
	payload := gcmConnector.parseMessageToMap(msg.Message)
	guble.Info("broadcasting message with topic %v ...", string(topic))

	subscriptions := gcmConnector.kvStore.Iterate(GCM_REGISTRATIONS_SCHEMA, "")
	count := 0
	for {
		select {
		case entry, ok := <-subscriptions:
			if !ok {
				guble.Info("send message to %v receivers", count)
				return
			}
			gcmId := entry[0]
			//TODO collect 1000 gcmIds and send them in one request!
			broadcastMessage := gcm.NewMessage(payload, gcmId)
			go func() {
				//TODO error handling of response!
				_, err := gcmConnector.sender.Send(broadcastMessage, 3)
				guble.Debug("sent broadcast message to gcmId=%v", gcmId)
				if err != nil {
					guble.Err("error sending broadcast message to cgmid=%v: %v", gcmId, err.Error())
				}
			}()
			count++
		}
	}
}
Пример #11
0
// Opens the database file.
// If the directory does not exist, it will be created.
func (kvStore *SqliteKVStore) Open() error {
	directoryPath := filepath.Dir(kvStore.filename)
	if err := ensureWriteableDirectory(directoryPath); err != nil {
		guble.Err("error db directory not writeable %q: %q", kvStore.filename, err)
		return err
	}

	guble.Info("opening sqldb %v", kvStore.filename)
	gormdb, err := gorm.Open("sqlite3", kvStore.filename)
	if err != nil {
		guble.Err("error opening sqlite3 db %q: %q", kvStore.filename, err)
		return err
	}

	if err := gormdb.DB().Ping(); err != nil {
		guble.Err("error pinging database %q: %q", kvStore.filename, err.Error())
	} else {
		guble.Debug("can ping database %q", kvStore.filename)
	}

	//gormdb.LogMode(true)
	gormdb.DB().SetMaxIdleConns(2)
	gormdb.DB().SetMaxOpenConns(5)
	gormdb.SingularTable(true)

	if err := gormdb.AutoMigrate(&kvEntry{}).Error; err != nil {
		guble.Err("error in schema migration: %q", err)
		return err
	} else {
		guble.Debug("ensured db schema")
	}

	if !kvStore.syncOnWrite {
		guble.Info("setting db: PRAGMA synchronous = OFF")
		if err := gormdb.Exec("PRAGMA synchronous = OFF").Error; err != nil {
			guble.Err("error setting PRAGMA synchronous = OFF: %v", err)
			return err
		}
	}
	kvStore.db = &gormdb
	return nil
}
Пример #12
0
func (fms *FileMessageStore) Stop() error {
	fms.mutex.Lock()
	defer fms.mutex.Unlock()

	var returnError error
	for key, partition := range fms.partitions {
		if err := partition.Close(); err != nil {
			returnError = err
			guble.Err("error on closing message store partition %q: %v", key, err)
		}
		delete(fms.partitions, key)
	}
	return returnError
}
Пример #13
0
// Take the message and forward it to the router.
func (entry *MessageEntry) HandleMessage(msg *guble.Message) error {
	txCallback := func(msgId uint64) []byte {
		msg.Id = msgId
		msg.PublishingTime = time.Now().Format(time.RFC3339)
		return msg.Bytes()
	}

	if err := entry.messageStore.StoreTx(msg.Path.Partition(), txCallback); err != nil {
		guble.Err("error storing message in partition %v: %v", msg.Path.Partition(), err)
		return err
	}

	return entry.router.HandleMessage(msg)
}
Пример #14
0
func (service *Service) Start() error {
	el := guble.NewErrorList("Errors occured while startup the service: ")

	for _, startable := range service.startListener {
		name := reflect.TypeOf(startable).String()

		guble.Debug("starting module %v", name)
		if err := startable.Start(); err != nil {
			guble.Err("error on startup module %v", name)
			el.Add(err)
		}
	}
	return el.ErrorOrNil()
}
Пример #15
0
func (rec *Receiver) subscriptionLoop() {
	for !rec.shouldStop {
		if rec.doFetch {

			if err := rec.fetch(); err != nil {
				guble.Err("error while fetching: %v, %+v", err.Error(), rec)
				rec.sendError(guble.ERROR_INTERNAL_SERVER, err.Error())
				return
			}

			if err := rec.messageStore.DoInTx(rec.path.Partition(), rec.subscribeIfNoUnreadMessagesAvailable); err != nil {
				if err == unread_messages_available {
					//fmt.Printf(" unread_messages_available lastSendId=%v\n", rec.lastSendId)
					rec.startId = int64(rec.lastSendId + 1)
					continue // fetch again
				} else {
					guble.Err("error while subscribeIfNoUnreadMessagesAvailable: %v, %+v", err.Error(), rec)
					rec.sendError(guble.ERROR_INTERNAL_SERVER, err.Error())
					return
				}
			}
		}

		if !rec.doFetch {
			rec.subscribe()
		}
		rec.receiveFromSubscription()

		if !rec.shouldStop {
			//fmt.Printf(" router closed .. on msg: %v\n", rec.lastSendId)
			// the router kicked us out, because we are to slow for realtime listening,
			// so we setup parameters for fetching and cloging the gap. Than we can subscribe again.
			rec.startId = int64(rec.lastSendId + 1)
			rec.doFetch = true
		}
	}
}
Пример #16
0
func (c *Client) readLoop() error {
	for {
		if _, msg, err := c.ws.ReadMessage(); err != nil {
			c.Connected = false
			if c.shouldStop() {
				return nil
			} else {
				guble.Err("read error: %v", err.Error())
				c.errors <- clientErrorMessage(err.Error())
				return err
			}
		} else {
			guble.Debug("raw> %s", msg)
			c.handleIncommoingMessage(msg)
		}
	}
}
Пример #17
0
func TestStopingOfModulesTimeout(t *testing.T) {
	defer initCtrl(t)()

	// given:
	service, _, _, _, _ := aMockedService()
	service.StopGracePeriod = time.Millisecond * 5

	// whith a registered stopable, which blocks to long on stop
	stopable := NewMockStopable(ctrl)
	service.Register(stopable)
	stopable.EXPECT().Stop().Do(func() {
		time.Sleep(time.Millisecond * 10)
	})

	// then the Stop returns with an error
	err := service.Stop()
	assert.Error(t, err)
	guble.Err(err.Error())
}
Пример #18
0
func (ws *WebServer) Start() error {
	guble.Info("starting up at %v", ws.addr)
	ws.server = &http.Server{Addr: ws.addr, Handler: ws.mux}
	var err error
	ws.ln, err = net.Listen("tcp", ws.addr)
	if err != nil {
		return err
	}

	go func() {
		err = ws.server.Serve(tcpKeepAliveListener{ws.ln.(*net.TCPListener)})

		if err != nil && !strings.HasSuffix(err.Error(), "use of closed network connection") {
			guble.Err("ListenAndServe %s", err.Error())
		}
		guble.Info("http server stopped")
	}()
	return nil
}
Пример #19
0
func (kvStore *SqliteKVStore) IterateKeys(schema string, keyPrefix string) chan string {
	responseChan := make(chan string, 100)

	go func() {

		rows, err := kvStore.db.Raw("select key from kv_entry where schema = ? and key LIKE ?", schema, keyPrefix+"%").
			Rows()

		if err != nil {
			guble.Err("error fetching keys from db %v", err)
		} else {
			defer rows.Close()
			for rows.Next() {
				var value string
				rows.Scan(&value)
				responseChan <- value
			}
		}
		close(responseChan)
	}()
	return responseChan
}