Base de client ReachRS fonctionnelle

This commit is contained in:
wpetit 2018-09-18 18:07:40 +02:00
parent 267017bdc1
commit cd27332c4f
12 changed files with 1188 additions and 6 deletions

View File

@ -2,21 +2,25 @@ export GO111MODULE := on
build: bin/server
bin/server: vendor
CGO_ENABLED=0 go build -v -o ./bin/server ./cmd/server
bin/server:
CGO_ENABLED=0 go build -mod=vendor -v -o ./bin/server ./cmd/server
watch:
modd
test:
go test -v ./...
test: tidy
GO111MODULE=off go clean -testcache
go test -mod=vendor -v ./...
lint:
PATH=$(PATH):./bin/gometalinter gometalinter -e '.*/pkg/mod' --vendor ./...
vendor:
tidy:
go mod tidy
vendor: tidy
go mod vendor
install-devtools: vendor
# Install modd
GO111MODULE=off go get -u github.com/cortesi/modd/cmd/modd
@ -27,4 +31,4 @@ clean:
rm -rf ./bin
go clean -i -x -r -modcache
.PHONY: test clean generate vendor install-devtools lint watch
.PHONY: test clean generate vendor install-devtools lint watch tidy

14
doc/debug-websocket.md Normal file
View File

@ -0,0 +1,14 @@
# Débugger la communication websocket avec ReachView
## Intercepter les connexions sur le module ReachRS
Il est possible d'intercepter et logger les communications sur la connexion websocket de ReachView.
Pour ce faire, se connecter en SSH sur le module ReachRS et lancer la commande:
```
tcpdump -nl -w - -i wlan0 -c 500 port 80|strings
```
## Intercepter les connexions sortantes depuis la machine de test

3
go.mod
View File

@ -1,9 +1,12 @@
module forge.cadoles.com/Pyxis/orion
require (
forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180918160219-85050e6154f1
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
github.com/gorilla/websocket v1.4.0 // indirect
github.com/pkg/errors v0.8.0
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2 // indirect
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3 // indirect

6
go.sum
View File

@ -1,9 +1,15 @@
forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180918160219-85050e6154f1 h1:T/50zBZ+rLp9q7ntXpkKkiLBp5h8J5BnrHO6dbZUNqo=
forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180918160219-85050e6154f1/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=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-chi/chi v3.3.3+incompatible h1:KHkmBEMNkwKuK4FdQL7N2wOeB9jnIx7jR5wsuSBEFI8=
github.com/go-chi/chi v3.3.3+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=

View File

@ -0,0 +1,823 @@
/**
* ReachView code is placed under the GPL license.
* Written by Egor Fedorov (egor.fedorov@emlid.com) and Danil Kramorov (danil.kramorov@emlid.com)
* Copyright (c) 2015-2018, Emlid Limited
* All rights reserved.
*
* If you are interested in using ReachView code as a part of a
* closed source project, please contact Emlid Limited (info@emlid.com).
*
* This file is part of ReachView.
*
* ReachView is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ReachView is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ReachView. If not, see <http://www.gnu.org/licenses/>.
*/
$(document).ready(function () {
requirejs(['socket', 'bootstrap_select'], function (io, bootstrap_select) {
var lostConnectionNoty;
var addConnectionNoty;
var removeConnetctionNoty;
var emptyRequiredModal = false;
var incorrectSymbolsNumber = false;
var incorrectSymbols = false;
var syncInterval;
var new_network = {};
var to_append = '';
var testPass = false;
var wifiPass = false;
var timePass = false;
var receiverPass = false;
var updatePass = false;
var currentVersion = false;
var availableReceiverVersion = false;
var availableVersion = false;
var opkgResult = false;
var receiverLocked = false;
var device = '';
var preventLostConnectionNoty = false;
var disconnect_msg = 'Lost connection with Reach. Please check your network, then try refreshing the page.';
$('.bootstrap-select').selectpicker();
$('.styled, .multiselect-container input').uniform({ radioClass: 'choice' });
$(document).on('click', '#create_new_network', function () {
$(this).parents('.modal-content').find('.required_field:visible').each(function () {
if ($.trim($(this).val()) === '') {
emptyRequiredModal = true;
return false;
}
});
if ($('#new_network_pass:visible').length !== 0) {
if ($('#new_network_pass').val().length < 8) {
incorrectSymbolsNumber = true;
} else {
incorrectSymbolsNumber = false;
}
} else {
incorrectSymbolsNumber = false;
}
if (emptyRequiredModal) {
$(this).parents('.modal-content').find('.required_field:visible')
.filter(function () { return $.trim($(this).val()) === ''; }).css('border', '1px solid red');
$(this).parents('.modal-content').find('.required_field')
.filter(function () { return $.trim($(this).val()) !== ''; }).css('border', '1px solid #ddd');
emptyRequiredModal = false;
} else {
$(this).parents('.modal-content').find('.required_field').css('border', '1px solid #ddd');
if (incorrectSymbols) {
$('.modal_add_warning').text('Incorrect symbols. Use only a-z, 1-9 characters.');
} else if (incorrectSymbolsNumber) {
$('.modal_add_warning').text('Password should contain at least 8 characters');
} else {
new_network['ssid'] = $('#new_network_name').val();
new_network['password'] = $('#new_network_pass').val();
new_network['security'] = $('#security_select').val();
new_network['identity'] = $('#new_network_identity').val();
$('#modal_network').modal('hide');
socket.emit('add new network', new_network);
}
}
});
$(document).on('change', '#security_select', function () {
$('#new_network_identity').removeClass('required_field');
$('#new_network_identity').parents('.form-group').css('display', 'none');
$('#new_network_pass').addClass('required_field');
$('#new_network_pass').parents('.form-group').css('display', 'block');
$('#uniform-show_pass').parents('.form-group').css('display', 'block');
if ($(this).val() === 'open') {
$('#new_network_pass').removeClass('required_field');
$('#new_network_pass').parents('.form-group').css('display', 'none');
$('#uniform-show_pass').parents('.form-group').css('display', 'none');
} else if ($(this).val() == 'wpaeap') {
$('#new_network_identity').addClass('required_field');
$('#new_network_identity').parents('.form-group').css('display', 'block');
}
});
$('#modal_network').on('show.bs.modal', function () {
$('#new_network_name').val('');
$('#new_network_pass').val('');
$('#new_network_pass').attr('type', 'password');
$('#new_network_identity').val('');
$('#security_select').val('wpa-psk');
$('#security_select').selectpicker('refresh');
$('#show_pass').attr('checked', false);
$('#show_pass').parent().removeClass('checked');
$('.modal_add_warning').text('');
$('#security_select').change();
$('#modal_network input').css('border', '1px solid #ddd');
});
$(document).on('change', '#show_pass', function () {
if ($(this).is(':checked')) {
$('#new_network_pass').attr('type', 'text');
} else {
$('#new_network_pass').attr('type', 'password');
}
});
$(document).on('click', '#added_wi-fi li', function () {
if (!$(this).hasClass('connected_wi-fi_network')) {
$('#modal_saved_connect .network_title').text($(this).find('.wi-fi_title').text());
$('#modal_saved_connect .network_mac').text('Security: ' + $(this).find('.wi-fi_security').val());
$('#modal_saved_connect').modal('show');
}
return false;
});
$(document).on('click', '#connected_wi-fi li', function () {
return false;
});
$(document).on('click', '#connect_network', function () {
var ssid_to_connect = $('#modal_saved_connect .network_title').text();
disconnect_msg = 'Reach is connecting to another network. Switch to ' + ssid_to_connect + ' to continue.';
socket.emit('connect to network', ssid_to_connect);
$('#modal_saved_connect').modal('hide');
return false;
});
$(document).on('click', '#forget_network', function () {
var ssid_to_remove = $('#modal_saved_connect .network_title').text();
socket.emit('remove network', ssid_to_remove);
$('#modal_saved_connect').modal('hide');
return false;
});
$('.update_reachview').on('click', function () {
if (!$(this).hasClass('disabled')) {
receiverPass = true;
socket.emit('upgrade reachview');
$('.current_version').text('Updating...');
$('.update_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
$('.row_try_skip').css('display', 'none');
$('.skip_update_btn').css('display', 'none');
$('.update_reachview').addClass('disabled');
}
return false;
});
$('.skip_update, .skip_update_btn').on('click', function () {
receiverPass = true;
socket.emit('skip update');
$('.update_status').html('<i class="icon-checkmark3 text-success"></i>');
$('.update_anchor:not(.collapsed)').click();
$('.row_try_skip').css('display', 'none');
$('.skip_update_btn').css('display', 'none');
updatePass = true;
if (updatePass && receiverPass && timePass && wifiPass && testPass) {
$('.to_app').removeClass('disabled');
} else {
$('.to_app').addClass('disabled');
}
return false;
});
$('.try_again').on('click', function () {
receiverPass = true;
$('.row_try_skip').css('display', 'none');
currentVersion = false;
socket.emit('get reachview version');
$('.current_version').text('Getting current version...');
$('.update_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
return false;
});
$('.to_app').on('click', function () {
if (!$(this).hasClass('disabled')) {
disconnect_msg = 'Reach is rebooting and has been disconnected from this network.';
noty({
width: 200,
text: 'Reboot will start in 3...',
type: 'information',
dismissQueue: true,
timeout: 3000,
closeWith: false,
layout: 'topRight',
callback: {
onClose: function () {
if (device === 'ReachM+' || device === 'ReachRS+') {
preventLostConnectionNoty = true;
$('#modal_mender_guide').modal({ backdrop: 'static', keyboard: false });
}
socket.emit('reboot now');
}
}
});
setTimeout(function () { $('.noty_text').text('Reboot will start in 2...'); }, 1000);
setTimeout(function () { $('.noty_text').text('Reboot will start in 1...'); }, 2000);
}
return false;
});
// SocketIO namespace:
socket = io();
socket.on('add network results', function (msg) {
if (msg) {
socket.emit('get saved wifi networks');
} else {
addConnectionNoty = noty({
width: 200,
text: 'Failed to add a new Wi-Fi connection',
type: 'error',
dismissQueue: true,
timeout: 4000,
closeWith: ['click'],
layout: 'topRight'
});
}
});
socket.on('remove network results', function (msg) {
if (msg) {
socket.emit('get saved wifi networks');
} else {
removeConnetctionNoty = noty({
width: 200,
text: 'Failed to remove network',
type: 'error',
dismissQueue: true,
timeout: 4000,
closeWith: ['click'],
layout: 'topRight'
});
}
});
// say hello on connect
socket.on('connect', function () {
socket.emit('browser connected', {data: 'I\'m connected'});
if (typeof lostConnectionNoty !== 'undefined') {
lostConnectionNoty.close();
}
});
socket.on('reconnect', function () {
$('.disconnect_overlay').fadeOut();
$('body').css('position', 'relative');
$(window).resize();
});
socket.on('disconnect', function () {
if (preventLostConnectionNoty) {
return;
}
$('.disconnect_overlay').fadeIn();
$('body').css('position', 'fixed');
lostConnectionNoty = noty({
width: 200,
text: disconnect_msg,
type: 'error',
dismissQueue: true,
timeout: false,
closeWith: false,
layout: 'topRight',
callback: {
onClose: function () {
$('.disconnect_overlay').fadeOut();
$('body').css('position', 'relative');
noty({
width: 200,
text: 'Reach reconnected!',
type: 'success',
dismissQueue: true,
closeWith: false,
timeout: 3000,
layout: 'topRight'
});
}
}
});
});
socket.on('connect_error', function () {
console.clear();
console.warn('Lost connection with sockets');
});
socket.emit('get test results');
socket.on('reachview upgrade status', function (msg) {
if (!receiverPass) {
return;
}
$('.row_try_skip').css('display', 'none');
$('.skip_update_btn').css('display', 'none');
if (!$('.update_status i').hasClass('icon-spinner2')) {
$('.update_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
}
$('.available_version').css('display', 'none');
$('.update_reachview').addClass('disabled');
$('.coords_progress').css('display', 'block');
if (msg['active']) {
$('.current_version').text(msg['state'] + ' ' + msg['package'] + ' (' + msg['version'] + ')');
}
if (msg['state'] === 'Downloading') {
$('.coords_progress .progress-bar').removeClass('progress-bar-striped active');
$('.coords_progress .progress-bar').css('width', msg['percentage'] + '%');
if (parseInt(msg['percentage']) > 30) {
$('.coords_progress .progress-bar span').text(msg['percentage'] + '%');
} else {
$('.coords_progress .progress-bar span').text('');
}
} else if (msg['state'] === 'Installing') {
$('.coords_progress .progress-bar').css('width', '100%');
$('.coords_progress .progress-bar span').text('');
$('.coords_progress .progress-bar').addClass('progress-bar-striped active');
} else if (msg['state'] === 'Finished') {
$('.coords_progress').css('display', 'none');
currentVersion = false;
socket.emit('get reachview version');
$('.update_status').html('<i class="icon-checkmark3 text-success"></i>');
$('.update_reachview').css('display', 'none');
$('.available_version').css('display', 'none');
updatePass = true;
if (updatePass && receiverPass && timePass && wifiPass && testPass) {
$('.to_app').removeClass('disabled');
} else {
$('.to_app').addClass('disabled');
}
} else if (msg['state'] === 'Failed') {
$('.coords_progress').css('display', 'none');
$('.update_status').html('<i class="icon-cross2 text-danger-400"></i>');
$('.coords_progress .progress-bar').css('width', '0%');
$('.coords_progress .progress-bar span').text('');
if (msg['locked']) {
$('.current_version').html('Update system is used by another process. Please try again later.');
} else {
$('.current_version').html('Failed to perform update.');
}
$('.skip_update_btn').css('display', 'inline-block');
$('.update_reachview').css('display', 'block');
$('.update_reachview').removeClass('disabled');
$('.update_anchor.collapsed').click();
}
});
socket.on('wifi saved networks results', function (msg) {
var connectedNetwork = false;
var to_append = '';
msg.forEach(function (key, value) {
var ssid = (key['ssid'] !== '') ? key['ssid'] : 'Unknown';
if (key['is_connected']) {
to_append += '<li class="media connected_wi-fi_network">';
$('#current_network').text(ssid);
} else {
to_append += '<li class="media">';
}
to_append += '<a href="#" class="media-link"><div class="media-body">';
to_append += '<div class="media-heading text-semibold wi-fi_title">' + ssid + '</div>';
if (key['is_connected']) {
to_append += '<span class="text-muted">Connected (' + key['ip'] + ')</span>';
connectedNetwork = true;
} else {
to_append += '<span class="text-muted">Saved</span>';
}
to_append += '<input type="hidden" class="wi-fi_mac" value="' + key['mac_address'] + '"><input type="hidden" class="wi-fi_security" value="' + key['security'] + '"></div>';
if (key['is_connected']) {
to_append += '<div class="media-right media-middle text-nowrap"><span class="text-muted wi-fi_remove"><i class="icon-link text-size-base"></i></span></div>';
}
to_append += '</a></li>';
});
$('#added_wi-fi').html(to_append);
$('#connected_wi-fi').html('');
$('#connected_wi-fi').append($('.connected_wi-fi_network'));
if (connectedNetwork) {
$('.wifi_status').html('<i class="icon-checkmark3 text-success"></i>');
socket.emit('get time sync status');
$('.overlay.sync_overlay').fadeOut();
$('.sync_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
syncInterval = setInterval(function () { socket.emit('get time sync status'); }, 1000);
wifiPass = true;
} else {
$('.wifi_status').html('<i class="icon-circle-small text-danger-400"></i>');
$('.wi-fi_anchor.collapsed').click();
wifiPass = false;
}
});
socket.on('time sync status', function (msg) {
if (timePass) {
return;
}
if (msg['status']) {
$('.sync_status').html('<i class="icon-checkmark3 text-success"></i>');
$('.time_sync_warning').text('Time was synchronized!');
// Receiver update
availableReceiverVersion = false;
socket.emit('is receiver upgrade available');
$('.receiver_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
$('#receiver_upgrade_msg').text('Checking for receiver updates...');
$('.receiver_overlay').fadeOut();
// Reach update
// currentVersion = false;
// socket.emit('get reachview version');
// $('.current_version').text('Getting current version...');
// $('.overlay.update_overlay').fadeOut();
// $('.update_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
clearInterval(syncInterval);
timePass = true;
} else {
$('.time_sync_warning').text('Check your internet connection or connect antenna.');
timePass = false;
}
});
socket.on('receiver upgrade available', function (msg) {
if (availableReceiverVersion || receiverLocked) {
return;
}
if (msg['running']) {
$('#receiver_upgrade_msg').text('Updating receiver...');
$('.receiver_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
$('.update_receiver').css('display', 'inline-block');
$('.update_receiver').addClass('disabled');
$('.skip_receiver_update').css('display', 'none');
$('.receiver_progress').css('display', 'block');
$('.receiver_anchor.collapsed').click();
return;
}
if (msg['available']) {
$('.receiver_status').html('<i class="text-warning icon-circle-small"></i>');
$('#receiver_upgrade_msg').text('Receiver upgrade available');
$('.update_receiver').css('display', 'inline-block');
$('.skip_receiver_update').css('display', 'inline-block');
$('.receiver_anchor.collapsed').click();
} else {
$('.receiver_status').html('<i class="icon-checkmark3 text-success"></i>');
$('#receiver_upgrade_msg').text('No upgrades available for receiver');
$('.skip_receiver_update').trigger('click', [true]);
}
availableReceiverVersion = true;
});
$('.update_receiver').on('click', function () {
if (!$(this).hasClass('disabled')) {
receiverPass = false;
socket.emit('upgrade receiver');
$('#receiver_upgrade_msg').text('Updating receiver...');
$('.receiver_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
$('.update_receiver').addClass('disabled');
$('.skip_receiver_update').css('display', 'none');
$('.receiver_progress').css('display', 'block');
}
return false;
});
$('.skip_receiver_update, .receiver_skip_locked').on('click', function (event, fakeClick) {
if (!$(this).hasClass('disabled')) {
$(this).css('display', 'none');
$('.receiver_status').html('<i class="icon-checkmark3 text-success"></i>');
if (!fakeClick) {
$('.receiver_anchor:not(.collapsed)').click();
}
if (!availableVersion && !updatePass) {
currentVersion = false;
socket.emit('get reachview version');
$('.current_version').text('Getting current version...');
$('.overlay.update_overlay').fadeOut();
$('.update_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
}
receiverLocked = false;
receiverPass = true;
}
return false;
});
$('.receiver_try_again').on('click', function () {
receiverPass = false;
availableReceiverVersion = false;
socket.emit('is receiver upgrade available');
$('.receiver_status').html('<i class="icon-spinner2 spinner text-warning"></i>');
$('#receiver_upgrade_msg').text('Checking for receiver updates...');
$('.receiver_try_skip').css('display', 'none');
receiverLocked = false;
return false;
});
socket.on('receiver upgrade result', function (msg) {
if (receiverPass || receiverLocked) {
return;
}
if (msg) {
$('.update_receiver').css('display', 'none');
$('#receiver_upgrade_msg').text('Receiver updated successfully');
$('.receiver_status').html('<i class="icon-checkmark3 text-success"></i>');
$('.skip_receiver_update').trigger('click', [true]);
} else {
$('#receiver_upgrade_msg').text('Failed to perform receiver update');
$('.receiver_status').html('<i class="text-warning icon-circle-small"></i>');
$('.update_receiver').css('display', 'inline-block');
$('.skip_receiver_update').css('display', 'inline-block');
$('.receiver_anchor.collapsed').click();
$('.update_receiver').removeClass('disabled');
}
$('.receiver_progress').css('display', 'none');
});
socket.on('opkg update result', function (msg) {
if (opkgResult) {
return;
}
if (msg['state'] === 'Failed') {
$('.update_status').html('<i class="icon-cross2 text-danger-400"></i>');
$('.update_anchor.collapsed').click();
if (msg['locked']) {
$('.current_version').html('Update system is used by another process. Please try again later.');
} else {
$('.current_version').html('Update server unreachable. Check your Internet connection or try again later.');
}
$('.available_version').css('display', 'none');
$('.row_try_skip').css('display', 'block');
$('.update_reachview').css('display', 'none');
$('.update_anchor.collapsed').click();
}
else if (msg['state'] === 'Finished') {
opkgResult = true;
availableVersion = false;
socket.emit('is reachview upgrade available');
}
});
socket.on('update system locked', function () {
if (receiverPass) {
$('.update_anchor.collapsed').click();
$('.update_status').html('<i class="icon-cross2 text-danger-400"></i>');
$('.current_version').text('Update system is used by another process. Please try again later.');
$('.available_version').css('display', 'none');
$('.row_try_skip').css('display', 'block');
} else {
$('.receiver_anchor.collapsed').click();
$('.receiver_status').html('<i class="icon-cross2 text-danger-400"></i>');
$('#receiver_upgrade_msg').text('Update system is used by another process. Please try again later.');
$('.update_receiver').css('display', 'none');
$('.skip_receiver_update').css('display', 'none');
$('.receiver_try_skip').css('display', 'block');
receiverLocked = true;
}
});
socket.on('current reachview version', function (msg) {
if (currentVersion || !receiverPass) {
return;
}
var version = (msg['version'] != null)
? 'Current ReachView version: ' + msg['version']
: 'Could not retrieve ReachView version.';
$('.current_version').text(version);
currentVersion = true;
opkgResult = false;
socket.emit('update');
$('.available_version').css('display', 'block');
$('.available_version').text('Checking for updates...');
});
socket.on('reachview upgrade version', function (msg) {
if (availableVersion || !receiverPass) {
return;
}
if (!msg['upgrade available']) {
$('.update_status').html('<i class="icon-checkmark3 text-success"></i>');
$('.update_reachview').css('display', 'none');
$('.available_version').css('display', 'none');
updatePass = true;
if (updatePass && receiverPass && timePass && wifiPass && testPass) {
$('.to_app').removeClass('disabled');
} else {
$('.to_app').addClass('disabled');
}
} else {
$('.available_version').css('display', 'block');
$('.available_version').text('Available version: ' + msg['available version']);
$('.update_status').html('<i class="text-warning icon-circle-small"></i>');
$('.update_reachview').css('display', 'inline-block');
$('.update_anchor.collapsed').click();
}
availableVersion = true;
});
socket.on('test results', function (msg) {
$('.tests_status').css('display', 'none');
device = msg['device'];
if (msg['device'] === 'Reach' || msg['device'] === 'ReachM+') {
$('.ltc_test, .stc_test, .lora_test').parent().css('display', 'none');
}
if (!msg['ltc']) {
$('.tests_status').html('<i class="icon-cross2 text-danger-400"></i>');
$('.test_warning').text('Test 3 failed');
$('.test_warning').slideDown();
testPass = true;
}
if (!msg['stc']) {
$('.tests_status').html('<i class="icon-cross2 text-danger-400"></i>');
$('.test_warning').text('Test 4 failed');
$('.test_warning').slideDown();
testPass = true;
}
if (!msg['lora']) {
$('.tests_status').html('<i class="icon-cross2 text-danger-400"></i>');
$('.test_warning').text('Test 5 failed');
$('.test_warning').slideDown();
testPass = true;
}
if (!msg['mpu']) {
$('.tests_status').html('<i class="icon-cross2 text-danger-400"></i>');
$('.test_warning').text('Test 1 failed');
$('.test_warning').slideDown();
testPass = true;
}
if (!msg['u-blox']) {
$('.tests_status').html('<i class="icon-cross2 text-danger-400"></i>');
$('.test_warning').text('Test 2 failed');
$('.test_warning').slideDown();
testPass = false;
}
if (msg['device'] === 'Reach' || msg['device'] === 'ReachM+') {
if (msg['u-blox'] && msg['mpu']) {
$('.tests_status').html('<i class="icon-checkmark3 text-success"></i>');
testPass = true;
}
} else {
if (msg['u-blox'] && msg['mpu'] && msg['lora'] && msg['ltc'] && msg['stc']) {
$('.tests_status').html('<i class="icon-checkmark3 text-success"></i>');
testPass = true;
}
}
$('.tests_status').fadeIn();
if (msg['mpu']) {
$('.mpu_test').html('<i class="icon-checkmark3 text-success"></i>');
} else {
$('.mpu_test').html('<i class="icon-cross2 text-danger-400"></i>');
}
if (msg['u-blox']) {
$('.u-blox_test').html('<i class="icon-checkmark3 text-success"></i>');
} else {
$('.u-blox_test').html('<i class="icon-cross2 text-danger-400"></i>');
}
if (msg['lora']) {
$('.lora_test').html('<i class="icon-checkmark3 text-success"></i>');
} else {
$('.lora_test').html('<i class="icon-cross2 text-danger-400"></i>');
}
if (msg['stc']) {
$('.stc_test').html('<i class="icon-checkmark3 text-success"></i>');
} else {
$('.stc_test').html('<i class="icon-cross2 text-danger-400"></i>');
}
if (msg['ltc']) {
$('.ltc_test').html('<i class="icon-checkmark3 text-success"></i>');
} else {
$('.ltc_test').html('<i class="icon-cross2 text-danger-400"></i>');
}
socket.emit('get saved wifi networks');
});
});
});

View File

@ -1,4 +1,5 @@
**/*.go
!**/*_test.go
modd.conf
.env
Makefile {

View File

@ -0,0 +1,26 @@
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
}

99
reach/client.go Normal file
View File

@ -0,0 +1,99 @@
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 {
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 {
var err error
var wg sync.WaitGroup
wg.Add(1)
transport := &transport.WebsocketTransport{
PingInterval: c.opts.PingInterval,
PingTimeout: c.opts.PingTimeout,
ReceiveTimeout: c.opts.ReceiveTimeout,
SendTimeout: c.opts.SendTimeout,
BufferSize: c.opts.BufferSize,
}
c.logf("connecting to '%s'", c.opts.Endpoint)
conn, err := gosocketio.Dial(c.opts.Endpoint, transport)
if err != nil {
return errors.Wrap(err, "error while connecting to endpoint")
}
c.conn = conn
err = conn.On(gosocketio.OnConnection, func(h *gosocketio.Channel) {
c.logf("connected with sid '%s'", h.Id())
err = c.sendBrowserConnected()
wg.Done()
})
if err != nil {
return errors.Wrap(err, "error while attaching to connection event")
}
err = conn.On(gosocketio.OnError, func(h *gosocketio.Channel) {
c.logf("error")
err = errors.Errorf("an unknown error occured")
c.conn = nil
wg.Done()
})
if err != nil {
return errors.Wrap(err, "error while attaching to error event")
}
wg.Wait()
conn.On(gosocketio.OnError, nil)
return err
}
// Close closes the current connection to the ReachView endpoint
func (c *Client) Close() {
if c.conn == nil {
return
}
c.conn.Close()
c.conn = nil
return
}
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 {
options := DefaultOptions()
for _, o := range opts {
o(options)
}
return &Client{
opts: options,
}
}

27
reach/client_test.go Normal file
View File

@ -0,0 +1,27 @@
package reach
import (
"testing"
)
func TestClient(t *testing.T) {
client := NewClient(
WithStandardLogger(),
)
if err := client.Connect(); err != nil {
t.Fatal(err)
}
results, err := client.TestResults()
if err != nil {
t.Error(err)
}
if g, e := results.Device, "ReachRS"; g != e {
t.Errorf("results.Device: got '%s', expected '%s'", g, e)
}
defer client.Close()
}

91
reach/option.go Normal file
View File

@ -0,0 +1,91 @@
package reach
import (
"log"
"os"
"time"
"forge.cadoles.com/Pyxis/golang-socketio"
)
type Logger interface {
Printf(format string, args ...interface{})
}
// Options are ReachRS client configuration options
type Options struct {
Endpoint string
PingInterval time.Duration
PingTimeout time.Duration
ReceiveTimeout time.Duration
SendTimeout time.Duration
BufferSize int
Logger Logger
}
type OptionFunc func(opts *Options)
func WithEndpoint(host string, port int) OptionFunc {
return func(opts *Options) {
opts.Endpoint = gosocketio.GetUrl(host, port, false)
}
}
func WithPingInterval(interval time.Duration) OptionFunc {
return func(opts *Options) {
opts.PingInterval = interval
}
}
func WithPingTimeout(timeout time.Duration) OptionFunc {
return func(opts *Options) {
opts.PingTimeout = timeout
}
}
func WithReceiveTimeout(timeout time.Duration) OptionFunc {
return func(opts *Options) {
opts.ReceiveTimeout = timeout
}
}
func WithSendTimeout(timeout time.Duration) OptionFunc {
return func(opts *Options) {
opts.SendTimeout = timeout
}
}
func WithBufferSize(size int) OptionFunc {
return func(opts *Options) {
opts.BufferSize = size
}
}
func WithLogger(logger Logger) OptionFunc {
return func(opts *Options) {
opts.Logger = logger
}
}
func WithStandardLogger() OptionFunc {
return func(opts *Options) {
logger := log.New(os.Stdout, "[reachrs] ", log.LstdFlags)
opts.Logger = logger
}
}
func DefaultOptions() *Options {
opts := &Options{}
defaults := []OptionFunc{
WithEndpoint("192.168.42.1", 80),
WithPingInterval(30 * time.Second),
WithPingTimeout(60 * time.Second),
WithReceiveTimeout(60 * time.Second),
WithSendTimeout(60 * time.Second),
WithBufferSize(1024 * 32),
}
for _, o := range defaults {
o(opts)
}
return opts
}

37
reach/probe.go Normal file
View File

@ -0,0 +1,37 @@
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
}

51
reach/test_results.go Normal file
View File

@ -0,0 +1,51 @@
package reach
import (
"sync"
"forge.cadoles.com/Pyxis/golang-socketio"
"github.com/pkg/errors"
)
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"
)
// TestResults are the ReachRS module's test results
type TestResults struct {
UBlox bool `json:"u-blox"`
STC bool `json:"stc"`
MPU bool `json:"mpu"`
Device string `json:"device"`
Lora bool `json:"lora"`
}
// TestResults returns the ReachRS module tests results
func (c *Client) TestResults() (*TestResults, error) {
var err error
var results *TestResults
var wg sync.WaitGroup
wg.Add(1)
c.conn.On(EventTestResults, func(h *gosocketio.Channel, res *TestResults) {
results = res
c.conn.On(EventTestResults, nil)
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)
}
c.logf("'%s' event sent", EventGetTestResults)
wg.Wait()
return results, err
}