update websocket + handle settings in session

This commit is contained in:
Martin/Geno 2018-08-24 23:34:02 +02:00
parent a198abb8d0
commit 832c30fa26
No known key found for this signature in database
GPG Key ID: 9D7D3C6BFF600C6A
12 changed files with 147 additions and 64 deletions

View File

@ -2,7 +2,6 @@ package runtime
import ( import (
"fmt" "fmt"
"strings"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -66,12 +65,13 @@ func (n *Node) SSHUpdate(sshmgmt *ssh.Manager) bool {
runWifi = true runWifi = true
} }
if n.Wireless.Channel24 != n.WirelessRespondd.Channel24 { if n.Wireless.Channel24 != n.WirelessRespondd.Channel24 {
//ubus call hostapd.%s switch_chan '{"freq":%d}'
ssh.Execute(n.Address, client, fmt.Sprintf(` ssh.Execute(n.Address, client, fmt.Sprintf(`
ubus call hostapd.%s switch_chan '{"freq":%d}'
uci set wireless.%s.channel='%d'; uci set wireless.%s.channel='%d';
uci commit wireless;`, uci commit wireless;`,
strings.Replace(radio, "radio", "client", 1), ch.Frequency, //strings.Replace(radio, "radio", "client", 1), ch.Frequency,
radio, n.Wireless.Channel24)) radio, n.Wireless.Channel24))
runWifi = true
} }
} }
@ -95,12 +95,13 @@ func (n *Node) SSHUpdate(sshmgmt *ssh.Manager) bool {
runWifi = true runWifi = true
} }
if n.Wireless.Channel5 != n.WirelessRespondd.Channel5 { if n.Wireless.Channel5 != n.WirelessRespondd.Channel5 {
//ubus call hostapd.%s switch_chan '{"freq":%d}'
ssh.Execute(n.Address, client, fmt.Sprintf(` ssh.Execute(n.Address, client, fmt.Sprintf(`
ubus call hostapd.%s switch_chan '{"freq":%d}'
uci set wireless.%s.channel='%d'; uci set wireless.%s.channel='%d';
uci commit wireless;`, uci commit wireless;`,
strings.Replace(radio, "radio", "client", 1), ch.Frequency, //strings.Replace(radio, "radio", "client", 1), ch.Frequency,
radio, n.Wireless.Channel5)) radio, n.Wireless.Channel5))
runWifi = true
} }
} }
return true return true

View File

@ -21,10 +21,15 @@ nav {
list-style-type: none; list-style-type: none;
} }
ul > li { ul > li,
ul li.right {
float:left; float:left;
display: inline-block; display: inline-block;
&.right {
float: right;
}
a, a,
span { span {
display: inline-block; display: inline-block;

View File

@ -31,6 +31,7 @@ export class MenuView extends View {
login() { login() {
socket.sendjson({'subject': 'login', 'body': this._loginInput}, (msg) => { socket.sendjson({'subject': 'login', 'body': this._loginInput}, (msg) => {
if (msg.body) { if (msg.body) {
store.settings = msg.body;
store.isLogin = true; store.isLogin = true;
render(); render();
}else { }else {
@ -60,7 +61,7 @@ export class MenuView extends View {
render () { render () {
const socketStatus = socket.getStatus(); const socketStatus = socket.getStatus();
let statusClass = 'status ', let statusClass = 'status ',
vLogin = V.h('li', { vLogin = [V.h('li', {
'class': 'login', 'class': 'login',
}, [ }, [
V.h('input', { V.h('input', {
@ -70,15 +71,24 @@ export class MenuView extends View {
}), }),
V.h('a', { V.h('a', {
'onclick': this.login.bind(this) 'onclick': this.login.bind(this)
}, 'Login' }, 'Login')
) ])];
]);
if (store.isLogin) { if (store.isLogin) {
vLogin = V.h('li', { vLogin = [
V.h('li', {
'class': 'login', 'class': 'login',
},[
V.h('a', {
'onclick': this.logout.bind(this) 'onclick': this.logout.bind(this)
}, 'Logout'); }, 'Logout')
]),
V.h('li', {
'class':'right item-3'
},[V.h('a', {
'href': '#/settings'
}, 'Settings')])
];
} }
if (socketStatus !== 1) { if (socketStatus !== 1) {
@ -93,6 +103,6 @@ export class MenuView extends View {
V.render(this.vMenu, this.vMenu = V.h('span',{},[V.h('li', { V.render(this.vMenu, this.vMenu = V.h('span',{},[V.h('li', {
'class': statusClass, 'class': statusClass,
'onclick': () => location.reload(true) 'onclick': () => location.reload(true)
}), vLogin]), this.menuList); })].concat(vLogin)), this.menuList);
} }
} }

View File

@ -12,6 +12,7 @@ import config from './config';
import {ListView} from './view/list'; import {ListView} from './view/list';
import {MapView} from './view/map'; import {MapView} from './view/map';
import {StatisticsView} from './view/statistics'; import {StatisticsView} from './view/statistics';
import {SettingsView} from './view/settings';
import {NodeView} from './view/node'; import {NodeView} from './view/node';
@ -20,6 +21,7 @@ window.onload = () => {
const listView = new ListView(); const listView = new ListView();
const mapView = new MapView(); const mapView = new MapView();
const statisticsView = new StatisticsView(); const statisticsView = new StatisticsView();
const settingsView = new SettingsView();
const nodeView = new NodeView(); const nodeView = new NodeView();
@ -27,6 +29,7 @@ window.onload = () => {
'/list': () => gui.setView(listView), '/list': () => gui.setView(listView),
'/map': () => gui.setView(mapView), '/map': () => gui.setView(mapView),
'/statistics': () => gui.setView(statisticsView), '/statistics': () => gui.setView(statisticsView),
'/settings': () => gui.setView(settingsView),
'/n/:nodeID': { '/n/:nodeID': {
'as': 'node', 'as': 'node',
// eslint-disable-next-line func-name-matching // eslint-disable-next-line func-name-matching

View File

@ -178,6 +178,7 @@ export function sendnode(node, callback) {
setEvent('auth_status', (msg) => { setEvent('auth_status', (msg) => {
if (msg.body) { if (msg.body) {
store.settings = msg.body
store.isLogin = true; store.isLogin = true;
notify.send({ notify.send({

View File

@ -1,7 +1,6 @@
import config from './config'; import config from './config';
const current = {}, const list = {};
list = {};
// Returns the node with specified id (or null if node doesn't exist). // Returns the node with specified id (or null if node doesn't exist).
export function getNode (nodeid) { export function getNode (nodeid) {
@ -30,7 +29,6 @@ export function createNode (nodeid) {
}; };
// Overwrites the values for the specified node (identified by its node_id) with new values. // Overwrites the values for the specified node (identified by its node_id) with new values.
// If system==false, the special "current" node will be modified instead.
export function updateNode (node) { export function updateNode (node) {
list[node.node_id] = node; list[node.node_id] = node;
}; };

View File

@ -107,6 +107,7 @@ export class ListView extends View {
V.h('td', {}, V.h('input',{ V.h('td', {}, V.h('input',{
'value': this._hostname || node.hostname, 'value': this._hostname || node.hostname,
'oninput':(e) => { 'oninput':(e) => {
this._node_id = node.node_id;
this._hostname = e.target.value; this._hostname = e.target.value;
}, },
'onfocusout':(e) => { 'onfocusout':(e) => {
@ -167,6 +168,7 @@ export class ListView extends View {
'max': 23, 'max': 23,
'value': this._txpower24 || node.wireless.txpower24, 'value': this._txpower24 || node.wireless.txpower24,
'oninput':(e) => { 'oninput':(e) => {
this._node_id = node.node_id;
this._txpower24 = e.target.value; this._txpower24 = e.target.value;
}, },
'onfocusout':(e) => { 'onfocusout':(e) => {
@ -188,6 +190,7 @@ export class ListView extends View {
'max': 23, 'max': 23,
'value': this._txpower5 || node.wireless.txpower5, 'value': this._txpower5 || node.wireless.txpower5,
'oninput':(e) => { 'oninput':(e) => {
this._node_id = node.node_id;
this._txpower5 = e.target.value; this._txpower5 = e.target.value;
}, },
'onfocusout':(e) => { 'onfocusout':(e) => {

View File

@ -0,0 +1,42 @@
import * as domlib from '../domlib';
import * as gui from '../gui';
import * as socket from '../socket';
import * as store from '../store';
import View from '../view';
export class SettingsView extends View {
constructor () {
super();
domlib.newAt(this.el, 'h1').innerHTML = 'Settings';
this.ping = domlib.newAt(this.el, 'input',{
'type': 'checkbox',
'id': 'settings_ping',
'onchange': this.updateSettings('ping').bind(this),
});
domlib.newAt(this.el, 'label', {'for': 'settings_ping'},'Ping');
}
updateSettings (key) {
return function(ev){
const copySettings = Object.assign({}, store.settings);
if (ev.target.type === 'checkbox') {
copySettings[key] = ev.target.checked;
socket.sendjson({'subject': 'settings','body': copySettings}, (msg) => {
if (msg.body) {
store.settings = copySettings;
}
});
}
}
}
render () {
if(!store.settings){
return
}
this.ping.checked = store.settings.ping || false;
}
}

View File

@ -1,27 +0,0 @@
package websocket
import (
log "github.com/sirupsen/logrus"
"dev.sum7.eu/genofire/golang-lib/websocket"
)
type WebsocketHandlerFunc func(*log.Entry, *websocket.Message) error
func (ws *WebsocketServer) MessageHandler() {
for msg := range ws.inputMSG {
logger := log.WithFields(log.Fields{
"session": msg.Session,
"id": msg.ID,
"subject": msg.Subject,
})
if handler, ok := ws.handlers[msg.Subject]; ok {
err := handler(logger, msg)
if err != nil {
logger.Errorf("websocket message '%s' cound not handle: %s", msg.Subject, err)
}
} else {
logger.Warnf("websocket message '%s' cound not handle", msg.Subject)
}
}
}

View File

@ -4,15 +4,16 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/mitchellh/mapstructure"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"dev.sum7.eu/genofire/golang-lib/websocket" "dev.sum7.eu/genofire/golang-lib/websocket"
) )
type Session struct { type Session struct {
SessionID uuid.UUID `json:"-" gorm:"primary_key"` SessionID uuid.UUID `json:"-" gorm:"primary_key" mapstructure:"-"`
Lastseen *time.Time `json:"-"` Lastseen *time.Time `json:"-" mapstructure:"-"`
Ping bool `json:"ping"` Ping bool `json:"ping" mapstructure:"ping"`
} }
func (ws *WebsocketServer) IsLoggedIn(msg *websocket.Message) (*Session, bool) { func (ws *WebsocketServer) IsLoggedIn(msg *websocket.Message) (*Session, bool) {
@ -35,7 +36,10 @@ func (ws *WebsocketServer) loginHandler(logger *log.Entry, msg *websocket.Messag
} }
err := ws.db.First(&session) err := ws.db.First(&session)
if err.Error == nil { if err.Error == nil {
msg.Answer(msg.Subject, true) msg.Answer(msg.Subject, session)
now := time.Now()
session.Lastseen = &now
ws.db.Save(&session)
logger.Warn("already loggedIn") logger.Warn("already loggedIn")
return nil return nil
} }
@ -73,6 +77,31 @@ func (ws *WebsocketServer) authStatusHandler(logger *log.Entry, msg *websocket.M
} }
return nil return nil
} }
func (ws *WebsocketServer) settingsHandler(logger *log.Entry, msg *websocket.Message) error {
session, ok := ws.IsLoggedIn(msg)
if !ok {
msg.Answer(msg.Subject, false)
logger.Warn("logout without login")
return nil
}
var setting Session
if err := mapstructure.Decode(msg.Body, &setting); err != nil {
msg.Answer(msg.Subject, false)
logger.Warnf("not able to decode data: %s", err)
return nil
}
setting.SessionID = session.SessionID
setting.Lastseen = session.Lastseen
err := ws.db.Save(&setting)
logger.Debug("done")
msg.Answer(msg.Subject, err.Error == nil)
return err.Error
}
func (ws *WebsocketServer) logoutHandler(logger *log.Entry, msg *websocket.Message) error { func (ws *WebsocketServer) logoutHandler(logger *log.Entry, msg *websocket.Message) error {
session := Session{ session := Session{
SessionID: msg.Session, SessionID: msg.Session,

View File

@ -5,6 +5,7 @@ const (
MessageTypeLogin = "login" MessageTypeLogin = "login"
MessageTypeAuthStatus = "auth_status" MessageTypeAuthStatus = "auth_status"
MessageTypeSettings = "settings"
MessageTypeLogout = "logout" MessageTypeLogout = "logout"
MessageTypeChannelsWifi24 = "channels_wifi24" MessageTypeChannelsWifi24 = "channels_wifi24"

View File

@ -1,11 +1,11 @@
package websocket package websocket
import ( import (
"net/http"
"time" "time"
wsLib "dev.sum7.eu/genofire/golang-lib/websocket" wsLib "dev.sum7.eu/genofire/golang-lib/websocket"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
log "github.com/sirupsen/logrus"
"github.com/FreifunkBremen/yanic/runtime" "github.com/FreifunkBremen/yanic/runtime"
) )
@ -16,10 +16,21 @@ type WebsocketServer struct {
blacklistFor time.Duration blacklistFor time.Duration
secret string secret string
ipPrefix string ipPrefix string
ws *wsLib.WebsocketHandlerService
}
inputMSG chan *wsLib.Message func websocketHandlerFunc(f func(logger *log.Entry, msg *wsLib.Message) error) wsLib.MessageHandleFunc {
ws *wsLib.Server return func(msg *wsLib.Message) {
handlers map[string]WebsocketHandlerFunc logger := log.WithFields(log.Fields{
"session": msg.Session,
"id": msg.ID,
"subject": msg.Subject,
})
err := f(logger, msg)
if err != nil {
logger.Warnf("websocket message '%s' cound not handle: %s", msg.Subject, err)
}
}
} }
func NewWebsocketServer(secret string, ipPrefix string, db *gorm.DB, blacklistFor time.Duration, nodes *runtime.Nodes) *WebsocketServer { func NewWebsocketServer(secret string, ipPrefix string, db *gorm.DB, blacklistFor time.Duration, nodes *runtime.Nodes) *WebsocketServer {
@ -27,27 +38,33 @@ func NewWebsocketServer(secret string, ipPrefix string, db *gorm.DB, blacklistFo
nodes: nodes, nodes: nodes,
db: db, db: db,
blacklistFor: blacklistFor, blacklistFor: blacklistFor,
handlers: make(map[string]WebsocketHandlerFunc),
inputMSG: make(chan *wsLib.Message),
secret: secret, secret: secret,
ipPrefix: ipPrefix, ipPrefix: ipPrefix,
} }
ownWS.ws = wsLib.NewServer(ownWS.inputMSG, wsLib.NewSessionManager()) ownWS.ws = wsLib.NewWebsocketHandlerService()
// Register Handlers // Register Handlers
ownWS.handlers[MessageTypeConnect] = ownWS.connectHandler ownWS.ws.SetHandler(MessageTypeConnect, websocketHandlerFunc(ownWS.connectHandler))
ownWS.handlers[MessageTypeLogin] = ownWS.loginHandler ownWS.ws.SetHandler(MessageTypeLogin, websocketHandlerFunc(ownWS.loginHandler))
ownWS.handlers[MessageTypeAuthStatus] = ownWS.authStatusHandler ownWS.ws.SetHandler(MessageTypeAuthStatus, websocketHandlerFunc(ownWS.authStatusHandler))
ownWS.handlers[MessageTypeLogout] = ownWS.logoutHandler ownWS.ws.SetHandler(MessageTypeSettings, websocketHandlerFunc(ownWS.settingsHandler))
ownWS.ws.SetHandler(MessageTypeLogout, websocketHandlerFunc(ownWS.logoutHandler))
ownWS.handlers[MessageTypeNode] = ownWS.nodeHandler ownWS.ws.SetHandler(MessageTypeNode, websocketHandlerFunc(ownWS.nodeHandler))
http.HandleFunc("/ws", ownWS.ws.Handler) ownWS.ws.FallbackHandler = func(msg *wsLib.Message) {
go ownWS.MessageHandler() log.WithFields(log.Fields{
"session": msg.Session,
"id": msg.ID,
"subject": msg.Subject,
}).Warnf("websocket message '%s' cound not handle", msg.Subject)
}
ownWS.ws.Listen("/ws")
return &ownWS return &ownWS
} }
func (ws *WebsocketServer) Close() { func (ws *WebsocketServer) Close() {
close(ws.inputMSG) ws.ws.Close()
} }