diff --git a/Makefile b/Makefile index 09fb3c9..4ba546a 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ test: tidy go test -mod=vendor -v ./... lint: - @PATH=$(PATH):./bin/gometalinter gometalinter -e '.*/pkg/mod' -e ".*/go/src" --vendor ./... + @PATH=$(PATH):./bin/gometalinter gometalinter -e '.*/pkg/mod' -e ".*/go/src" --vendor $(LINT_ARGS) ./... tidy: go mod tidy @@ -31,4 +31,8 @@ clean: rm -rf ./bin go clean -i -x -r -modcache -.PHONY: test clean generate vendor install-devtools lint watch tidy \ No newline at end of file +doc: + @echo "Open your browser to http://localhost:6060/pkg/forge.cadoles.com/Pyxis/orion/ to see the documentation" + @godoc -http=:6060 + +.PHONY: test clean generate vendor install-devtools lint watch tidy doc \ No newline at end of file diff --git a/go.mod b/go.mod index a351cfb..08eb7a8 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module forge.cadoles.com/Pyxis/orion require ( - forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180919081902-52a9157a070d + forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180919100209-bb857ced6b95 github.com/caarlos0/env v3.3.0+incompatible github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-chi/chi v3.3.3+incompatible diff --git a/go.sum b/go.sum index bff80fd..4749ce9 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180919081902-52a9157a070d h1:gkJw6IeJ+A/EVw48eUnZwbK36fBlDrfB5lNyEPAltLQ= -forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180919081902-52a9157a070d/go.mod h1:I6kYOFWNkFlNeQLI7ZqfTRz4NdPHZxX0Bzizmzgchs0= +forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180919100209-bb857ced6b95 h1:o3G5+9RjczCK1xAYFaRMknk1kY9Ule6PNfiW6N6hEpg= +forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180919100209-bb857ced6b95/go.mod h1:I6kYOFWNkFlNeQLI7ZqfTRz4NdPHZxX0Bzizmzgchs0= github.com/caarlos0/env v3.3.0+incompatible h1:jCfY0ilpzC2FFViyZyDKCxKybDESTwaR+ebh8zm6AOE= github.com/caarlos0/env v3.3.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/modd.conf b/modd.conf index fba3af3..b69c775 100644 --- a/modd.conf +++ b/modd.conf @@ -11,6 +11,7 @@ Makefile { **/*.go modd.conf Makefile { + prep: make lint LINT_ARGS=--fast prep: make test } diff --git a/reach/browser_connected.go b/reach/browser_connected.go index a859cbb..a773d5b 100644 --- a/reach/browser_connected.go +++ b/reach/browser_connected.go @@ -7,20 +7,20 @@ import ( const ( // EventBrowserConnected is emitted after the initial connection to the // ReachView endpoint - EventBrowserConnected = "browser connected" + 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 { +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("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) + c.logf("'%s' event sent", eventBrowserConnected) return nil } diff --git a/reach/client.go b/reach/client.go index 257cb5b..539df72 100644 --- a/reach/client.go +++ b/reach/client.go @@ -2,26 +2,20 @@ package reach import ( "sync" - "time" "forge.cadoles.com/Pyxis/golang-socketio" "forge.cadoles.com/Pyxis/golang-socketio/transport" "github.com/pkg/errors" ) -type handshake struct { - PingInterval time.Duration `json:"pingInterval"` -} - -// Client is a ReachView Websocket API client -type Client struct { +type client struct { opts *Options conn *gosocketio.Client } // Connect connects the client to the ReachView endpoint // This method is not safe to call by different coroutines -func (c *Client) Connect() error { +func (c *client) Connect() error { var err error var wg sync.WaitGroup @@ -71,7 +65,7 @@ func (c *Client) Connect() error { } // Close closes the current connection to the ReachView endpoint -func (c *Client) Close() { +func (c *client) Close() { if c.conn == nil { return } @@ -80,20 +74,19 @@ func (c *Client) Close() { return } -func (c *Client) logf(format string, args ...interface{}) { +func (c *client) logf(format string, args ...interface{}) { if c.opts.Logger == nil { return } c.opts.Logger.Printf(format, args...) } -// NewClient returns a new ReachView Websocket API client -func NewClient(opts ...OptionFunc) *Client { +func newClient(opts ...OptionFunc) *client { options := DefaultOptions() for _, o := range opts { o(options) } - return &Client{ + return &client{ opts: options, } } diff --git a/reach/example_test.go b/reach/example_test.go new file mode 100644 index 0000000..eebcb4e --- /dev/null +++ b/reach/example_test.go @@ -0,0 +1,30 @@ +package reach + +import "log" + +// ReachRS modules provides an Updater application when reset in factory mode. +// This package provides an API to communicate with this application. +func Example_updaterClientUsage() { + // Create a new Updater client instance + updater := NewUpdaterClient( + WithEndpoint("192.168.42.1", 80), // Define the module endpoint + ) + + // Connect to the ReachRS Updater endpoint + if err := updater.Connect(); err != nil { + log.Fatal(err) + } + + networks, err := updater.SavedWifiNetworks() + if err != nil { + log.Fatal(err) + } + + // Do something with network + for _, n := range networks { + log.Printf("Save WiFi network: SSID: '%s', Security: '%s'", n.SSID, n.Security) + } + + // Dont forget to close the connection when you are done + defer updater.Close() +} diff --git a/reach/probe.go b/reach/probe.go deleted file mode 100644 index 802b9f3..0000000 --- a/reach/probe.go +++ /dev/null @@ -1,37 +0,0 @@ -package reach - -import ( - "sync" - - "forge.cadoles.com/Pyxis/golang-socketio" - "github.com/pkg/errors" -) - -const ( - // EventProbe - - EventProbe = "probe" -) - -// Probe - -func (c *Client) Probe() error { - - var wg sync.WaitGroup - - wg.Add(1) - - c.conn.On(EventProbe, func(h *gosocketio.Channel) { - wg.Done() - c.conn.On(EventProbe, nil) - }) - - c.logf("sending '%s' event", EventProbe) - if err := c.conn.Emit(EventProbe, nil); err != nil { - return errors.Wrapf(err, "error while emitting '%s' event", EventProbe) - } - c.logf("'%s' event sent", EventProbe) - - wg.Wait() - - return nil - -} diff --git a/reach/reach.go b/reach/reach.go new file mode 100644 index 0000000..6a8aa41 --- /dev/null +++ b/reach/reach.go @@ -0,0 +1,4 @@ +// Package reach is a package to configure EMLID ReachRS modules in Go. +// +// It aims to provide a simple interface to common ReachRS modules management operations. +package reach diff --git a/reach/reachview_version.go b/reach/reachview_version.go new file mode 100644 index 0000000..db9b8c6 --- /dev/null +++ b/reach/reachview_version.go @@ -0,0 +1,49 @@ +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 + +} diff --git a/reach/reachview_version_test.go b/reach/reachview_version_test.go new file mode 100644 index 0000000..7dba9a8 --- /dev/null +++ b/reach/reachview_version_test.go @@ -0,0 +1,32 @@ +package reach + +import ( + "testing" +) + +func TestClientReachViewVersion(t *testing.T) { + + if !*runUpdaterIntegrationTests { + t.Skip("To run this test, use: go test -updater-integration") + } + + client := NewUpdaterClient( + WithStandardLogger(), + WithEndpoint(*reachHost, 80), + ) + if err := client.Connect(); err != nil { + t.Fatal(err) + } + + version, err := client.ReachViewVersion() + if err != nil { + t.Error(err) + } + + if version == "" { + t.Error("version should not be empty") + } + + defer client.Close() + +} diff --git a/reach/reboot_now.go b/reach/reboot_now.go new file mode 100644 index 0000000..3ccdcf3 --- /dev/null +++ b/reach/reboot_now.go @@ -0,0 +1,24 @@ +package reach + +import ( + "github.com/pkg/errors" +) + +const ( + eventReboot = "reboot now" +) + +// RebootNow asks the ReachRS module to reboot now +func (u *Updater) RebootNow() error { + + var err error + + u.logf("sending '%s' event", eventReboot) + if err = u.conn.Emit(eventReboot, nil); err != nil { + return errors.Wrapf(err, "error while emitting '%s' event", eventReboot) + } + u.logf("'%s' event sent", eventReboot) + + return err + +} diff --git a/reach/reboot_now_test.go b/reach/reboot_now_test.go new file mode 100644 index 0000000..41fbc8f --- /dev/null +++ b/reach/reboot_now_test.go @@ -0,0 +1,27 @@ +package reach + +import ( + "testing" +) + +func TestClientReboutNow(t *testing.T) { + + if !*runUpdaterIntegrationTests { + t.Skip("To run this test, use: go test -updater-integration") + } + + client := NewUpdaterClient( + WithStandardLogger(), + WithEndpoint(*reachHost, 80), + ) + if err := client.Connect(); err != nil { + t.Fatal(err) + } + + if err := client.RebootNow(); err != nil { + t.Error(err) + } + + defer client.Close() + +} diff --git a/reach/receiver_upgrade.go b/reach/receiver_upgrade.go new file mode 100644 index 0000000..79b9630 --- /dev/null +++ b/reach/receiver_upgrade.go @@ -0,0 +1,49 @@ +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 + +} diff --git a/reach/receiver_upgrade_test.go b/reach/receiver_upgrade_test.go new file mode 100644 index 0000000..a4358d2 --- /dev/null +++ b/reach/receiver_upgrade_test.go @@ -0,0 +1,28 @@ +package reach + +import ( + "testing" +) + +func TestClientReceiverUpgradeAvailable(t *testing.T) { + + if !*runUpdaterIntegrationTests { + t.Skip("To run this test, use: go test -updater-integration") + } + + client := NewUpdaterClient( + WithStandardLogger(), + WithEndpoint(*reachHost, 80), + ) + if err := client.Connect(); err != nil { + t.Fatal(err) + } + + _, _, err := client.ReceiverUpgradeAvailable() + if err != nil { + t.Error(err) + } + + defer client.Close() + +} diff --git a/reach/test.go b/reach/test.go new file mode 100644 index 0000000..5343fc6 --- /dev/null +++ b/reach/test.go @@ -0,0 +1,13 @@ +package reach + +import "flag" + +var runUpdaterIntegrationTests = flag.Bool( + "updater-integration", false, + "Run the 'Updater' integration tests (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", +) diff --git a/reach/test_results.go b/reach/test_results.go index 2ceb7bb..0c050b9 100644 --- a/reach/test_results.go +++ b/reach/test_results.go @@ -8,10 +8,8 @@ import ( ) const ( - // EventGetTestResults is a request for the ReachRS module's test results - EventGetTestResults = "get test results" - // EventTestResults is the response of the EventGetTestResults request - EventTestResults = "test results" + eventGetTestResults = "get test results" + eventTestResults = "test results" ) // TestResults are the ReachRS module's test results @@ -24,7 +22,7 @@ type TestResults struct { } // TestResults returns the ReachRS module tests results -func (c *Client) TestResults() (*TestResults, error) { +func (u *Updater) TestResults() (*TestResults, error) { var err error var results *TestResults @@ -32,17 +30,20 @@ func (c *Client) TestResults() (*TestResults, error) { wg.Add(1) - c.conn.On(EventTestResults, func(h *gosocketio.Channel, res *TestResults) { + err = u.conn.On(eventTestResults, func(h *gosocketio.Channel, res *TestResults) { results = res - c.conn.On(EventTestResults, nil) + u.conn.Off(eventTestResults) wg.Done() }) - - c.logf("sending '%s' event", EventGetTestResults) - if err = c.conn.Emit(EventGetTestResults, nil); err != nil { - return nil, errors.Wrapf(err, "error while emitting '%s' event", EventGetTestResults) + if err != nil { + return nil, errors.Wrapf(err, "error while binding to '%s' event", eventTestResults) } - c.logf("'%s' event sent", EventGetTestResults) + + 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() diff --git a/reach/client_test.go b/reach/test_results_test.go similarity index 62% rename from reach/client_test.go rename to reach/test_results_test.go index 658b98e..b8691bb 100644 --- a/reach/client_test.go +++ b/reach/test_results_test.go @@ -4,10 +4,15 @@ import ( "testing" ) -func TestClient(t *testing.T) { +func TestClientTestResults(t *testing.T) { - client := NewClient( + if !*runUpdaterIntegrationTests { + t.Skip("To run this test, use: go test -updater-integration") + } + + client := NewUpdaterClient( WithStandardLogger(), + WithEndpoint(*reachHost, 80), ) if err := client.Connect(); err != nil { t.Fatal(err) diff --git a/reach/time_sync.go b/reach/time_sync.go new file mode 100644 index 0000000..d9f8c96 --- /dev/null +++ b/reach/time_sync.go @@ -0,0 +1,49 @@ +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"` +} + +// TimeSyncStatus returns the ReachRS module time sync status +func (u *Updater) TimeSyncStatus() (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 + +} diff --git a/reach/time_sync_test.go b/reach/time_sync_test.go new file mode 100644 index 0000000..c6a6682 --- /dev/null +++ b/reach/time_sync_test.go @@ -0,0 +1,28 @@ +package reach + +import ( + "testing" +) + +func TestClientTimeSync(t *testing.T) { + + if !*runUpdaterIntegrationTests { + t.Skip("To run this test, use: go test -updater-integration") + } + + client := NewUpdaterClient( + WithStandardLogger(), + WithEndpoint(*reachHost, 80), + ) + if err := client.Connect(); err != nil { + t.Fatal(err) + } + + _, err := client.TimeSyncStatus() + if err != nil { + t.Error(err) + } + + defer client.Close() + +} diff --git a/reach/update.go b/reach/update.go new file mode 100644 index 0000000..1d078a3 --- /dev/null +++ b/reach/update.go @@ -0,0 +1,55 @@ +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"` + State string `json:"state"` + Locked bool `json:"locked"` +} + +// 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 + +} diff --git a/reach/update_test.go b/reach/update_test.go new file mode 100644 index 0000000..87161e4 --- /dev/null +++ b/reach/update_test.go @@ -0,0 +1,28 @@ +package reach + +import ( + "testing" +) + +func TestClientOPKGUpdate(t *testing.T) { + + if !*runUpdaterIntegrationTests { + t.Skip("To run this test, use: go test -updater-integration") + } + + client := NewUpdaterClient( + WithStandardLogger(), + WithEndpoint(*reachHost, 80), + ) + if err := client.Connect(); err != nil { + t.Fatal(err) + } + + _, err := client.Update() + if err != nil { + t.Error(err) + } + + defer client.Close() + +} diff --git a/reach/updater.go b/reach/updater.go new file mode 100644 index 0000000..888790d --- /dev/null +++ b/reach/updater.go @@ -0,0 +1,12 @@ +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} +} diff --git a/reach/wifi_networks.go b/reach/wifi_networks.go new file mode 100644 index 0000000..2abaecf --- /dev/null +++ b/reach/wifi_networks.go @@ -0,0 +1,148 @@ +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's saved wifi network +// Raw messages examples: +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"` +} + +// SavedWifiNetworks returns the ReachRS module saved wifi networks +func (u *Updater) SavedWifiNetworks() ([]*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 + +} + +// ConnectToWifiNetwork asks the ReachRS module to connect to the given WiFi network +func (u *Updater) ConnectToWifiNetwork(ssid string) error { + 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) + return nil +} diff --git a/reach/wifi_networks_test.go b/reach/wifi_networks_test.go new file mode 100644 index 0000000..e7d42e1 --- /dev/null +++ b/reach/wifi_networks_test.go @@ -0,0 +1,85 @@ +package reach + +import ( + "fmt" + "math/rand" + "testing" +) + +func TestClientSavedWiFiNetworks(t *testing.T) { + + if !*runUpdaterIntegrationTests { + t.Skip("To run this test, use: go test -updater-integration") + } + + client := NewUpdaterClient( + WithStandardLogger(), + WithEndpoint(*reachHost, 80), + ) + if err := client.Connect(); err != nil { + t.Fatal(err) + } + + _, err := client.SavedWifiNetworks() + if err != nil { + t.Error(err) + } + + defer client.Close() + +} + +func TestClientCRUDWiFiNetwork(t *testing.T) { + + if !*runUpdaterIntegrationTests { + t.Skip("To run this test, use: go test -updater-integration") + } + + client := NewUpdaterClient( + WithStandardLogger(), + WithEndpoint(*reachHost, 80), + ) + if err := client.Connect(); err != nil { + t.Fatal(err) + } + + ssid := fmt.Sprintf("wifi_test_%d", rand.Uint32()) + + done, err := client.AddWifiNetwork(ssid, SecurityOpen, "") + if err != nil { + t.Error(err) + } + + if g, e := done, true; g != e { + t.Errorf("AddWifiNetwork() -> done: got '%v', expected '%v'", g, e) + } + + networks, err := client.SavedWifiNetworks() + if err != nil { + t.Error(err) + } + + found := false + for _, n := range networks { + if n.SSID == ssid { + found = true + break + } + } + + if g, e := found, true; g != e { + t.Errorf("wifi network '%s' should exists", ssid) + } + + done, err = client.RemoveWifiNetwork(ssid) + if err != nil { + t.Error(err) + } + + if g, e := done, true; g != e { + t.Errorf("RemoveWifiNetwork() -> done: got '%v', expected '%v'", g, e) + } + + defer client.Close() + +}