// subscribe for notifications func (service *Service) SubscribeNotifications(device *core.Device, timestamp string, timeout time.Duration) (listener *core.NotificationListener, err error) { if listener, ok := service.notificationListeners[device.Id]; ok { return listener, nil } // install new listener = core.NewNotificationListener() service.notificationListeners[device.Id] = listener go func(deviceId string) { log.Debugf("REST: start notification polling %q", deviceId) for { names := "" wait := "30" ntfs, err := service.PollNotifications(device, timestamp, names, wait, 60*time.Second) if err != nil { log.Warnf("REST: failed to poll notifications (error: %s)", err) // TODO: break? wait and try again? } if listener, ok := service.notificationListeners[deviceId]; ok { for _, ntf := range ntfs { log.Debugf("REST: got notification %s received", ntf) timestamp = ntf.Timestamp listener.C <- &ntf } } else { log.Debugf("REST: stop notification polling %q", deviceId) return // stop } } }(device.Id) return }
// subscribe for commands func (service *Service) SubscribeCommands(device *core.Device, timestamp string, timeout time.Duration) (listener *core.CommandListener, err error) { if listener, ok := service.commandListeners[device.Id]; ok { return listener, nil } // install new listener = core.NewCommandListener() service.commandListeners[device.Id] = listener go func(deviceId string) { log.Debugf("REST: start command polling %q", deviceId) for { names := "" wait := "30" cmds, err := service.PollCommands(device, timestamp, names, wait, 60*time.Second) if err != nil { log.Warnf("REST: failed to poll commands (error: %s)", err) // TODO: break? wait and try again? } if listener, ok := service.commandListeners[deviceId]; ok { for _, cmd := range cmds { log.Debugf("REST: got command %s received", cmd) timestamp = cmd.Timestamp listener.C <- &cmd } } else { log.Debugf("REST: stop command polling %q", deviceId) return // stop } } }(device.Id) return }
// GetCommand() function get the command data. func (service *Service) GetCommand(device *core.Device, commandId uint64, timeout time.Duration) (command *core.Command, err error) { log.Debugf("REST: getting command %q/%d...", device.Id, commandId) task, err := service.prepareGetCommand(device, commandId) if err != nil { log.Warnf("REST: failed to prepare /command/get task (error: %s)", err) return } select { case <-time.After(timeout): log.Warnf("REST: failed to wait %s for /command/get task", timeout) err = fmt.Errorf("timed out") case task = <-service.doAsync(task): command = &core.Command{Id: commandId} err = service.processGetCommand(task, command) if err != nil { log.Warnf("REST: failed to process /command/get task (error: %s)", err) return } } return }
// Do a request/task asynchronously func (service *Service) doAsync(task Task) <-chan Task { ch := make(chan Task, 1) go func() { defer func() { ch <- task }() log.Tracef("REST: sending: %+v", task.request) task.response, task.err = service.client.Do(task.request) if task.err != nil { log.Warnf("REST: failed to do %s %s request (error: %s)", task.request.Method, task.request.URL, task.err) return } log.Tracef("REST: got %s %s response: %+v", task.request.Method, task.request.URL, task.response) // read body defer task.response.Body.Close() task.body, task.err = ioutil.ReadAll(task.response.Body) if task.err != nil { log.Warnf("REST: failed to read %s %s response body (error: %s)", task.request.Method, task.request.URL, task.err) return } log.Debugf("REST: got %s %s body: %s", task.request.Method, task.request.URL, string(task.body)) }() return ch }
// InsertCommand() function inserts the device command. func (service *Service) InsertCommand(device *core.Device, command *core.Command, timeout time.Duration) (err error) { log.Debugf("REST: inserting command %q to %q...", command.Name, device.Id) task, err := service.prepareInsertCommand(device, command) if err != nil { log.Warnf("REST: failed to prepare /command/insert task (error: %s)", err) return } select { case <-time.After(timeout): log.Warnf("REST: failed to wait %s for /command/insert task", timeout) err = fmt.Errorf("timed out") case task = <-service.doAsync(task): err = service.processInsertCommand(task, command) if err != nil { log.Warnf("REST: failed to process /command/insert task (error: %s)", err) return } } return }
// GetCommand() function poll the commands. func (service *Service) PollCommands(device *core.Device, timestamp, names, waitTimeout string, timeout time.Duration) (commands []core.Command, err error) { log.Debugf("REST: polling commands %q, timestamp:%q...", device.Id, timestamp) task, err := service.preparePollCommand(device, timestamp, names, waitTimeout) if err != nil { log.Warnf("REST: failed to prepare /command/poll task (error: %s)", err) return } select { case <-time.After(timeout): log.Warnf("REST: failed to wait %s for /command/poll task", timeout) err = fmt.Errorf("timed out") case task = <-service.doAsync(task): commands, err = service.processPollCommand(task) if err != nil { log.Warnf("REST: failed to process /command/poll task (error: %s)", err) return } } return }
// DeleteDevice() function deletes the device. func (service *Service) DeleteDevice(device *core.Device, timeout time.Duration) (err error) { log.Debugf("REST: deleting device %q...", device.Id) task, err := service.prepareDeleteDevice(device) if err != nil { log.Warnf("REST: failed to prepare /device/delete task (error: %s)", err) return } select { case <-time.After(timeout): log.Warnf("REST: failed to wait %s for /device/delete task", timeout) err = fmt.Errorf("timed out") case task = <-service.doAsync(task): err = service.processDeleteDevice(task) if err != nil { log.Warnf("REST: failed to process /device/delete task (error: %s)", err) return } } return }