[BUGFIX] improve websocket and stats of nodes

This commit is contained in:
Martin Geno 2017-05-09 01:03:44 +02:00
parent 9579f62815
commit 24248d3673
No known key found for this signature in database
GPG Key ID: F0D39A37E925E941
9 changed files with 108 additions and 82 deletions

View File

@ -64,7 +64,7 @@ func main() {
go func() { go func() {
if err := srv.ListenAndServe(); err != nil { if err := srv.ListenAndServe(); err != nil {
panic(err) log.Log.Panic(err)
} }
}() }()

View File

@ -41,11 +41,16 @@ func (nodes *Nodes) AddNode(n *yanic.Node) {
if cNode := nodes.List[node.NodeID]; cNode != nil { if cNode := nodes.List[node.NodeID]; cNode != nil {
cNode.Lastseen = time.Now() cNode.Lastseen = time.Now()
if _, ok := nodes.ToUpdate[node.NodeID]; ok { cNode.Stats = node.Stats
if uNode, ok := nodes.ToUpdate[node.NodeID]; ok {
uNode.Lastseen = time.Now()
uNode.Stats = node.Stats
if nodes.List[node.NodeID].IsEqual(node) { if nodes.List[node.NodeID].IsEqual(node) {
delete(nodes.ToUpdate, node.NodeID) delete(nodes.ToUpdate, node.NodeID)
nodes.List[node.NodeID] = node nodes.List[node.NodeID] = node
nodes.notify(node, true) nodes.notify(node, true)
} else {
nodes.notify(uNode, false)
} }
} else { } else {
nodes.List[node.NodeID] = node nodes.List[node.NodeID] = node

View File

@ -4,6 +4,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>FreifunkManager</title> <title>FreifunkManager</title>
<link rel="stylesheet" href="/node_modules/semantic-ui-css/semantic.min.css">
<link rel="stylesheet" href="/css/main.css"> <link rel="stylesheet" href="/css/main.css">
<script src="//localhost:35729/livereload.js"></script> <script src="//localhost:35729/livereload.js"></script>
<script src="/js/config.js"></script> <script src="/js/config.js"></script>
@ -21,6 +22,7 @@
<br /> <br />
Karten &amp; Knoten... Karten &amp; Knoten...
</p> </p>
<p class="error"></p>
<noscript> <noscript>
<strong>JavaScript required</strong> <strong>JavaScript required</strong>
</noscript> </noscript>

View File

@ -10,9 +10,8 @@ var gui = {};
console.log(store.will()) console.log(store.will())
} }
gui.disable = function disable(err){ gui.disable = function disable(err){
document.querySelector('.loader').innerHTML += err document.querySelector('.loader p.error').innerHTML = err
+ '<br /><br /><button onclick="location.reload(true)" class="btn text">Try to reload</button>'; + '<br /><br /><button onclick="location.reload(true)" class="ui labeled icon button"><i class="bomb icon"></i>Try to reload</button>';
console.warn(err);
}; };
gui.connecting = function connecting(){ gui.connecting = function connecting(){

View File

@ -1,35 +1,51 @@
var socket = new WebSocket(config.backend); var socket = {};
(function(){ (function(){
// When the connection is open, send some data to the server
socket.onopen = function () { function onerror(err) {
gui.disable("Es besteht ein Verbindungsproblem!");
console.warn(err);
}
function onopen() {
gui.enable(); gui.enable();
}; }
// Log errors function onmessage(e) {
socket.onerror = function (err) {
gui.disable(err);
};
// Log messages from the server
socket.onmessage = function (e) {
var msg = JSON.parse(e.data); var msg = JSON.parse(e.data);
if(msg.state === "current") { if(msg.type === "current") {
store.updateReal(msg.node); store.updateReal(msg.node);
gui.render(); gui.render();
} else if (msg.state === "to-update") { } else if (msg.type === "to-update") {
store.update(msg.node); store.update(msg.node);
gui.render(); gui.render();
} else { } else {
gui.disable(e); gui.disable(e);
} }
}; }
socket.sendnode = function(node) { function onclose(){
gui.disable("Es besteht ein Verbindungsproblem!<br/> <small>(Automatische Neuverbindung)</small>");
console.log("socket closed by server");
setTimeout(connect, 5000);
}
function sendnode(node) {
var msg = {node:node}; var msg = {node:node};
var string = JSON.stringify(msg); var string = JSON.stringify(msg);
socket.send(string); socket.send(string);
}; }
function connect() {
socket = new WebSocket(config.backend);
socket.onopen = onopen;
socket.onerror = onerror;
socket.onmessage = onmessage;
socket.onclose = onclose;
socket.sendnode = sendnode;
}
connect();
})(); })();

View File

@ -11,27 +11,25 @@ import (
const channelBufSize = 100 const channelBufSize = 100
type Client struct { type Client struct {
ip string ip string
ws *websocket.Conn ws *websocket.Conn
ch chan *Message ch chan *Message
doneCh chan bool writeQuit chan bool
} readQuit chan bool
func disconnect(c *Client) {
delete(clients, c.ip)
} }
func NewClient(ip string, ws *websocket.Conn) *Client { func NewClient(ip string, ws *websocket.Conn) *Client {
if ws == nil { if ws == nil {
panic("ws cannot be nil") log.Log.Panic("ws cannot be nil")
} }
return &Client{ return &Client{
ws: ws, ws: ws,
ch: make(chan *Message, channelBufSize), ch: make(chan *Message, channelBufSize),
doneCh: make(chan bool), writeQuit: make(chan bool),
ip: ip, readQuit: make(chan bool),
ip: ip,
} }
} }
@ -39,22 +37,15 @@ func (c *Client) Write(msg *Message) {
select { select {
case c.ch <- msg: case c.ch <- msg:
default: default:
disconnect(c) delete(clients, c.ip)
log.HTTP(c.ws.Request()).Error("client is disconnected.") log.HTTP(c.ws.Request()).Error("client disconnected")
} }
} }
func (c *Client) Done() { func (c *Client) Close() {
c.doneCh <- true c.writeQuit <- true
} c.readQuit <- true
log.HTTP(c.ws.Request()).Info("client disconnecting...")
func (c *Client) allNodes() {
for _, node := range nodes.List {
c.Write(&Message{State: StateCurrentNode, Node: node})
}
for _, node := range nodes.ToUpdate {
c.Write(&Message{State: StateUpdateNode, Node: node})
}
} }
// Listen Write and Read request via chanel // Listen Write and Read request via chanel
@ -64,6 +55,22 @@ func (c *Client) Listen() {
c.listenRead() c.listenRead()
} }
func (c *Client) allNodes() {
for _, node := range nodes.List {
c.Write(&Message{Type: MessageTypeCurrentNode, Node: node})
}
for _, node := range nodes.ToUpdate {
c.Write(&Message{Type: MessageTypeUpdateNode, Node: node})
}
}
func (c *Client) handleMassage(msg *Message) {
switch msg.Type {
case MessageTypeUpdateNode:
nodes.UpdateNode(msg.Node)
}
}
// Listen write request via chanel // Listen write request via chanel
func (c *Client) listenWrite() { func (c *Client) listenWrite() {
for { for {
@ -71,9 +78,10 @@ func (c *Client) listenWrite() {
case msg := <-c.ch: case msg := <-c.ch:
websocket.JSON.Send(c.ws, msg) websocket.JSON.Send(c.ws, msg)
case <-c.doneCh: case <-c.writeQuit:
disconnect(c) close(c.ch)
c.doneCh <- true close(c.writeQuit)
delete(clients, c.ip)
return return
} }
} }
@ -84,22 +92,22 @@ func (c *Client) listenRead() {
for { for {
select { select {
case <-c.doneCh: case <-c.readQuit:
disconnect(c) close(c.readQuit)
c.doneCh <- true delete(clients, c.ip)
return return
default: default:
var msg Message var msg Message
err := websocket.JSON.Receive(c.ws, &msg) err := websocket.JSON.Receive(c.ws, &msg)
if err == io.EOF { if err == io.EOF {
log.HTTP(c.ws.Request()).Info("disconnect") close(c.readQuit)
c.doneCh <- true c.writeQuit <- true
return
} else if err != nil { } else if err != nil {
log.HTTP(c.ws.Request()).Error(err) log.HTTP(c.ws.Request()).Error(err)
} else { } else {
log.HTTP(c.ws.Request()).Info("recieve nodeupdate") c.handleMassage(&msg)
nodes.UpdateNode(msg.Node)
} }
} }
} }

View File

@ -3,11 +3,11 @@ package websocket
import "github.com/FreifunkBremen/freifunkmanager/runtime" import "github.com/FreifunkBremen/freifunkmanager/runtime"
type Message struct { type Message struct {
State string `json:"state"` Type string `json:"type"`
Node *runtime.Node `json:"node"` Node *runtime.Node `json:"node"`
} }
const ( const (
StateUpdateNode = "to-update" MessageTypeUpdateNode = "to-update"
StateCurrentNode = "current" MessageTypeCurrentNode = "current"
) )

View File

@ -12,48 +12,42 @@ import (
var nodes *runtime.Nodes var nodes *runtime.Nodes
var clients map[string]*Client var clients map[string]*Client
var quit chan struct{}
func Start(nodeBind *runtime.Nodes) { func Start(nodeBind *runtime.Nodes) {
nodes = nodeBind nodes = nodeBind
clients = make(map[string]*Client) clients = make(map[string]*Client)
quit = make(chan struct{})
http.Handle("/websocket", websocket.Handler(func(ws *websocket.Conn) { http.Handle("/websocket", websocket.Handler(func(ws *websocket.Conn) {
r := ws.Request()
ip := httpLib.GetRemoteIP(r)
defer func() { defer func() {
ws.Close() ws.Close()
delete(clients, ip)
log.HTTP(r).Info("client disconnected")
}() }()
r := ws.Request()
log.HTTP(r).Infof("new client") log.HTTP(r).Infof("new client")
ip := httpLib.GetRemoteIP(r)
client := NewClient(ip, ws) client := NewClient(ip, ws)
clients[ip] = client clients[ip] = client
client.Listen() client.Listen()
})) }))
nodes.AddNotify(Notify) nodes.AddNotify(Notify)
/*
for {
select {
case <-quit:
return
}
}*/
} }
func Notify(node *runtime.Node, real bool) { func Notify(node *runtime.Node, real bool) {
state := StateUpdateNode msgType := MessageTypeUpdateNode
if real { if real {
state = StateCurrentNode msgType = MessageTypeCurrentNode
} }
for _, c := range clients { for _, c := range clients {
c.Write(&Message{State: state, Node: node}) c.Write(&Message{Type: msgType, Node: node})
} }
} }
func Close() { func Close() {
for _, c := range clients { log.Log.Infof("websocket stopped with %d clients", len(clients))
c.Done()
}
close(quit)
} }

View File

@ -38,9 +38,11 @@ func (d *Dialer) Start() {
go d.parser() go d.parser()
} }
func (d *Dialer) Close() { func (d *Dialer) Close() {
close(d.quit) if d != nil {
d.conn.Close() d.conn.Close()
close(d.queue) close(d.queue)
close(d.quit)
}
} }
func (d *Dialer) reciever() { func (d *Dialer) reciever() {