Refactor reach package

- Rename reach package to emlid
- Create generic Reach websocket client
- Add 2 new subpackages 'updater' and 'reachview' to provides specific
API
This commit is contained in:
wpetit 2018-09-21 12:31:52 +02:00
parent 77a779aebe
commit 6e9df8d386
35 changed files with 427 additions and 576 deletions

View File

@ -0,0 +1,17 @@
package emlid
const (
// EventBrowserConnected is emitted after the initial connection to the
// ReachView endpoint
eventBrowserConnected = "browser connected"
)
// sendBrowserConnected notifies the ReachView endpoint
// of a new connection.
// See misc/reachview/update_main.js line 297
func (c *Client) sendBrowserConnected() error {
payload := map[string]string{
"data": "I'm connected",
}
return c.Emit(eventBrowserConnected, payload)
}

View File

@ -1,4 +1,4 @@
package reach package emlid
import ( import (
"sync" "sync"
@ -9,14 +9,18 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
type client struct { // Client is a ReachRS websocket API client
type Client struct {
opts *Options opts *Options
conn *gosocketio.Client conn *gosocketio.Client
} }
// EventHandler is an event handler
type EventHandler func(data interface{})
// Connect connects the client to the ReachView endpoint // Connect connects the client to the ReachView endpoint
// This method is not safe to call by different coroutines // This method is not safe to call by different coroutines
func (c *client) Connect() error { func (c *Client) Connect() error {
var err error var err error
var wg sync.WaitGroup var wg sync.WaitGroup
@ -31,7 +35,7 @@ func (c *client) Connect() error {
BufferSize: c.opts.BufferSize, BufferSize: c.opts.BufferSize,
} }
c.logf("connecting to '%s'", c.opts.Endpoint) c.Logf("connecting to '%s'", c.opts.Endpoint)
conn, err := gosocketio.Dial(c.opts.Endpoint, transport) conn, err := gosocketio.Dial(c.opts.Endpoint, transport)
if err != nil { if err != nil {
return errors.Wrap(err, "error while connecting to endpoint") return errors.Wrap(err, "error while connecting to endpoint")
@ -41,7 +45,7 @@ func (c *client) Connect() error {
err = conn.On(gosocketio.OnConnection, func(h *gosocketio.Channel) { err = conn.On(gosocketio.OnConnection, func(h *gosocketio.Channel) {
conn.Off(gosocketio.OnError) conn.Off(gosocketio.OnError)
c.logf("connected with sid '%s'", h.Id()) c.Logf("connected with sid '%s'", h.Id())
err = c.sendBrowserConnected() err = c.sendBrowserConnected()
wg.Done() wg.Done()
}) })
@ -50,7 +54,7 @@ func (c *client) Connect() error {
} }
err = conn.On(gosocketio.OnError, func(h *gosocketio.Channel) { err = conn.On(gosocketio.OnError, func(h *gosocketio.Channel) {
c.logf("error") c.Logf("error")
err = errors.Errorf("an unknown error occured") err = errors.Errorf("an unknown error occured")
c.conn = nil c.conn = nil
wg.Done() wg.Done()
@ -65,7 +69,7 @@ func (c *client) Connect() error {
} }
// Close closes the current connection to the ReachView endpoint // Close closes the current connection to the ReachView endpoint
func (c *client) Close() { func (c *Client) Close() {
if c.conn == nil { if c.conn == nil {
return return
} }
@ -73,7 +77,28 @@ func (c *client) Close() {
c.conn = nil c.conn = nil
} }
func (c *client) fetch(requestEvent string, requestData interface{}, responseEvent string, res interface{}) error { // Emit a new event with the given data
func (c *Client) Emit(event string, data interface{}) error {
c.Logf("emit '%s' event", event)
if err := c.conn.Emit(event, data); err != nil {
return errors.Wrapf(err, "error while emitting '%s' event", event)
}
c.Logf("'%s' event sent", event)
return nil
}
// On binds and event handler to the given event
func (c *Client) On(event string, handler interface{}) error {
return c.conn.On(event, handler)
}
// Off remove the handler bound to the given event
func (c *Client) Off(event string) {
c.conn.Off(event)
}
// ReqResp emits an event with the given data and waits for a response
func (c *Client) ReqResp(requestEvent string, requestData interface{}, responseEvent string, res interface{}) error {
var err error var err error
var wg sync.WaitGroup var wg sync.WaitGroup
@ -89,11 +114,9 @@ func (c *client) fetch(requestEvent string, requestData interface{}, responseEve
return errors.Wrapf(err, "error while binding to '%s' event", responseEvent) return errors.Wrapf(err, "error while binding to '%s' event", responseEvent)
} }
c.logf("sending '%s' event", requestEvent) if err := c.Emit(requestEvent, requestData); err != nil {
if err = c.conn.Emit(requestEvent, requestData); err != nil { return errors.Wrapf(err, "error while emitting event '%s'", requestEvent)
return errors.Wrapf(err, "error while emitting '%s' event", requestEvent)
} }
c.logf("'%s' event sent", requestEvent)
wg.Wait() wg.Wait()
@ -101,19 +124,21 @@ func (c *client) fetch(requestEvent string, requestData interface{}, responseEve
} }
func (c *client) logf(format string, args ...interface{}) { // Logf logs the given message with the configured logger
func (c *Client) Logf(format string, args ...interface{}) {
if c.opts.Logger == nil { if c.opts.Logger == nil {
return return
} }
c.opts.Logger.Printf(format, args...) c.opts.Logger.Printf(format, args...)
} }
func newClient(opts ...OptionFunc) *client { // NewClient returns a new ReachRS websocket client
func NewClient(opts ...OptionFunc) *Client {
options := DefaultOptions() options := DefaultOptions()
for _, o := range opts { for _, o := range opts {
o(options) o(options)
} }
return &client{ return &Client{
opts: options, opts: options,
} }
} }

View File

@ -1,4 +1,4 @@
package reach package emlid
import ( import (
"log" "log"

View File

@ -1,4 +1,4 @@
// Package reach is a package to configure EMLID ReachRS modules in Go. // Package emlid is a package to configure EMLID ReachRS modules in Go.
// //
// It aims to provide a simple interface to common ReachRS modules management operations. // It aims to provide a simple interface to common ReachRS modules management operations.
package reach package emlid

14
emlid/reachview/client.go Normal file
View File

@ -0,0 +1,14 @@
package reachview
import "forge.cadoles.com/Pyxis/orion/emlid"
// Client is a ReachRS Updater client
type Client struct {
*emlid.Client
}
// NewClient returns a new ReachRS ReachView client
func NewClient(opts ...emlid.OptionFunc) *Client {
client := emlid.NewClient(opts...)
return &Client{client}
}

View File

@ -1,4 +1,4 @@
package reach package reachview
const ( const (
eventGetConfiguration = "get configuration" eventGetConfiguration = "get configuration"
@ -35,9 +35,9 @@ type PositionningSystems struct {
} }
// Configuration fetches and return the current configuration of the ReachRS module // Configuration fetches and return the current configuration of the ReachRS module
func (r *ReachView) Configuration() (*Configuration, error) { func (r *Client) Configuration() (*Configuration, error) {
configuration := &Configuration{} configuration := &Configuration{}
if err := r.fetch(eventGetConfiguration, nil, eventCurrentConfiguration, configuration); err != nil { if err := r.ReqResp(eventGetConfiguration, nil, eventCurrentConfiguration, configuration); err != nil {
return nil, err return nil, err
} }
return configuration, nil return configuration, nil

View File

@ -1,7 +1,9 @@
package reach package reachview
import ( import (
"testing" "testing"
"forge.cadoles.com/Pyxis/orion/emlid"
) )
func TestReachViewConfiguration(t *testing.T) { func TestReachViewConfiguration(t *testing.T) {
@ -10,9 +12,9 @@ func TestReachViewConfiguration(t *testing.T) {
t.Skip("To run this test, use: go test -reachview-integration") t.Skip("To run this test, use: go test -reachview-integration")
} }
client := NewReachViewClient( client := NewClient(
WithStandardLogger(), emlid.WithStandardLogger(),
WithEndpoint(*reachHost, 80), emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -1,12 +1,7 @@
package reach package reachview
import "flag" import "flag"
var runUpdaterIntegrationTests = flag.Bool(
"updater-integration", false,
"Run the 'Updater' integration tests (in addition to the unit tests)",
)
var runReachViewIntegrationTests = flag.Bool( var runReachViewIntegrationTests = flag.Bool(
"reachview-integration", false, "reachview-integration", false,
"Run the 'ReachView' integration tests (in addition to the unit tests)", "Run the 'ReachView' integration tests (in addition to the unit tests)",

15
emlid/updater/client.go Normal file
View File

@ -0,0 +1,15 @@
// Package updater provides an API to communicate with the ReachRS modules "Updater" application
package updater
import "forge.cadoles.com/Pyxis/orion/emlid"
// Client is a ReachRS Updater client
type Client struct {
*emlid.Client
}
// NewClient returns a new ReachRS Updater client
func NewClient(opts ...emlid.OptionFunc) *Client {
client := emlid.NewClient(opts...)
return &Client{client}
}

View File

@ -1,13 +1,15 @@
package reach package updater
import "log" import (
"log"
// ReachRS modules provides an Updater application when reset in factory mode. "forge.cadoles.com/Pyxis/orion/emlid"
// This package provides an API to communicate with this application. )
func Example_updaterClientUsage() {
func Example_usage() {
// Create a new Updater client instance // Create a new Updater client instance
updater := NewUpdaterClient( updater := NewClient(
WithEndpoint("192.168.42.1", 80), // Define the module endpoint emlid.WithEndpoint("192.168.42.1", 80), // Define the module endpoint
) )
// Connect to the ReachRS Updater endpoint // Connect to the ReachRS Updater endpoint

View File

@ -0,0 +1,19 @@
package updater
const (
eventGetReachViewVersion = "get reachview version"
eventReachViewVersionResults = "current reachview version"
)
type reachViewVersion struct {
Version string `json:"version"`
}
// ReachViewVersion returns the ReachRS module ReachView version
func (c *Client) ReachViewVersion() (string, error) {
res := &reachViewVersion{}
if err := c.ReqResp(eventGetReachViewVersion, nil, eventReachViewVersionResults, res); err != nil {
return "", err
}
return res.Version, nil
}

View File

@ -1,7 +1,9 @@
package reach package updater
import ( import (
"testing" "testing"
"forge.cadoles.com/Pyxis/orion/emlid"
) )
func TestClientReachViewVersion(t *testing.T) { func TestClientReachViewVersion(t *testing.T) {
@ -10,9 +12,9 @@ func TestClientReachViewVersion(t *testing.T) {
t.Skip("To run this test, use: go test -updater-integration") t.Skip("To run this test, use: go test -updater-integration")
} }
client := NewUpdaterClient( client := NewClient(
WithStandardLogger(), emlid.WithStandardLogger(),
WithEndpoint(*reachHost, 80), emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -1,4 +1,4 @@
package reach package updater
import ( import (
"sync" "sync"
@ -12,15 +12,15 @@ const (
) )
// RebootNow asks the ReachRS module to reboot now // RebootNow asks the ReachRS module to reboot now
func (u *Updater) RebootNow(waitDisconnect bool) error { func (c *Client) RebootNow(waitDisconnect bool) error {
var err error var err error
var wg sync.WaitGroup var wg sync.WaitGroup
if waitDisconnect { if waitDisconnect {
wg.Add(1) wg.Add(1)
err = u.conn.On(gosocketio.OnDisconnection, func(h *gosocketio.Channel) { err = c.On(gosocketio.OnDisconnection, func(h *gosocketio.Channel) {
u.conn.Off(gosocketio.OnDisconnection) c.Off(gosocketio.OnDisconnection)
wg.Done() wg.Done()
}) })
if err != nil { if err != nil {
@ -28,11 +28,9 @@ func (u *Updater) RebootNow(waitDisconnect bool) error {
} }
} }
u.logf("sending '%s' event", eventReboot) if err = c.Emit(eventReboot, nil); err != nil {
if err = u.conn.Emit(eventReboot, nil); err != nil { return err
return errors.Wrapf(err, "error while emitting '%s' event", eventReboot)
} }
u.logf("'%s' event sent", eventReboot)
if waitDisconnect { if waitDisconnect {
wg.Wait() wg.Wait()

View File

@ -1,18 +1,24 @@
package reach package updater
import ( import (
"testing" "testing"
"forge.cadoles.com/Pyxis/orion/emlid"
) )
func TestClientReboutNow(t *testing.T) { func TestClientRebootNow(t *testing.T) {
if !*runUpdaterIntegrationTests { if !*runUpdaterIntegrationTests {
t.Skip("To run this test, use: go test -updater-integration") t.Skip("To run this test, use: go test -updater-integration")
} }
client := NewUpdaterClient( if !*runRebootTest {
WithStandardLogger(), t.Skip("To run this test, use: go test -updater-reboot-test")
WithEndpoint(*reachHost, 80), }
client := NewClient(
emlid.WithStandardLogger(),
emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -0,0 +1,21 @@
package updater
const (
eventIsReceiverUpgradeAvailable = "is receiver upgrade available"
eventReceiverUpgradeAvailable = "receiver upgrade available"
)
type receiverUpgreAvailable struct {
Available bool `json:"available"`
Running bool `json:"running"`
}
// ReceiverUpgradeAvailable checks if an upgrade is avaialable/running for the ReachRS module
func (c *Client) ReceiverUpgradeAvailable() (bool, bool, error) {
res := &receiverUpgreAvailable{}
if err := c.ReqResp(eventIsReceiverUpgradeAvailable, nil, eventReceiverUpgradeAvailable, res); err != nil {
return false, false, err
}
c.Logf("receiver upgrade result: available: %v, running: %v", res.Available, res.Running)
return res.Available, res.Running, nil
}

View File

@ -1,7 +1,9 @@
package reach package updater
import ( import (
"testing" "testing"
"forge.cadoles.com/Pyxis/orion/emlid"
) )
func TestClientReceiverUpgradeAvailable(t *testing.T) { func TestClientReceiverUpgradeAvailable(t *testing.T) {
@ -10,9 +12,9 @@ func TestClientReceiverUpgradeAvailable(t *testing.T) {
t.Skip("To run this test, use: go test -updater-integration") t.Skip("To run this test, use: go test -updater-integration")
} }
client := NewUpdaterClient( client := NewClient(
WithStandardLogger(), emlid.WithStandardLogger(),
WithEndpoint(*reachHost, 80), emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)

23
emlid/updater/test.go Normal file
View File

@ -0,0 +1,23 @@
package updater
import "flag"
var runUpdaterIntegrationTests = flag.Bool(
"updater-integration", false,
"Run the 'Updater' integration tests (in addition to the unit tests)",
)
var runRebootTest = flag.Bool(
"updater-reboot-test", false,
"Run the updater 'Reboot' test (in addition to the unit tests)",
)
var runJoinNetworkTest = flag.Bool(
"updater-join-network-test", false,
"Run the updater 'JoinWiFiNetwork' test (in addition to the unit tests)",
)
var reachHost = flag.String(
"reach-host", "192.168.42.1",
"The Reach module host to use in integration tests",
)

View File

@ -0,0 +1,25 @@
package updater
const (
eventGetTestResults = "get test results"
eventTestResults = "test results"
)
// TestResults are the ReachRS module's test results
//
type TestResults struct {
Device string `json:"device"`
Lora bool `json:"lora"`
MPU bool `json:"mpu"`
STC bool `json:"stc"`
UBlox bool `json:"u-blox"`
}
// TestResults returns the ReachRS module tests results
func (c *Client) TestResults() (*TestResults, error) {
res := &TestResults{}
if err := c.ReqResp(eventGetTestResults, nil, eventTestResults, res); err != nil {
return nil, err
}
return res, nil
}

View File

@ -1,7 +1,9 @@
package reach package updater
import ( import (
"testing" "testing"
"forge.cadoles.com/Pyxis/orion/emlid"
) )
func TestClientTestResults(t *testing.T) { func TestClientTestResults(t *testing.T) {
@ -10,9 +12,9 @@ func TestClientTestResults(t *testing.T) {
t.Skip("To run this test, use: go test -updater-integration") t.Skip("To run this test, use: go test -updater-integration")
} }
client := NewUpdaterClient( client := NewClient(
WithStandardLogger(), emlid.WithStandardLogger(),
WithEndpoint(*reachHost, 80), emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -0,0 +1,21 @@
package updater
const (
eventGetTimeSyncStatus = "get time sync status"
eventTimeSyncResults = "time sync status"
)
type timeSyncStatus struct {
Status bool `json:"status"`
}
// TimeSynced returns the ReachRS module time synchronization status.
// A true response means that the module has synchronized its clock.
func (c *Client) TimeSynced() (bool, error) {
res := &timeSyncStatus{}
if err := c.ReqResp(eventGetTimeSyncStatus, nil, eventTimeSyncResults, res); err != nil {
return false, err
}
c.Logf("time sync result: %v", res.Status)
return res.Status, nil
}

View File

@ -1,7 +1,9 @@
package reach package updater
import ( import (
"testing" "testing"
"forge.cadoles.com/Pyxis/orion/emlid"
) )
func TestClientTimeSync(t *testing.T) { func TestClientTimeSync(t *testing.T) {
@ -10,9 +12,9 @@ func TestClientTimeSync(t *testing.T) {
t.Skip("To run this test, use: go test -updater-integration") t.Skip("To run this test, use: go test -updater-integration")
} }
client := NewUpdaterClient( client := NewClient(
WithStandardLogger(), emlid.WithStandardLogger(),
WithEndpoint(*reachHost, 80), emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)

26
emlid/updater/update.go Normal file
View File

@ -0,0 +1,26 @@
package updater
const (
eventUpdate = "update"
eventOPKGUpdateResult = "opkg update result"
)
// UpdateStatus embeds informations about update status
type UpdateStatus struct {
Active bool `json:"active"`
Locked bool `json:"locked"`
State string `json:"state"`
}
// Update asks the ReachRS module to start an OPKG update
func (c *Client) Update() (*UpdateStatus, error) {
res := &UpdateStatus{}
if err := c.ReqResp(eventUpdate, nil, eventOPKGUpdateResult, res); err != nil {
return nil, err
}
c.Logf(
"opkg update result: active: %v, state: %v, locked: %v",
res.Active, res.State, res.Locked,
)
return res, nil
}

View File

@ -1,7 +1,9 @@
package reach package updater
import ( import (
"testing" "testing"
"forge.cadoles.com/Pyxis/orion/emlid"
) )
func TestClientOPKGUpdate(t *testing.T) { func TestClientOPKGUpdate(t *testing.T) {
@ -10,9 +12,9 @@ func TestClientOPKGUpdate(t *testing.T) {
t.Skip("To run this test, use: go test -updater-integration") t.Skip("To run this test, use: go test -updater-integration")
} }
client := NewUpdaterClient( client := NewClient(
WithStandardLogger(), emlid.WithStandardLogger(),
WithEndpoint(*reachHost, 80), emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -0,0 +1,101 @@
package updater
import (
"sync"
"forge.cadoles.com/Pyxis/golang-socketio"
"github.com/pkg/errors"
)
const (
eventGetSavedWifiNetworks = "get saved wifi networks"
eventSavedWifiNetworkResults = "wifi saved networks results"
eventAddWifiNetwork = "add new network"
eventAddWifiNetworkResults = "add network results"
eventRemoveWifiNetwork = "remove network"
eventRemoveWifiNetworkResults = "remove network results"
eventConnectToNetwork = "connect to network"
)
// WifiSecurity is a WiFi network security algorithm
type WifiSecurity string
const (
// SecurityWEP WEP wifi network
SecurityWEP WifiSecurity = "wep"
// SecurityWPAPSK WPA(2)-PSK wifi network
SecurityWPAPSK WifiSecurity = "wpa-psk"
// SecurityOpen Open wifi network
SecurityOpen WifiSecurity = "open"
)
// WifiNetwork is a ReachRS module wifi network
type WifiNetwork struct {
SSID string `json:"ssid"`
Password string `json:"password"`
Security WifiSecurity `json:"security"`
Identity string `json:"identity"`
Visible bool `json:"is_visible"`
Connected bool `json:"is_connected"`
Added bool `json:"is_added"`
}
// WifiNetworks returns the ReachRS module wifi networks
func (c *Client) WifiNetworks() ([]WifiNetwork, error) {
res := make([]WifiNetwork, 0)
if err := c.ReqResp(eventGetSavedWifiNetworks, nil, eventSavedWifiNetworkResults, &res); err != nil {
return nil, err
}
return res, nil
}
// AddWifiNetwork asks the ReachRS module to save the given wifi network informations
func (c *Client) AddWifiNetwork(ssid string, security WifiSecurity, password string) (bool, error) {
res := false
network := &WifiNetwork{
SSID: ssid,
Security: security,
Password: password,
}
if err := c.ReqResp(eventAddWifiNetwork, network, eventAddWifiNetworkResults, &res); err != nil {
return false, err
}
return res, nil
}
// RemoveWifiNetwork asks the ReachRS module to remove the given WiFi network
func (c *Client) RemoveWifiNetwork(ssid string) (bool, error) {
res := false
if err := c.ReqResp(eventRemoveWifiNetwork, ssid, eventRemoveWifiNetworkResults, &res); err != nil {
return false, err
}
return res, nil
}
// JoinWifiNetwork asks the ReachRS module to join the given WiFi network
func (c *Client) JoinWifiNetwork(ssid string, waitDisconnect bool) error {
var err error
var wg sync.WaitGroup
if waitDisconnect {
wg.Add(1)
err = c.On(gosocketio.OnDisconnection, func(h *gosocketio.Channel) {
c.Off(gosocketio.OnDisconnection)
wg.Done()
})
if err != nil {
return errors.Wrapf(err, "error while binding to '%s' event", gosocketio.OnDisconnection)
}
}
if err := c.Emit(eventConnectToNetwork, ssid); err != nil {
return errors.Wrapf(err, "error while emitting '%s' event", eventConnectToNetwork)
}
if waitDisconnect {
wg.Wait()
}
return nil
}

View File

@ -1,10 +1,12 @@
package reach package updater
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
"testing" "testing"
"time" "time"
"forge.cadoles.com/Pyxis/orion/emlid"
) )
func TestClientSavedWiFiNetworks(t *testing.T) { func TestClientSavedWiFiNetworks(t *testing.T) {
@ -13,9 +15,9 @@ func TestClientSavedWiFiNetworks(t *testing.T) {
t.Skip("To run this test, use: go test -updater-integration") t.Skip("To run this test, use: go test -updater-integration")
} }
client := NewUpdaterClient( client := NewClient(
WithStandardLogger(), emlid.WithStandardLogger(),
WithEndpoint(*reachHost, 80), emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)
@ -36,9 +38,9 @@ func TestClientCRUDWiFiNetwork(t *testing.T) {
t.Skip("To run this test, use: go test -updater-integration") t.Skip("To run this test, use: go test -updater-integration")
} }
client := NewUpdaterClient( client := NewClient(
WithStandardLogger(), emlid.WithStandardLogger(),
WithEndpoint(*reachHost, 80), emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)
@ -91,9 +93,13 @@ func TestClientWifiNetworkJoin(t *testing.T) {
t.Skip("To run this test, use: go test -updater-integration") t.Skip("To run this test, use: go test -updater-integration")
} }
client := NewUpdaterClient( if !*runJoinNetworkTest {
WithStandardLogger(), t.Skip("To run this test, use: go test -updater-join-network-test")
WithEndpoint(*reachHost, 80), }
client := NewClient(
emlid.WithStandardLogger(),
emlid.WithEndpoint(*reachHost, 80),
) )
if err := client.Connect(); err != nil { if err := client.Connect(); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -6,7 +6,8 @@ import (
"log" "log"
"strings" "strings"
"forge.cadoles.com/Pyxis/orion/reach" "forge.cadoles.com/Pyxis/orion/emlid"
"forge.cadoles.com/Pyxis/orion/emlid/updater"
) )
const ( const (
@ -18,7 +19,7 @@ var (
phase = phaseConfigureWifi phase = phaseConfigureWifi
host = "192.168.42.1" host = "192.168.42.1"
ssid = "" ssid = ""
security = string(reach.SecurityWPAPSK) security = string(updater.SecurityWPAPSK)
password = "" password = ""
) )
@ -51,20 +52,20 @@ func main() {
} }
func connect() *reach.Updater { func connect() *updater.Client {
updater := reach.NewUpdaterClient( c := updater.NewClient(
reach.WithEndpoint(host, 80), emlid.WithEndpoint(host, 80),
) )
log.Printf("connecting to module '%s'", host) log.Printf("connecting to module '%s'", host)
if err := updater.Connect(); err != nil { if err := c.Connect(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Println("connected") log.Println("connected")
return updater return c
} }
@ -74,11 +75,11 @@ func configureWifi() {
log.Fatal("you must provide a WiFi SSID with the -ssid flag") log.Fatal("you must provide a WiFi SSID with the -ssid flag")
} }
updater := connect() c := connect()
defer updater.Close() defer c.Close()
log.Println("checking module status") log.Println("checking module status")
results, err := updater.TestResults() results, err := c.TestResults()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -91,7 +92,7 @@ func configureWifi() {
log.Printf("adding wifi network '%s'", ssid) log.Printf("adding wifi network '%s'", ssid)
done, err := updater.AddWifiNetwork(ssid, reach.WifiSecurity(security), password) done, err := c.AddWifiNetwork(ssid, updater.WifiSecurity(security), password)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -101,7 +102,7 @@ func configureWifi() {
} }
log.Println("connecting module to wifi network") log.Println("connecting module to wifi network")
if err := updater.JoinWifiNetwork(ssid, true); err != nil { if err := c.JoinWifiNetwork(ssid, true); err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Printf("you can now switch to the wifi network and start phase '%s'", phaseUpdateThenReboot) log.Printf("you can now switch to the wifi network and start phase '%s'", phaseUpdateThenReboot)
@ -109,25 +110,26 @@ func configureWifi() {
} }
func updateThenReboot() { func updateThenReboot() {
updater := connect()
defer updater.Close() c := connect()
defer c.Close()
log.Println("checking time sync") log.Println("checking time sync")
synced, err := updater.TimeSynced() synced, err := c.TimeSynced()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Printf("time synced ? %v", synced) log.Printf("time synced ? %v", synced)
log.Println("checking reachview version") log.Println("checking reachview version")
version, err := updater.ReachViewVersion() version, err := c.ReachViewVersion()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
log.Printf("reachview version ? '%s'", version) log.Printf("reachview version ? '%s'", version)
log.Println("checking for update") log.Println("checking for update")
status, err := updater.Update() status, err := c.Update()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -141,7 +143,7 @@ func updateThenReboot() {
} }
log.Println("rebooting device") log.Println("rebooting device")
if err := updater.RebootNow(true); err != nil { if err := c.RebootNow(true); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -1,26 +0,0 @@
package reach
import (
"github.com/pkg/errors"
)
const (
// EventBrowserConnected is emitted after the initial connection to the
// ReachView endpoint
eventBrowserConnected = "browser connected"
)
// sendBrowserConnected notifies the ReachView endpoint
// of a new connection.
// See misc/reachview/update_main.js line 297
func (c *client) sendBrowserConnected() error {
payload := map[string]string{
"data": "I'm connected",
}
c.logf("sending '%s' event", eventBrowserConnected)
if err := c.conn.Emit(eventBrowserConnected, payload); err != nil {
return errors.Wrapf(err, "error while emitting '%s' event", eventBrowserConnected)
}
c.logf("'%s' event sent", eventBrowserConnected)
return nil
}

View File

@ -1,12 +0,0 @@
package reach
// ReachView is a ReachRS Updater client
type ReachView struct { // nolint: golint
*client
}
// NewReachViewClient returns a new ReachRS ReachView client
func NewReachViewClient(opts ...OptionFunc) *ReachView {
client := newClient(opts...)
return &ReachView{client}
}

View File

@ -1,49 +0,0 @@
package reach
import (
"sync"
"forge.cadoles.com/Pyxis/golang-socketio"
"github.com/pkg/errors"
)
const (
eventGetReachViewVersion = "get reachview version"
eventReachViewVersionResults = "current reachview version"
)
type reachViewVersion struct {
Version string `json:"version"`
}
// ReachViewVersion returns the ReachRS module ReachView version
func (u *Updater) ReachViewVersion() (string, error) {
var err error
var version string
var wg sync.WaitGroup
wg.Add(1)
err = u.conn.On(eventReachViewVersionResults, func(h *gosocketio.Channel, rv *reachViewVersion) {
version = rv.Version
u.conn.Off(eventReachViewVersionResults)
wg.Done()
})
if err != nil {
return "", errors.Wrapf(err, "error while binding to '%s' event", eventReachViewVersionResults)
}
u.logf("sending '%s' event", eventGetReachViewVersion)
if err = u.conn.Emit(eventGetReachViewVersion, nil); err != nil {
return "", errors.Wrapf(err, "error while emitting '%s' event", eventGetReachViewVersion)
}
u.logf("'%s' event sent", eventGetReachViewVersion)
wg.Wait()
u.logf("reachview version result: %v", version)
return version, err
}

View File

@ -1,49 +0,0 @@
package reach
import (
"sync"
"forge.cadoles.com/Pyxis/golang-socketio"
"github.com/pkg/errors"
)
const (
eventIsReceiverUpgradeAvailable = "is receiver upgrade available"
eventReceiverUpgradeAvailable = "receiver upgrade available"
)
type receiverUpgreAvailable struct {
Available bool `json:"available"`
Running bool `json:"running"`
}
// ReceiverUpgradeAvailable checks if an upgrade is avaialable/running for the ReachRS module
func (u *Updater) ReceiverUpgradeAvailable() (available bool, running bool, err error) {
var wg sync.WaitGroup
wg.Add(1)
err = u.conn.On(eventReceiverUpgradeAvailable, func(h *gosocketio.Channel, up *receiverUpgreAvailable) {
available = up.Available
running = up.Running
u.conn.Off(eventReceiverUpgradeAvailable)
wg.Done()
})
if err != nil {
return false, false, errors.Wrapf(err, "error while binding to '%s' event", eventReceiverUpgradeAvailable)
}
u.logf("sending '%s' event", eventIsReceiverUpgradeAvailable)
if err = u.conn.Emit(eventIsReceiverUpgradeAvailable, nil); err != nil {
return false, false, errors.Wrapf(err, "error while emitting '%s' event", eventIsReceiverUpgradeAvailable)
}
u.logf("'%s' event sent", eventIsReceiverUpgradeAvailable)
wg.Wait()
u.logf("receiver upgrade result: available: %v, running: %v", available, running)
return available, running, err
}

View File

@ -1,53 +0,0 @@
package reach
import (
"sync"
"forge.cadoles.com/Pyxis/golang-socketio"
"github.com/pkg/errors"
)
const (
eventGetTestResults = "get test results"
eventTestResults = "test results"
)
// TestResults are the ReachRS module's test results
//
type TestResults struct {
Device string `json:"device"`
Lora bool `json:"lora"`
MPU bool `json:"mpu"`
STC bool `json:"stc"`
UBlox bool `json:"u-blox"`
}
// TestResults returns the ReachRS module tests results
func (u *Updater) TestResults() (*TestResults, error) {
var err error
var results *TestResults
var wg sync.WaitGroup
wg.Add(1)
err = u.conn.On(eventTestResults, func(h *gosocketio.Channel, res *TestResults) {
results = res
u.conn.Off(eventTestResults)
wg.Done()
})
if err != nil {
return nil, errors.Wrapf(err, "error while binding to '%s' event", eventTestResults)
}
u.logf("sending '%s' event", eventGetTestResults)
if err = u.conn.Emit(eventGetTestResults, nil); err != nil {
return nil, errors.Wrapf(err, "error while emitting '%s' event", eventGetTestResults)
}
u.logf("'%s' event sent", eventGetTestResults)
wg.Wait()
return results, err
}

View File

@ -1,50 +0,0 @@
package reach
import (
"sync"
"forge.cadoles.com/Pyxis/golang-socketio"
"github.com/pkg/errors"
)
const (
eventGetTimeSyncStatus = "get time sync status"
eventTimeSyncResults = "time sync status"
)
type timeSyncStatus struct {
Status bool `json:"status"`
}
// TimeSynced returns the ReachRS module time synchronization status.
// A true response means that the module has synchronized its clock.
func (u *Updater) TimeSynced() (bool, error) {
var err error
var synced bool
var wg sync.WaitGroup
wg.Add(1)
err = u.conn.On(eventTimeSyncResults, func(h *gosocketio.Channel, st *timeSyncStatus) {
synced = st.Status
u.conn.Off(eventTimeSyncResults)
wg.Done()
})
if err != nil {
return false, errors.Wrapf(err, "error while binding to '%s' event", eventTimeSyncResults)
}
u.logf("sending '%s' event", eventGetTimeSyncStatus)
if err = u.conn.Emit(eventGetTimeSyncStatus, nil); err != nil {
return false, errors.Wrapf(err, "error while emitting '%s' event", eventGetTimeSyncStatus)
}
u.logf("'%s' event sent", eventGetTimeSyncStatus)
wg.Wait()
u.logf("time sync result: %v", synced)
return synced, err
}

View File

@ -1,55 +0,0 @@
package reach
import (
"sync"
"forge.cadoles.com/Pyxis/golang-socketio"
"github.com/pkg/errors"
)
const (
eventUpdate = "update"
eventOPKGUpdateResult = "opkg update result"
)
// UpdateStatus embeds informations about update status
type UpdateStatus struct {
Active bool `json:"active"`
Locked bool `json:"locked"`
State string `json:"state"`
}
// Update asks the ReachRS module to start an OPKG update
func (u *Updater) Update() (*UpdateStatus, error) {
var err error
var status *UpdateStatus
var wg sync.WaitGroup
wg.Add(1)
err = u.conn.On(eventOPKGUpdateResult, func(h *gosocketio.Channel, st *UpdateStatus) {
status = st
u.conn.Off(eventOPKGUpdateResult)
wg.Done()
})
if err != nil {
return nil, errors.Wrapf(err, "error while binding to '%s' event", eventOPKGUpdateResult)
}
u.logf("sending '%s' event", eventUpdate)
if err = u.conn.Emit(eventUpdate, nil); err != nil {
return nil, errors.Wrapf(err, "error while emitting '%s' event", eventUpdate)
}
u.logf("'%s' event sent", eventUpdate)
wg.Wait()
u.logf(
"opkg update result: active: %v, state: %v, locked: %v",
status.Active, status.State, status.Locked,
)
return status, err
}

View File

@ -1,12 +0,0 @@
package reach
// Updater is a ReachRS Updater client
type Updater struct {
*client
}
// NewUpdaterClient returns a new ReachRS Updater client
func NewUpdaterClient(opts ...OptionFunc) *Updater {
client := newClient(opts...)
return &Updater{client}
}

View File

@ -1,171 +0,0 @@
package reach
import (
"sync"
"forge.cadoles.com/Pyxis/golang-socketio"
"github.com/pkg/errors"
)
const (
eventGetSavedWifiNetworks = "get saved wifi networks"
eventSavedWifiNetworkResults = "wifi saved networks results"
eventAddWifiNetwork = "add new network"
eventAddWifiNetworkResults = "add network results"
eventRemoveWifiNetwork = "remove network"
eventRemoveWifiNetworkResults = "remove network results"
eventConnectToNetwork = "connect to network"
)
// WifiSecurity is a WiFi network security algorithm
type WifiSecurity string
const (
// SecurityWEP WEP wifi network
SecurityWEP WifiSecurity = "wep"
// SecurityWPAPSK WPA(2)-PSK wifi network
SecurityWPAPSK WifiSecurity = "wpa-psk"
// SecurityOpen Open wifi network
SecurityOpen WifiSecurity = "open"
)
// WifiNetwork is a ReachRS module wifi network
type WifiNetwork struct {
SSID string `json:"ssid"`
Password string `json:"password"`
Security WifiSecurity `json:"security"`
Identity string `json:"identity"`
Visible bool `json:"is_visible"`
Connected bool `json:"is_connected"`
Added bool `json:"is_added"`
}
// WifiNetworks returns the ReachRS module wifi networks
func (u *Updater) WifiNetworks() ([]*WifiNetwork, error) {
var err error
var wifiNetworks []*WifiNetwork
var wg sync.WaitGroup
wg.Add(1)
err = u.conn.On(eventSavedWifiNetworkResults, func(h *gosocketio.Channel, wn []*WifiNetwork) {
wifiNetworks = wn
u.conn.Off(eventSavedWifiNetworkResults)
wg.Done()
})
if err != nil {
return nil, errors.Wrapf(err, "error while binding to '%s' event", eventSavedWifiNetworkResults)
}
u.logf("sending '%s' event", eventGetSavedWifiNetworks)
if err = u.conn.Emit(eventGetSavedWifiNetworks, nil); err != nil {
return nil, errors.Wrapf(err, "error while emitting '%s' event", eventGetSavedWifiNetworks)
}
u.logf("'%s' event sent", eventGetSavedWifiNetworks)
wg.Wait()
return wifiNetworks, err
}
// AddWifiNetwork asks the ReachRS module to save the given wifi network informations
func (u *Updater) AddWifiNetwork(ssid string, security WifiSecurity, password string) (bool, error) {
var err error
var wg sync.WaitGroup
var done bool
wg.Add(1)
err = u.conn.On(eventAddWifiNetworkResults, func(h *gosocketio.Channel, d bool) {
done = d
u.conn.Off(eventAddWifiNetworkResults)
wg.Done()
})
if err != nil {
return false, errors.Wrapf(err, "error while binding to '%s' event", eventAddWifiNetworkResults)
}
wn := &WifiNetwork{
SSID: ssid,
Security: security,
Password: password,
}
u.logf("sending '%s' event", eventAddWifiNetwork)
if err = u.conn.Emit(eventAddWifiNetwork, wn); err != nil {
return false, errors.Wrapf(err, "error while emitting '%s' event", eventAddWifiNetwork)
}
u.logf("'%s' event sent", eventAddWifiNetwork)
wg.Wait()
return done, err
}
// RemoveWifiNetwork asks the ReachRS module to remove the given WiFi network
func (u *Updater) RemoveWifiNetwork(ssid string) (bool, error) {
var err error
var wg sync.WaitGroup
var done bool
wg.Add(1)
err = u.conn.On(eventRemoveWifiNetworkResults, func(h *gosocketio.Channel, d bool) {
done = d
u.conn.Off(eventRemoveWifiNetworkResults)
wg.Done()
})
if err != nil {
return false, errors.Wrapf(err, "error while binding to '%s' event", eventRemoveWifiNetworkResults)
}
u.logf("sending '%s' event", eventRemoveWifiNetwork)
if err := u.conn.Emit(eventRemoveWifiNetwork, ssid); err != nil {
return false, errors.Wrapf(err, "error while emitting '%s' event", eventRemoveWifiNetwork)
}
u.logf("'%s' event sent", eventRemoveWifiNetwork)
wg.Wait()
return done, nil
}
// JoinWifiNetwork asks the ReachRS module to join the given WiFi network
func (u *Updater) JoinWifiNetwork(ssid string, waitDisconnect bool) error {
var err error
var wg sync.WaitGroup
if waitDisconnect {
wg.Add(1)
err = u.conn.On(gosocketio.OnDisconnection, func(h *gosocketio.Channel) {
u.conn.Off(gosocketio.OnDisconnection)
wg.Done()
})
if err != nil {
return errors.Wrapf(err, "error while binding to '%s' event", gosocketio.OnDisconnection)
}
}
u.logf("sending '%s' event", eventConnectToNetwork)
if err := u.conn.Emit(eventConnectToNetwork, ssid); err != nil {
return errors.Wrapf(err, "error while emitting '%s' event", eventConnectToNetwork)
}
u.logf("'%s' event sent", eventConnectToNetwork)
if waitDisconnect {
wg.Wait()
}
return nil
}