// TX thread func (service *Service) doTX() { for { select { case task, ok := <-service.tx: if !ok || task == nil { log.Infof("WS: TX thread stopped") service.conn.Close() // TODO: send Close frame? return } body, err := task.Format() if err != nil { log.Warnf("WS: failed to format message (error: %s)", err) continue // TODO: return? } log.Tracef("WS: sending message: %s", string(body)) err = service.conn.WriteMessage(websocket.TextMessage, body) if err != nil { log.Warnf("WS: failed to send message (error: %s)", err) continue // TODO: return? } // case <-service.pingTimer.C: // if err := c.write(websocket.PingMessage, []byte{}); err != nil { // log.Warnf("WS: could not write ping message (error: %s)", err) // return // } } } }
func main() { configFile, config, err := conf.FromArgs() switch { case err != nil: log.Fatalf("Failed to read %q configuration (%s)", configFile, err) case configFile == "": log.Warnf("No configuration file provided!") log.Infof("Test configuration is used: %+v", config) default: log.Infof("Starting DeviceHive with %q configuration: %+v", configFile, config) } log.SetLevelByName(config.LoggingLevel) bus, err := dbus.SystemBus() if err != nil { log.Warnf("Cannot get system bus (error: %s)", err) log.Infof("Trying to use session bus for testing purposes...") if bus, err = dbus.SessionBus(); err != nil { log.Fatalf("Cannot get session bus (error: %s)", err) return } } reply, err := bus.RequestName(DBusConnName, dbus.NameFlagDoNotQueue) switch { case err != nil: log.Fatalf("Cannot request name %q (error: %s)", DBusConnName, err) case reply != dbus.RequestNameReplyPrimaryOwner: log.Fatalf("The name %q already taken", DBusConnName) } s, err := devicehive.NewService(config.URL, config.AccessKey) if err != nil { log.Fatalf("Failed to create DeviceHive service (error: %s)", err) } log.Infof("Starting %v", s) mainLoop(bus, s, config) }
// main loop func mainLoop(bus *dbus.Conn, service devicehive.Service, config conf.Conf) { // getting server info info, err := service.GetServerInfo(waitTimeout) if err != nil { log.Warnf("Cannot get service info (error: %s)", err) return } // registering device device := devicehive.NewDevice(config.DeviceID, config.DeviceName, devicehive.NewDeviceClass("go-gateway-class", "0.1")) device.Key = config.DeviceKey if len(config.NetworkName) != 0 || len(config.NetworkKey) != 0 { device.Network = devicehive.NewNetwork(config.NetworkName, config.NetworkKey) device.Network.Description = config.NetworkDesc } err = service.RegisterDevice(device, waitTimeout) if err != nil { log.Warnf("Cannot register device (error: %s)", err) return } // start polling commands listener, err := service.SubscribeCommands(device, info.Timestamp, waitTimeout) if err != nil { log.Warnf("Cannot subscribe commands (error: %s)") return } wrapper := DBusWrapper{service: service, device: device} exportDBusObject(bus, &wrapper) for { select { case cmd := <-listener.C: params := "" if cmd.Parameters != nil { buf, err := json.Marshal(cmd.Parameters) if err != nil { log.Warnf("Cannot generate JSON from parameters of command %+v (error: %s)", cmd, err) continue } params = string(buf) } log.Infof("COMMAND %s -> %s(%v)", config.URL, cmd.Name, params) bus.Emit(ComDevicehiveCloudPath, ComDevicehiveCloudIface+".CommandReceived", cmd.Id, cmd.Name, params) } //time.Sleep(5 * time.Second) } }
// update command result func (w *DBusWrapper) UpdateCommand(id uint64, status, result string) *dbus.Error { log.Infof("updating command(id:%d, status=%q, result:%q", id, status, result) dat, err := parseJSON(result) if err != nil { log.Warnf("failed to convert command result to JSON (error: %s)", err) return newDHError(err.Error()) } command := devicehive.NewCommandResult(id, status, dat) err = w.service.UpdateCommand(w.device, command, waitTimeout) if err != nil { log.Warnf("failed to update command (error: %s)", err) return newDHError(err.Error()) } return nil // OK }
// send notification // priority is ignored func (w *DBusWrapper) SendNotification(name, parameters string, priority uint64) *dbus.Error { log.Infof("sending notification(name=%q, params=%q, priority=%d)", name, parameters, priority) dat, err := parseJSON(parameters) if err != nil { log.Warnf("failed to convert notification parameters to JSON (error: %s)", err) return newDHError(err.Error()) } notification := devicehive.NewNotification(name, dat) err = w.service.InsertNotification(w.device, notification, waitTimeout) if err != nil { log.Warnf("failed to send notification (error: %s)", err) return newDHError(err.Error()) } return nil // OK }
func TestBatchNotificationInsert(t *testing.T) { device := testNewDevice() device.Network = testNewNetwork() s := testNewRest(t) s2 := s //testNewWs(t) device.Id += "-batch-ntf" testCheckRegisterDevice1(t, s, *device, true) count := testBatchLen gap := time.Duration(testGapMs) * time.Millisecond tx_ntfs := make([]*core.Notification, 0, count) rx_ntfs := make([]*core.Notification, 0, count) type Stat struct { tx_beg time.Time tx_end time.Time rx_end time.Time } stat := make(map[string]*Stat) // transmitter go func() { time.Sleep(2 * time.Second) // small delay before start log.Infof("TEST/TX: started") for i := 0; i < count; i++ { p := fmt.Sprintf("%d", i) ntf := core.NewNotification("batch-notification", p) stat[p] = &Stat{} stat[p].tx_beg = time.Now() err := s.InsertNotification(device, ntf, testWaitTimeout) stat[p].tx_end = time.Now() if err != nil { t.Errorf("failed to insert batch notification: %s", err) break } log.Infof("TEST/TX: %s", ntf) tx_ntfs = append(tx_ntfs, ntf) time.Sleep(gap) } log.Infof("TEST/TX: stopped") }() // receiver listener, err := s2.SubscribeNotifications(device, "", testWaitTimeout) if err != nil { t.Errorf("failed to subscribe notifications: %s", err) return } log.Infof("TEST/RX: started") for len(rx_ntfs) < count && !t.Failed() { select { case ntf := <-listener.C: if ntf.Name != "batch-notification" { // notification ignored continue } p := ntf.Parameters.(string) stat[p].rx_end = time.Now() log.Infof("TEST/RX: %s", ntf) rx_ntfs = append(rx_ntfs, ntf) case <-time.After(30 * time.Second): t.Errorf("failed to wait notification: %s", "timed out") break } } log.Infof("TEST/RX: stopped") err = s2.UnsubscribeNotifications(device, testWaitTimeout) if err != nil { t.Errorf("failed to unsubscribe notifications: %s", err) return } // compare tx_ntfs == rx_ntfs if len(tx_ntfs) != count || len(rx_ntfs) != count { t.Errorf("TX:%d != RX:%d notifications length mismatch", len(tx_ntfs), len(rx_ntfs)) return } // time statistics: // ins - insertion time (tx_end - tx_beg) // rtt - round trip (rx_end - tx_beg) var ins, rtt TimeStat for i, tx := range tx_ntfs { rx := rx_ntfs[i] // log.Infof("%d:\tTX:%q at %q\t\tRX:%q at %q", i, // tx.Parameters, tx.Timestamp, // rx.Parameters, rx.Timestamp) // if tx.Name != rx.Name { // t.Errorf("TX:%q != RX:%q notification name mismatch", tx.Name, rx.Name) // continue // } tx_p := tx.Parameters.(string) rx_p := rx.Parameters.(string) if tx_p != rx_p { t.Errorf("TX:%q != RX:%q notification parameter mismatch", tx_p, rx_p) continue } t := stat[tx_p] ins.Add(t.tx_end.Sub(t.tx_beg)) rtt.Add(t.rx_end.Sub(t.tx_beg)) } log.Infof("insert time: %s", ins) log.Infof(" round trip: %s", rtt) }