[TASK] add functions to listView + allow unlearn nodes
This commit is contained in:
parent
f48aaf3236
commit
f3e9b6c0db
|
@ -49,7 +49,7 @@ func main() {
|
|||
|
||||
if config.Yanic.Enable {
|
||||
yanicDialer := yanic.Dial(config.Yanic.Type, config.Yanic.Address)
|
||||
yanicDialer.NodeHandler = nodes.AddNode
|
||||
yanicDialer.NodeHandler = nodes.LearnNode
|
||||
yanicDialer.GlobalsHandler = func(data *runtimeYanic.GlobalStats) {
|
||||
stats = data
|
||||
websocket.NotifyStats(data)
|
||||
|
|
|
@ -26,7 +26,7 @@ type Node struct {
|
|||
Location data.Location `json:"location"`
|
||||
Wireless data.Wireless `json:"wireless"`
|
||||
Owner string `json:"owner"`
|
||||
Address net.IP `json:"address"`
|
||||
Address net.IP `json:"-"`
|
||||
Stats struct {
|
||||
Wireless data.WirelessStatistics `json:"wireless"`
|
||||
Clients data.Clients `json:"clients"`
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
type Nodes struct {
|
||||
List map[string]*Node `json:"nodes"`
|
||||
ToUpdate map[string]*Node
|
||||
Current map[string]*Node `json:"-"`
|
||||
ssh *ssh.Manager
|
||||
statePath string
|
||||
iface string
|
||||
|
@ -25,7 +25,7 @@ type Nodes struct {
|
|||
func NewNodes(path string, iface string, mgmt *ssh.Manager) *Nodes {
|
||||
nodes := &Nodes{
|
||||
List: make(map[string]*Node),
|
||||
ToUpdate: make(map[string]*Node),
|
||||
Current: make(map[string]*Node),
|
||||
ssh: mgmt,
|
||||
statePath: path,
|
||||
iface: iface,
|
||||
|
@ -34,33 +34,25 @@ func NewNodes(path string, iface string, mgmt *ssh.Manager) *Nodes {
|
|||
return nodes
|
||||
}
|
||||
|
||||
func (nodes *Nodes) AddNode(n *yanic.Node) {
|
||||
func (nodes *Nodes) LearnNode(n *yanic.Node) {
|
||||
node := NewNode(n)
|
||||
if node == nil {
|
||||
return
|
||||
}
|
||||
node.Lastseen = jsontime.Now()
|
||||
logger := log.Log.WithField("method", "AddNode").WithField("node_id", node.NodeID)
|
||||
logger := log.Log.WithField("method", "LearnNode").WithField("node_id", node.NodeID)
|
||||
nodes.Lock()
|
||||
nodes.Unlock()
|
||||
if cNode := nodes.List[node.NodeID]; cNode != nil {
|
||||
cNode.Lastseen = jsontime.Now()
|
||||
cNode.Stats = node.Stats
|
||||
if uNode, ok := nodes.ToUpdate[node.NodeID]; ok {
|
||||
uNode.Lastseen = jsontime.Now()
|
||||
uNode.Stats = node.Stats
|
||||
if nodes.List[node.NodeID].IsEqual(node) {
|
||||
delete(nodes.ToUpdate, node.NodeID)
|
||||
nodes.List[node.NodeID] = node
|
||||
nodes.notify(node, true)
|
||||
} else {
|
||||
nodes.notify(uNode, false)
|
||||
}
|
||||
} else {
|
||||
nodes.List[node.NodeID] = node
|
||||
nodes.notify(node, true)
|
||||
}
|
||||
logger.Debugf("know already these node")
|
||||
defer nodes.Unlock()
|
||||
if lNode := nodes.List[node.NodeID]; lNode != nil {
|
||||
lNode.Lastseen = jsontime.Now()
|
||||
lNode.Stats = node.Stats
|
||||
} else {
|
||||
nodes.List[node.NodeID] = node
|
||||
nodes.notify(node, true)
|
||||
}
|
||||
if _, ok := nodes.Current[node.NodeID]; ok {
|
||||
nodes.Current[node.NodeID] = node
|
||||
nodes.notify(node, false)
|
||||
return
|
||||
}
|
||||
// session := nodes.ssh.ConnectTo(node.Address)
|
||||
|
@ -72,16 +64,16 @@ func (nodes *Nodes) AddNode(n *yanic.Node) {
|
|||
uptime := ssh.SSHResultToString(result)
|
||||
logger.Infof("new node with uptime: %s", uptime)
|
||||
|
||||
nodes.List[node.NodeID] = node
|
||||
nodes.notify(node, true)
|
||||
nodes.Current[node.NodeID] = node
|
||||
nodes.notify(node, false)
|
||||
}
|
||||
|
||||
func (nodes *Nodes) AddNotify(f func(*Node, bool)) {
|
||||
nodes.notifyFunc = append(nodes.notifyFunc, f)
|
||||
}
|
||||
func (nodes *Nodes) notify(node *Node, real bool) {
|
||||
func (nodes *Nodes) notify(node *Node, system bool) {
|
||||
for _, f := range nodes.notifyFunc {
|
||||
f(node, real)
|
||||
f(node, system)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,16 +87,16 @@ func (nodes *Nodes) UpdateNode(node *Node) {
|
|||
if n, ok := nodes.List[node.NodeID]; ok {
|
||||
go node.SSHUpdate(nodes.ssh, nodes.iface, n)
|
||||
}
|
||||
nodes.ToUpdate[node.NodeID] = node
|
||||
nodes.notify(node, false)
|
||||
nodes.List[node.NodeID] = node
|
||||
nodes.notify(node, true)
|
||||
}
|
||||
|
||||
func (nodes *Nodes) Updater() {
|
||||
nodes.Lock()
|
||||
defer nodes.Unlock()
|
||||
for nodeid := range nodes.ToUpdate {
|
||||
if node := nodes.List[nodeid]; node != nil {
|
||||
go node.SSHSet(nodes.ssh, nodes.iface)
|
||||
for nodeid, node := range nodes.List {
|
||||
if n, ok := nodes.Current[nodeid]; ok {
|
||||
go node.SSHUpdate(nodes.ssh, nodes.iface, n)
|
||||
}
|
||||
}
|
||||
log.Log.Debug("updater per ssh runs")
|
||||
|
|
|
@ -144,12 +144,13 @@ table.nodes tbody tr:nth-child(odd) {
|
|||
table.nodes tbody tr:hover {
|
||||
background: #ccc;
|
||||
}
|
||||
table.nodes tbody tr.offline{
|
||||
background: #ffb400;
|
||||
}
|
||||
table.nodes tbody tr.offline,
|
||||
table.nodes tbody tr.offline:hover{
|
||||
background: #dc0067;
|
||||
}
|
||||
table.nodes tbody tr.unseen{
|
||||
background: #009ee0;
|
||||
}
|
||||
|
||||
table tr.line td,table tr.line th {
|
||||
border-bottom: 1px solid #ffb400;
|
||||
|
@ -178,3 +179,14 @@ a {
|
|||
color: #dc0067;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
input[readonly] {
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0px;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
line-height: 1.3;
|
||||
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
const config = {
|
||||
'title': 'FreifunkManager - Breminale',
|
||||
'backend': `ws://${location.host}/websocket`,
|
||||
'node': {
|
||||
// Minuten till is shown as offline
|
||||
'offline': 5
|
||||
},
|
||||
'map': {
|
||||
'view': {
|
||||
'bound': [53.07103, 8.81624],
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* exported guiList */
|
||||
/* global domlib,store,router */
|
||||
/* global config,domlib,store,router,socket */
|
||||
/* eslint max-lines: [off] */
|
||||
|
||||
const guiList = {};
|
||||
|
||||
|
@ -14,7 +15,8 @@ const guiList = {};
|
|||
sortReverse = false,
|
||||
sortIndex = null,
|
||||
hostnameFilter = null,
|
||||
nodeidFilter = null;
|
||||
nodeidFilter = null,
|
||||
editing = false;
|
||||
|
||||
// eslint-disable-next-line id-length
|
||||
function sort (a, b) {
|
||||
|
@ -69,52 +71,160 @@ const guiList = {};
|
|||
lastseen = domlib.newAt(tr, 'td'),
|
||||
nodeID = domlib.newAt(tr, 'td'),
|
||||
hostname = domlib.newAt(tr, 'td'),
|
||||
hostnameInput = domlib.newAt(hostname, 'input'),
|
||||
freq = domlib.newAt(tr, 'td'),
|
||||
curchannel = domlib.newAt(tr, 'td'),
|
||||
channel = domlib.newAt(tr, 'td'),
|
||||
channel24Input = domlib.newAt(domlib.newAt(channel, 'span'), 'input'),
|
||||
channel5Input = domlib.newAt(domlib.newAt(channel, 'span'), 'input'),
|
||||
curpower = domlib.newAt(tr, 'td'),
|
||||
power = domlib.newAt(tr, 'td'),
|
||||
power24Input = domlib.newAt(domlib.newAt(power, 'span'), 'input'),
|
||||
power5Input = domlib.newAt(domlib.newAt(power, 'span'), 'input'),
|
||||
client = domlib.newAt(tr, 'td'),
|
||||
chanUtil = domlib.newAt(tr, 'td'),
|
||||
option = domlib.newAt(tr, 'td'),
|
||||
edit = domlib.newAt(option, 'div');
|
||||
|
||||
startdate.setMinutes(startdate.getMinutes() - 1);
|
||||
startdate.setMinutes(startdate.getMinutes() - config.node.offline);
|
||||
if (new Date(node.lastseen) < startdate) {
|
||||
tr.classList.add('offline');
|
||||
}
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
if (!node._wireless) {
|
||||
tr.classList.add('unseen');
|
||||
}
|
||||
|
||||
lastseen.innerHTML = moment(node.lastseen).fromNow(true);
|
||||
|
||||
nodeID.innerHTML = node.node_id;
|
||||
|
||||
hostname.innerHTML = node.hostname;
|
||||
hostnameInput.value = node.hostname;
|
||||
hostnameInput.readOnly = true;
|
||||
hostnameInput.setAttribute('placeholder', 'Hostname');
|
||||
hostnameInput.addEventListener('dblclick', () => {
|
||||
editing = true;
|
||||
hostnameInput.readOnly = false;
|
||||
});
|
||||
hostnameInput.addEventListener('focusout', () => {
|
||||
if (hostnameInput.readOnly) {
|
||||
return;
|
||||
}
|
||||
editing = false;
|
||||
hostnameInput.readOnly = true;
|
||||
node.hostname = hostnameInput.value;
|
||||
socket.sendnode(node);
|
||||
});
|
||||
|
||||
domlib.newAt(freq, 'span').innerHTML = '2.4 Ghz';
|
||||
domlib.newAt(freq, 'span').innerHTML = '5 Ghz';
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
domlib.newAt(curchannel, 'span').innerHTML = node._wireless.channel24 || '-';
|
||||
domlib.newAt(curchannel, 'span').innerHTML = node._wireless.channel5 || '-';
|
||||
if (node._wireless) {
|
||||
domlib.newAt(curchannel, 'span').innerHTML = node._wireless.channel24 || '-';
|
||||
domlib.newAt(curchannel, 'span').innerHTML = node._wireless.channel5 || '-';
|
||||
}
|
||||
/* eslint-enable no-underscore-dangle */
|
||||
|
||||
domlib.newAt(channel, 'span').innerHTML = node.wireless.channel24 || '-';
|
||||
domlib.newAt(channel, 'span').innerHTML = node.wireless.channel5 || '-';
|
||||
|
||||
channel24Input.value = node.wireless.channel24 || '';
|
||||
channel24Input.type = 'number';
|
||||
channel24Input.min = 1;
|
||||
channel24Input.max = 14;
|
||||
channel24Input.readOnly = true;
|
||||
channel24Input.setAttribute('placeholder', '-');
|
||||
channel24Input.addEventListener('dblclick', () => {
|
||||
editing = true;
|
||||
channel24Input.readOnly = false;
|
||||
});
|
||||
channel24Input.addEventListener('focusout', () => {
|
||||
if (channel24Input.readOnly) {
|
||||
return;
|
||||
}
|
||||
editing = false;
|
||||
channel24Input.readOnly = true;
|
||||
node.wireless.channel24 = parseInt(channel24Input.value, 10);
|
||||
socket.sendnode(node);
|
||||
});
|
||||
|
||||
channel5Input.value = node.wireless.channel5 || '';
|
||||
channel5Input.type = 'number';
|
||||
channel5Input.min = 36;
|
||||
channel5Input.max = 165;
|
||||
channel5Input.step = 4;
|
||||
channel5Input.readOnly = true;
|
||||
channel5Input.setAttribute('placeholder', '-');
|
||||
channel5Input.addEventListener('dblclick', () => {
|
||||
editing = true;
|
||||
channel5Input.readOnly = false;
|
||||
});
|
||||
channel5Input.addEventListener('focusout', () => {
|
||||
if (channel5Input.readOnly) {
|
||||
return;
|
||||
}
|
||||
editing = false;
|
||||
channel5Input.readOnly = true;
|
||||
node.wireless.channel5 = parseInt(channel5Input.value, 10);
|
||||
socket.sendnode(node);
|
||||
});
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
domlib.newAt(curpower, 'span').innerHTML = node._wireless.txpower24 || '-';
|
||||
domlib.newAt(curpower, 'span').innerHTML = node._wireless.txpower5 || '-';
|
||||
if (node._wireless) {
|
||||
domlib.newAt(curpower, 'span').innerHTML = node._wireless.txpower24 || '-';
|
||||
domlib.newAt(curpower, 'span').innerHTML = node._wireless.txpower5 || '-';
|
||||
}
|
||||
/* eslint-enable no-underscore-dangle */
|
||||
|
||||
domlib.newAt(power, 'span').innerHTML = node.wireless.txpower24 || '-';
|
||||
domlib.newAt(power, 'span').innerHTML = node.wireless.txpower5 || '-';
|
||||
power24Input.value = node.wireless.txpower24 || '';
|
||||
power24Input.type = 'number';
|
||||
power24Input.min = 1;
|
||||
power24Input.max = 23;
|
||||
power24Input.readOnly = true;
|
||||
power24Input.setAttribute('placeholder', '-');
|
||||
power24Input.addEventListener('dblclick', () => {
|
||||
editing = true;
|
||||
power24Input.readOnly = false;
|
||||
});
|
||||
power24Input.addEventListener('focusout', () => {
|
||||
if (power24Input.readOnly) {
|
||||
return;
|
||||
}
|
||||
editing = false;
|
||||
power24Input.readOnly = true;
|
||||
node.wireless.txpower24 = parseInt(power24Input.value, 10);
|
||||
socket.sendnode(node);
|
||||
});
|
||||
|
||||
power5Input.value = node.wireless.txpower5 || '';
|
||||
power5Input.type = 'number';
|
||||
power5Input.min = 1;
|
||||
power5Input.max = 23;
|
||||
power5Input.readOnly = true;
|
||||
power5Input.setAttribute('placeholder', '-');
|
||||
power5Input.addEventListener('dblclick', () => {
|
||||
editing = true;
|
||||
power5Input.readOnly = false;
|
||||
});
|
||||
power5Input.addEventListener('focusout', () => {
|
||||
if (power5Input.readOnly) {
|
||||
return;
|
||||
}
|
||||
editing = false;
|
||||
power5Input.readOnly = true;
|
||||
node.wireless.txpower5 = parseInt(power5Input.value, 10);
|
||||
socket.sendnode(node);
|
||||
});
|
||||
|
||||
domlib.newAt(client, 'span').innerHTML = node.statistics.clients.wifi24;
|
||||
domlib.newAt(client, 'span').innerHTML = node.statistics.clients.wifi5;
|
||||
|
||||
/* eslint-disable id-length, no-magic-numbers,one-var */
|
||||
const chanUtil24 = node.statistics.wireless.filter((d) => d.frequency < 5000)[0] || {},
|
||||
chanUtil5 = node.statistics.wireless.filter((d) => d.frequency > 5000)[0] || {};
|
||||
const chanUtil24 = node.statistics.wireless
|
||||
? node.statistics.wireless.filter((d) => d.frequency < 5000)[0] || {}
|
||||
: {},
|
||||
chanUtil5 = node.statistics.wireless
|
||||
? node.statistics.wireless.filter((d) => d.frequency > 5000)[0] || {}
|
||||
: {};
|
||||
/* eslint-enable id-length, no-magic-numbers,one-var */
|
||||
|
||||
domlib.newAt(chanUtil, 'span').innerHTML = chanUtil24.ChanUtil || '-';
|
||||
|
@ -130,6 +240,9 @@ const guiList = {};
|
|||
}
|
||||
|
||||
function update () {
|
||||
if (editing) {
|
||||
return;
|
||||
}
|
||||
domlib.removeChildren(tbody);
|
||||
let nodes = store.getNodes();
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ const guiMap = {};
|
|||
tx24 = node.wireless.txpower24 || '-',
|
||||
tx5 = node.wireless.txpower5 || '-';
|
||||
|
||||
startdate.setMinutes(startdate.getMinutes() - 1);
|
||||
startdate.setMinutes(startdate.getMinutes() - config.node.offline);
|
||||
if (new Date(node.lastseen) < startdate) {
|
||||
className += ' offline';
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ const guiNode = {};
|
|||
return;
|
||||
}
|
||||
|
||||
startdate.setMinutes(startdate.getMinutes() - 1);
|
||||
startdate.setMinutes(startdate.getMinutes() - config.node.offline);
|
||||
if (new Date(node.lastseen) < startdate) {
|
||||
ago.classList.add('offline');
|
||||
ago.classList.remove('online');
|
||||
|
|
|
@ -24,10 +24,10 @@ let socket = {'readyState': 0};
|
|||
const msg = JSON.parse(raw.data);
|
||||
|
||||
switch (msg.type) {
|
||||
case 'current':
|
||||
case 'system':
|
||||
store.updateNode(msg.node, true);
|
||||
break;
|
||||
case 'to-update':
|
||||
case 'current':
|
||||
store.updateNode(msg.node);
|
||||
break;
|
||||
case 'stats':
|
||||
|
@ -54,7 +54,7 @@ let socket = {'readyState': 0};
|
|||
const notifyMsg = `Einstellungen für '${node.node_id}' gespeichert.`,
|
||||
socketMsg = JSON.stringify({
|
||||
'node': node,
|
||||
'type': 'to-update'
|
||||
'type': 'system'
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -17,30 +17,37 @@ const store = {
|
|||
(function init () {
|
||||
'use strict';
|
||||
|
||||
const list = {},
|
||||
toupdate = {};
|
||||
const current = {},
|
||||
list = {};
|
||||
|
||||
function getNode (nodeid) {
|
||||
let node = {};
|
||||
|
||||
if (toupdate[nodeid]) {
|
||||
node = toupdate[nodeid];
|
||||
} else if (list[nodeid]) {
|
||||
if (list[nodeid]) {
|
||||
node = list[nodeid];
|
||||
if (current[nodeid]) {
|
||||
const cNode = current[nodeid];
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
node._wireless = cNode.wireless;
|
||||
node.lastseen = cNode.lastseen;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
// eslint-disable-next-line camelcase
|
||||
node.node_id = nodeid;
|
||||
node.wireless = {};
|
||||
node.location = {};
|
||||
list[nodeid] = node;
|
||||
}
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
node._wireless = list[nodeid].wireless;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
store.updateNode = function updateNode (node, real) {
|
||||
if (real) {
|
||||
store.updateNode = function updateNode (node, system) {
|
||||
if (system) {
|
||||
list[node.node_id] = node;
|
||||
} else {
|
||||
toupdate[node.node_id] = node;
|
||||
current[node.node_id] = node;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -59,16 +59,16 @@ func (c *Client) Listen() {
|
|||
|
||||
func (c *Client) allNodes() {
|
||||
for _, node := range nodes.List {
|
||||
c.Write(&Message{Type: MessageTypeCurrentNode, Node: node})
|
||||
c.Write(&Message{Type: MessageTypeSystemNode, Node: node})
|
||||
}
|
||||
for _, node := range nodes.ToUpdate {
|
||||
c.Write(&Message{Type: MessageTypeUpdateNode, Node: node})
|
||||
for _, node := range nodes.Current {
|
||||
c.Write(&Message{Type: MessageTypeCurrentNode, Node: node})
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleMessage(msg *Message) {
|
||||
switch msg.Type {
|
||||
case MessageTypeUpdateNode:
|
||||
case MessageTypeSystemNode:
|
||||
nodes.UpdateNode(msg.Node)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ type Message struct {
|
|||
}
|
||||
|
||||
const (
|
||||
MessageTypeUpdateNode = "to-update"
|
||||
MessageTypeSystemNode = "system"
|
||||
MessageTypeCurrentNode = "current"
|
||||
MessageTypeStats = "stats"
|
||||
)
|
||||
|
|
|
@ -46,10 +46,10 @@ func Start(nodeBind *runtime.Nodes) {
|
|||
nodes.AddNotify(NotifyNode)
|
||||
}
|
||||
|
||||
func NotifyNode(node *runtime.Node, real bool) {
|
||||
msgType := MessageTypeUpdateNode
|
||||
if real {
|
||||
msgType = MessageTypeCurrentNode
|
||||
func NotifyNode(node *runtime.Node, system bool) {
|
||||
msgType := MessageTypeCurrentNode
|
||||
if system {
|
||||
msgType = MessageTypeSystemNode
|
||||
}
|
||||
SendAll(Message{Type: msgType, Node: node})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue