update websocket + handle settings in session
This commit is contained in:
parent
a198abb8d0
commit
832c30fa26
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 = [
|
||||||
'class': 'login',
|
V.h('li', {
|
||||||
'onclick': this.logout.bind(this)
|
'class': 'login',
|
||||||
}, 'Logout');
|
},[
|
||||||
|
V.h('a', {
|
||||||
|
'onclick': this.logout.bind(this)
|
||||||
|
}, '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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue