From 21c398ca423d6ca57c7480d10f3760beec44bf11 Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Thu, 26 Jul 2018 14:14:23 +0200 Subject: [PATCH] sql rewrite --- config_example.conf | 12 +++-- main.go | 41 +++++++--------- runtime/config.go | 4 +- runtime/node.go | 30 ++++++------ runtime/node_ssh.go | 31 ++++++------ runtime/nodes.go | 101 ---------------------------------------- runtime/yanic.go | 79 +++++++++++++++++-------------- webroot/css/styles.less | 6 +-- webroot/js/view/list.js | 2 - websocket/handler.go | 2 +- websocket/hd_auth.go | 51 +++++++++++++------- websocket/hd_connect.go | 25 ++++++---- websocket/hd_node.go | 31 ++++++++++-- websocket/send.go | 2 +- websocket/server.go | 9 ++-- 15 files changed, 188 insertions(+), 238 deletions(-) delete mode 100644 runtime/nodes.go diff --git a/config_example.conf b/config_example.conf index af725b3..900cb10 100644 --- a/config_example.conf +++ b/config_example.conf @@ -1,4 +1,5 @@ -state_path = "/tmp/freifunkmanager.json" +db_type = "sqlite3" +db_connection = "/tmp/freifunkmanager.db" webserver_bind = ":8080" webroot = "./webroot" @@ -6,14 +7,15 @@ webroot = "./webroot" secret = "passw0rd" ssh_key = "~/.ssh/id_rsa" -ssh_interface = "wlp4s0" -ssh_ipaddress_suffix = "fe80:" +ssh_ipaddress_suffix = "fd2f:" ssh_timeout = "1m" +ssh_config_all = false +ssh_yanic_update = true # enable receiving yanic_enable = true # yanic_synchronize = "1m" -yanic_collect_interval = "1m" +yanic_collect_interval = "10s" [yanic] ifname = "wlp4s0" @@ -22,4 +24,4 @@ ifname = "wlp4s0" # ifname = "lo" # ip_address = "::1" # send_no_request = no -# port +# port = 1001 diff --git a/main.go b/main.go index 07a4f30..2f50c2b 100644 --- a/main.go +++ b/main.go @@ -8,15 +8,16 @@ import ( "syscall" "time" + "dev.sum7.eu/genofire/golang-lib/file" "github.com/NYTimes/gziphandler" - "github.com/genofire/golang-lib/file" - httpLib "github.com/genofire/golang-lib/http" - "github.com/genofire/golang-lib/worker" log "github.com/sirupsen/logrus" respondYanic "github.com/FreifunkBremen/yanic/respond" runtimeYanic "github.com/FreifunkBremen/yanic/runtime" + "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/sqlite" + "github.com/FreifunkBremen/freifunkmanager/runtime" "github.com/FreifunkBremen/freifunkmanager/ssh" "github.com/FreifunkBremen/freifunkmanager/websocket" @@ -25,7 +26,6 @@ import ( var ( configFile string config = &runtime.Config{} - nodes *runtime.Nodes collector *respondYanic.Collector verbose bool ) @@ -44,19 +44,18 @@ func main() { log.Info("starting...") + db, err := gorm.Open(config.DatabaseType, config.DatabaseConnection) + if err != nil { + log.Panic("failed to connect database") + } + db.AutoMigrate(&runtime.Node{}, &websocket.Auth{}) + sshmanager := ssh.NewManager(config.SSHPrivateKey, config.SSHTimeout.Duration) - nodes = runtime.NewNodes(config.StatePath, config.SSHInterface, sshmanager) - nodesSaveWorker := worker.NewWorker(time.Duration(3)*time.Second, nodes.Saver) - nodesUpdateWorker := worker.NewWorker(time.Duration(3)*time.Minute, nodes.Updater) nodesYanic := runtimeYanic.NewNodes(&runtimeYanic.NodesConfig{}) - db := runtime.NewYanicDB(nodes, config.SSHIPAddressSuffix) - go nodesSaveWorker.Start() - go nodesUpdateWorker.Start() + ws := websocket.NewWebsocketServer(config.Secret, db, nodesYanic) - ws := websocket.NewWebsocketServer(config.Secret, nodes) - nodes.AddNotifyStats(ws.SendStats) - nodes.AddNotifyNode(ws.SendNode) + yanic := runtime.NewYanicDB(db, sshmanager, ws.SendNode, ws.SendStats, config.SSHIPAddressSuffix) if config.YanicEnable { if duration := config.YanicSynchronize.Duration; duration > 0 { @@ -65,7 +64,7 @@ func main() { log.Printf("delaying %0.1f seconds", delay.Seconds()) time.Sleep(delay) } - collector = respondYanic.NewCollector(db, nodesYanic, make(map[string][]string), []respondYanic.InterfaceConfig{config.Yanic}) + collector = respondYanic.NewCollector(yanic, nodesYanic, make(map[string][]string), []respondYanic.InterfaceConfig{config.Yanic}) if duration := config.YanicCollectInterval.Duration; duration > 0 { collector.Start(config.YanicCollectInterval.Duration) } @@ -74,12 +73,6 @@ func main() { } // Startwebserver - http.HandleFunc("/nodes", func(w http.ResponseWriter, r *http.Request) { - httpLib.Write(w, nodes) - }) - http.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) { - httpLib.Write(w, nodes.Statistics) - }) http.Handle("/", gziphandler.GzipHandler(http.FileServer(http.Dir(config.Webroot)))) srv := &http.Server{ @@ -99,12 +92,14 @@ func main() { signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) sig := <-sigs + log.Debug("stop recieve:", sig) + ws.Close() // Stop services srv.Close() - nodesSaveWorker.Close() - nodesUpdateWorker.Close() + db.Close() + + log.Info("stop freifunkmanager") - log.Info("stop recieve:", sig) } diff --git a/runtime/config.go b/runtime/config.go index 76d1222..e42db0b 100644 --- a/runtime/config.go +++ b/runtime/config.go @@ -9,7 +9,8 @@ import ( //config file of this daemon (for more the config_example.conf in git repository) type Config struct { // prevent crashes - StatePath string `toml:"state_path"` + DatabaseType string `toml:"db_type"` + DatabaseConnection string `toml:"db_connection"` // address on which the api and static content webserver runs WebserverBind string `toml:"webserver_bind"` @@ -21,7 +22,6 @@ type Config struct { // SSH private key SSHPrivateKey string `toml:"ssh_key"` - SSHInterface string `toml:"ssh_interface"` SSHIPAddressSuffix string `toml:"ssh_ipaddress_suffix"` SSHTimeout duration.Duration `toml:"ssh_timeout"` diff --git a/runtime/node.go b/runtime/node.go index 2615f67..fd7ad7e 100644 --- a/runtime/node.go +++ b/runtime/node.go @@ -1,7 +1,6 @@ package runtime import ( - "bytes" "net" "strings" @@ -11,14 +10,15 @@ import ( ) type Node struct { - Lastseen jsontime.Time `json:"lastseen" mapstructure:"-"` - NodeID string `json:"node_id" mapstructure:"node_id"` - Hostname string `json:"hostname"` - Location yanicData.Location `json:"location"` - Wireless yanicData.Wireless `json:"wireless"` - Owner string `json:"owner"` - Address net.IP `json:"ip" mapstructure:"-"` - Stats struct { + Lastseen jsontime.Time `json:"lastseen" mapstructure:"-"` + NodeID string `json:"node_id" gorm:"primary_key" mapstructure:"node_id"` + Hostname string `json:"hostname"` + Location yanicData.Location `json:"location" gorm:"embedded;embedded_prefix:location_"` + Wireless yanicData.Wireless `json:"wireless" gorm:"embedded;embedded_prefix:wireless_"` + Owner string `json:"owner"` + Blacklist bool `json:"blacklist" gorm:"-" mapstructure:"-"` + Address string `json:"ip" mapstructure:"-"` + Stats struct { Wireless yanicData.WirelessStatistics `json:"wireless"` Clients yanicData.Clients `json:"clients"` } `json:"statistics" mapstructure:"-"` @@ -35,8 +35,8 @@ func NewNode(nodeOrigin *yanicRuntime.Node, ipPrefix string) *Node { continue } ipAddr := net.ParseIP(ip) - if node.Address == nil || ipAddr.IsGlobalUnicast() { - node.Address = ipAddr + if node.Address == "" || ipAddr.IsGlobalUnicast() { + node.Address = ipAddr.String() } } if owner := nodeinfo.Owner; owner != nil { @@ -56,14 +56,14 @@ func NewNode(nodeOrigin *yanicRuntime.Node, ipPrefix string) *Node { } return nil } -func (n *Node) GetAddress(iface string) net.TCPAddr { - return net.TCPAddr{IP: n.Address, Port: 22, Zone: iface} +func (n *Node) GetAddress() net.TCPAddr { + return net.TCPAddr{IP: net.ParseIP(n.Address), Port: 22} } func (n *Node) Update(node *yanicRuntime.Node) { if nodeinfo := node.Nodeinfo; nodeinfo != nil { n.Hostname = nodeinfo.Hostname n.NodeID = nodeinfo.NodeID - n.Address = node.Address.IP + n.Address = node.Address.IP.String() if owner := nodeinfo.Owner; owner != nil { n.Owner = owner.Contact @@ -80,7 +80,7 @@ func (n *Node) IsEqual(node *Node) bool { if n.NodeID != node.NodeID { return false } - if !bytes.Equal(n.Address, node.Address) { + if n.Address != node.Address { return false } if n.Hostname != node.Hostname { diff --git a/runtime/node_ssh.go b/runtime/node_ssh.go index 8a9ac2d..7b7b7ad 100644 --- a/runtime/node_ssh.go +++ b/runtime/node_ssh.go @@ -9,30 +9,27 @@ import ( "github.com/FreifunkBremen/freifunkmanager/ssh" ) -func (n *Node) SSHUpdate(sshmgmt *ssh.Manager, iface string, oldnode *Node) { - addr := n.GetAddress(iface) - client, err := sshmgmt.ConnectTo(addr) +func (n *Node) SSHUpdate(sshmgmt *ssh.Manager, oldnode *Node) { + client, err := sshmgmt.ConnectTo(n.GetAddress()) if err != nil { return } defer client.Close() if oldnode == nil || n.Hostname != oldnode.Hostname { - ssh.Execute(n.Address.String(), client, fmt.Sprintf(` + ssh.Execute(n.Address, client, fmt.Sprintf(` uci set system.@system[0].hostname='%s'; - uci set wireless.priv_radio0.ssid="offline-$(uci get system.@system[0].hostname)"; - uci set wireless.priv_radio1.ssid="offline-$(uci get system.@system[0].hostname)"; uci commit; echo $(uci get system.@system[0].hostname) > /proc/sys/kernel/hostname;`, n.Hostname)) } if oldnode == nil || n.Owner != oldnode.Owner { - ssh.Execute(n.Address.String(), client, fmt.Sprintf(` + ssh.Execute(n.Address, client, fmt.Sprintf(` uci set gluon-node-info.@owner[0].contact='%s'; uci commit gluon-node-info;`, n.Owner)) } if oldnode == nil || !locationEqual(n.Location, oldnode.Location) { - ssh.Execute(n.Address.String(), client, fmt.Sprintf(` + ssh.Execute(n.Address, client, fmt.Sprintf(` uci set gluon-node-info.@location[0].latitude='%f'; uci set gluon-node-info.@location[0].longitude='%f'; uci set gluon-node-info.@location[0].share_location=1; @@ -43,13 +40,13 @@ func (n *Node) SSHUpdate(sshmgmt *ssh.Manager, iface string, oldnode *Node) { runWifi := false defer func() { if runWifi { - ssh.Execute(n.Address.String(), client, "wifi") + ssh.Execute(n.Address, client, "wifi") // send warning for running wifi, because it kicks clients from node log.Warn("[cmd] wifi ", n.NodeID) } }() - result, err := ssh.Run(n.Address.String(), client, ` + result, err := ssh.Run(n.Address, client, ` if [ "$(uci get wireless.radio0.hwmode | grep -c g)" -ne 0 ]; then echo "radio0"; elif [ "$(uci get wireless.radio1.hwmode | grep -c g)" -ne 0 ]; then @@ -60,16 +57,16 @@ func (n *Node) SSHUpdate(sshmgmt *ssh.Manager, iface string, oldnode *Node) { } radio := ssh.SSHResultToString(result) ch := GetChannel(n.Wireless.Channel24) - if radio != "" || ch == nil { + if radio != "" && ch != nil { if oldnode == nil || n.Wireless.TxPower24 != oldnode.Wireless.TxPower24 { - ssh.Execute(n.Address.String(), client, fmt.Sprintf(` + ssh.Execute(n.Address, client, fmt.Sprintf(` uci set wireless.%s.txpower='%d'; uci commit wireless;`, radio, n.Wireless.TxPower24)) runWifi = true } if oldnode == nil || n.Wireless.Channel24 != oldnode.Wireless.Channel24 { - ssh.Execute(n.Address.String(), 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 commit wireless;`, @@ -78,7 +75,7 @@ func (n *Node) SSHUpdate(sshmgmt *ssh.Manager, iface string, oldnode *Node) { } } - result, err = ssh.Run(n.Address.String(), client, ` + result, err = ssh.Run(n.Address, client, ` if [ "$(uci get wireless.radio0.hwmode | grep -c a)" -ne 0 ]; then echo "radio0"; elif [ "$(uci get wireless.radio1.hwmode | grep -c a)" -ne 0 ]; then @@ -89,16 +86,16 @@ func (n *Node) SSHUpdate(sshmgmt *ssh.Manager, iface string, oldnode *Node) { } radio = ssh.SSHResultToString(result) ch = GetChannel(n.Wireless.Channel5) - if radio != "" || ch == nil { + if radio != "" && ch != nil { if oldnode == nil || n.Wireless.TxPower5 != oldnode.Wireless.TxPower5 { - ssh.Execute(n.Address.String(), client, fmt.Sprintf(` + ssh.Execute(n.Address, client, fmt.Sprintf(` uci set wireless.%s.txpower='%d'; uci commit wireless;`, radio, n.Wireless.TxPower5)) runWifi = true } if oldnode == nil || n.Wireless.Channel5 != oldnode.Wireless.Channel5 { - ssh.Execute(n.Address.String(), 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 commit wireless;`, diff --git a/runtime/nodes.go b/runtime/nodes.go deleted file mode 100644 index 0fa4cce..0000000 --- a/runtime/nodes.go +++ /dev/null @@ -1,101 +0,0 @@ -package runtime - -import ( - "sync" - - log "github.com/sirupsen/logrus" - - runtimeYanic "github.com/FreifunkBremen/yanic/runtime" - "github.com/genofire/golang-lib/file" - - "github.com/FreifunkBremen/freifunkmanager/ssh" -) - -type Nodes struct { - List map[string]*Node `json:"nodes"` - Current map[string]*Node `json:"-"` - Statistics *runtimeYanic.GlobalStats `json:"-"` - ssh *ssh.Manager - statePath string - iface string - notifyNodeFunc []func(*Node, bool) - notifyStatsFunc []func(*runtimeYanic.GlobalStats) - ListMux sync.RWMutex - CurrentMux sync.RWMutex -} - -func NewNodes(path string, iface string, mgmt *ssh.Manager) *Nodes { - nodes := &Nodes{ - List: make(map[string]*Node), - Current: make(map[string]*Node), - ssh: mgmt, - statePath: path, - iface: iface, - } - file.ReadJSON(path, nodes) - return nodes -} - -func (nodes *Nodes) AddNotifyNode(f func(*Node, bool)) { - nodes.notifyNodeFunc = append(nodes.notifyNodeFunc, f) -} -func (nodes *Nodes) notifyNode(node *Node, system bool) { - for _, f := range nodes.notifyNodeFunc { - f(node, system) - } -} - -func (nodes *Nodes) AddNotifyStats(f func(stats *runtimeYanic.GlobalStats)) { - nodes.notifyStatsFunc = append(nodes.notifyStatsFunc, f) -} -func (nodes *Nodes) notifyStats(stats *runtimeYanic.GlobalStats) { - nodes.Statistics = stats - for _, f := range nodes.notifyStatsFunc { - f(stats) - } -} - -func (nodes *Nodes) UpdateNode(node *Node) bool { - if node == nil { - log.Warn("no new node to update") - return false - } - if GetChannel(node.Wireless.Channel24) == nil { - log.Warnf("wrong wifi24 channel for '%s'", node.NodeID) - return false - } - if GetChannel(node.Wireless.Channel5) == nil { - log.Warnf("wrong wifi5 channel for '%s'", node.NodeID) - return false - } - nodes.ListMux.Lock() - if n, ok := nodes.List[node.NodeID]; ok { - node.Address = n.Address - go node.SSHUpdate(nodes.ssh, nodes.iface, n) - log.Info("update node", node.NodeID) - } - nodes.List[node.NodeID] = node - nodes.ListMux.Unlock() - nodes.notifyNode(node, true) - return true -} - -func (nodes *Nodes) Updater() { - nodes.ListMux.RLock() - nodes.CurrentMux.RLock() - for nodeid, node := range nodes.List { - if n, ok := nodes.Current[nodeid]; ok { - go node.SSHUpdate(nodes.ssh, nodes.iface, n) - } - } - nodes.ListMux.RUnlock() - nodes.CurrentMux.RUnlock() - log.Info("updater per ssh") -} - -func (nodes *Nodes) Saver() { - nodes.ListMux.RLock() - file.SaveJSON(nodes.statePath, nodes) - nodes.ListMux.RUnlock() - log.Debug("saved state file") -} diff --git a/runtime/yanic.go b/runtime/yanic.go index cad9941..d3aa57f 100644 --- a/runtime/yanic.go +++ b/runtime/yanic.go @@ -3,6 +3,7 @@ package runtime import ( "time" + "github.com/jinzhu/gorm" log "github.com/sirupsen/logrus" databaseYanic "github.com/FreifunkBremen/yanic/database" @@ -14,14 +15,20 @@ import ( type YanicDB struct { databaseYanic.Connection - nodes *Nodes - prefix string + db *gorm.DB + ssh *ssh.Manager + sendNode func(*Node, bool) + sendStats func(*runtimeYanic.GlobalStats) + prefix string } -func NewYanicDB(nodes *Nodes, prefix string) *YanicDB { +func NewYanicDB(db *gorm.DB, ssh *ssh.Manager, sendNode func(*Node, bool), sendStats func(*runtimeYanic.GlobalStats), prefix string) *YanicDB { return &YanicDB{ - nodes: nodes, - prefix: prefix, + db: db, + ssh: ssh, + sendNode: sendNode, + sendStats: sendStats, + prefix: prefix, } } @@ -32,40 +39,42 @@ func (conn *YanicDB) InsertNode(n *runtimeYanic.Node) { } node.Lastseen = jsontime.Now() logger := log.WithField("method", "LearnNode").WithField("node_id", node.NodeID) - conn.nodes.ListMux.Lock() - if lNode := conn.nodes.List[node.NodeID]; lNode != nil { - lNode.Lastseen = jsontime.Now() - lNode.Stats = node.Stats - } else { - conn.nodes.List[node.NodeID] = node - conn.nodes.notifyNode(node, true) + lNode := Node{ + NodeID: node.NodeID, } - conn.nodes.ListMux.Unlock() - conn.nodes.CurrentMux.Lock() - if _, ok := conn.nodes.Current[node.NodeID]; ok { - conn.nodes.Current[node.NodeID] = node - conn.nodes.notifyNode(node, false) - conn.nodes.CurrentMux.Unlock() + if conn.db.First(&lNode).Error == nil { + conn.db.Model(&lNode).Update(map[string]interface{}{ + "Lastseen": jsontime.Now(), + //"StatsWireless": node.StatsWireless, + //"StatsClients": node.StatsClients, + "Address": node.Address, + }) + conn.sendNode(node, false) + if lNode.Blacklist { + logger.Debug("on blacklist") + return + } + if !node.IsEqual(&lNode) { + lNode.SSHUpdate(conn.ssh, node) + logger.Debug("run sshupdate again") + } + logger.Debug("yanic update") return } - // session := nodes.ssh.ConnectTo(node.Address) - result, err := conn.nodes.ssh.RunOn(node.GetAddress(conn.nodes.iface), "uptime") - if err != nil { - logger.Debug("init ssh command not run", err) - return - } - uptime := ssh.SSHResultToString(result) - logger.Infof("new node with uptime: %s", uptime) - conn.nodes.Current[node.NodeID] = node - conn.nodes.CurrentMux.Unlock() - conn.nodes.ListMux.Lock() - if lNode := conn.nodes.List[node.NodeID]; lNode != nil { - lNode.Address = node.Address - go lNode.SSHUpdate(conn.nodes.ssh, conn.nodes.iface, node) + node.Lastseen = jsontime.Now() + + _, err := conn.ssh.RunOn(node.GetAddress(), "uptime") + if err != nil { + logger.Debug("set on blacklist") + node.Blacklist = true + } + conn.db.Create(&node) + conn.sendNode(node, true) + if err == nil { + lNode.SSHUpdate(conn.ssh, node) + logger.Debug("run sshupdate") } - conn.nodes.ListMux.Unlock() - conn.nodes.notifyNode(node, false) } func (conn *YanicDB) InsertLink(link *runtimeYanic.Link, time time.Time) { @@ -73,7 +82,7 @@ func (conn *YanicDB) InsertLink(link *runtimeYanic.Link, time time.Time) { func (conn *YanicDB) InsertGlobals(stats *runtimeYanic.GlobalStats, time time.Time, site string, domain string) { if runtimeYanic.GLOBAL_SITE == site && runtimeYanic.GLOBAL_DOMAIN == domain { - conn.nodes.notifyStats(stats) + conn.sendStats(stats) } } diff --git a/webroot/css/styles.less b/webroot/css/styles.less index 948dd53..62fe0a2 100644 --- a/webroot/css/styles.less +++ b/webroot/css/styles.less @@ -66,11 +66,11 @@ table.nodes tbody tr:nth-child(odd) { table.nodes tbody tr:hover { background: #ccc; } -table.nodes tbody tr.offline, -table.nodes tbody tr.offline:hover{ +table.nodes tbody tr.offline:first-child, +table.nodes tbody tr.offline:hover:first-child{ background: #dc0067; } -table.nodes tbody tr.unseen{ +table.nodes tbody tr.unseen:first-child{ background: #009ee0; } diff --git a/webroot/js/view/list.js b/webroot/js/view/list.js index 0f4eb45..7a78016 100644 --- a/webroot/js/view/list.js +++ b/webroot/js/view/list.js @@ -281,8 +281,6 @@ export class ListView extends View { 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', () => { diff --git a/websocket/handler.go b/websocket/handler.go index b63e655..2b7641c 100644 --- a/websocket/handler.go +++ b/websocket/handler.go @@ -3,7 +3,7 @@ package websocket import ( log "github.com/sirupsen/logrus" - "github.com/genofire/golang-lib/websocket" + "dev.sum7.eu/genofire/golang-lib/websocket" ) type WebsocketHandlerFunc func(*log.Entry, *websocket.Message) error diff --git a/websocket/hd_auth.go b/websocket/hd_auth.go index e27691a..7fa49af 100644 --- a/websocket/hd_auth.go +++ b/websocket/hd_auth.go @@ -1,14 +1,30 @@ package websocket import ( + "github.com/google/uuid" log "github.com/sirupsen/logrus" - "github.com/genofire/golang-lib/websocket" + "dev.sum7.eu/genofire/golang-lib/websocket" ) +type Auth struct { + SessionID uuid.UUID +} + +func (ws *WebsocketServer) IsLoggedIn(msg *websocket.Message) bool { + auth := Auth{ + SessionID: msg.Session, + } + err := ws.db.First(&auth) + return err.Error == nil +} + func (ws *WebsocketServer) loginHandler(logger *log.Entry, msg *websocket.Message) error { - _, ok := ws.loggedIn[msg.Session] - if ok { + auth := Auth{ + SessionID: msg.Session, + } + err := ws.db.First(&auth) + if err.Error == nil { msg.Answer(msg.Subject, true) logger.Warn("already loggedIn") return nil @@ -21,7 +37,12 @@ func (ws *WebsocketServer) loginHandler(logger *log.Entry, msg *websocket.Messag } ok = (ws.secret == secret) if ok { - ws.loggedIn[msg.Session] = true + err = ws.db.Create(&auth) + if err.Error != nil { + log.Warnf("database error: %s", err.Error.Error()) + msg.Answer(msg.Subject, false) + return err.Error + } logger.Debug("done") } else { logger.Warn("wrong secret") @@ -31,25 +52,23 @@ func (ws *WebsocketServer) loginHandler(logger *log.Entry, msg *websocket.Messag } func (ws *WebsocketServer) authStatusHandler(logger *log.Entry, msg *websocket.Message) error { - login, ok := ws.loggedIn[msg.Session] defer logger.Debug("done") - if !ok { - msg.Answer(msg.Subject, false) - return nil - } - msg.Answer(msg.Subject, login) + + msg.Answer(msg.Subject, ws.IsLoggedIn(msg)) return nil } func (ws *WebsocketServer) logoutHandler(logger *log.Entry, msg *websocket.Message) error { - _, ok := ws.loggedIn[msg.Session] - if !ok { + auth := Auth{ + SessionID: msg.Session, + } + err := ws.db.First(&auth) + if err.Error != nil { msg.Answer(msg.Subject, false) logger.Warn("logout without login") return nil } - ws.loggedIn[msg.Session] = false - delete(ws.loggedIn, msg.Session) + err = ws.db.Delete(&auth) logger.Debug("done") - msg.Answer(msg.Subject, true) - return nil + msg.Answer(msg.Subject, err.Error == nil) + return err.Error } diff --git a/websocket/hd_connect.go b/websocket/hd_connect.go index 9b86bab..121909c 100644 --- a/websocket/hd_connect.go +++ b/websocket/hd_connect.go @@ -3,7 +3,7 @@ package websocket import ( log "github.com/sirupsen/logrus" - wsLib "github.com/genofire/golang-lib/websocket" + wsLib "dev.sum7.eu/genofire/golang-lib/websocket" "github.com/FreifunkBremen/freifunkmanager/runtime" ) @@ -12,20 +12,25 @@ var wifi24Channels []uint32 var wifi5Channels []uint32 func (ws *WebsocketServer) connectHandler(logger *log.Entry, msg *wsLib.Message) error { - msg.From.Write(&wsLib.Message{Subject: MessageTypeStats, Body: ws.nodes.Statistics}) - ws.nodes.ListMux.RLock() + //msg.From.Write(&wsLib.Message{Subject: MessageTypeStats, Body: ws.nodes.Statistics}) + var nodes []*runtime.Node + var count int + + ws.db.Find(&nodes).Count(&count) + + ws.nodes.Lock() + i := 0 for _, node := range ws.nodes.List { + msg.From.Write(&wsLib.Message{Subject: MessageTypeCurrentNode, Body: node}) + i++ + } + ws.nodes.Unlock() + for _, node := range nodes { msg.From.Write(&wsLib.Message{Subject: MessageTypeSystemNode, Body: node}) } - ws.nodes.ListMux.RUnlock() - ws.nodes.CurrentMux.RLock() - for _, node := range ws.nodes.Current { - msg.From.Write(&wsLib.Message{Subject: MessageTypeCurrentNode, Body: node}) - } - ws.nodes.CurrentMux.RUnlock() msg.From.Write(&wsLib.Message{Subject: MessageTypeChannelsWifi24, Body: wifi24Channels}) msg.From.Write(&wsLib.Message{Subject: MessageTypeChannelsWifi5, Body: wifi5Channels}) - logger.Debug("done") + logger.Debugf("done - fetch %d nodes and send %d", count, i) return nil } diff --git a/websocket/hd_node.go b/websocket/hd_node.go index 3a0e65a..4bcea78 100644 --- a/websocket/hd_node.go +++ b/websocket/hd_node.go @@ -4,18 +4,18 @@ import ( "github.com/mitchellh/mapstructure" log "github.com/sirupsen/logrus" - wsLib "github.com/genofire/golang-lib/websocket" + wsLib "dev.sum7.eu/genofire/golang-lib/websocket" "github.com/FreifunkBremen/freifunkmanager/runtime" ) func (ws *WebsocketServer) nodeHandler(logger *log.Entry, msg *wsLib.Message) error { - if ok, exists := ws.loggedIn[msg.Session]; !ok || !exists { + if !ws.IsLoggedIn(msg) { msg.Answer(msg.Subject, false) logger.Warn("not logged in") return nil } - node := runtime.Node{} + var node runtime.Node if err := mapstructure.Decode(msg.Body, &node); err != nil { msg.Answer(msg.Subject, false) logger.Warnf("not able to decode data: %s", err) @@ -27,7 +27,30 @@ func (ws *WebsocketServer) nodeHandler(logger *log.Entry, msg *wsLib.Message) er logger.Debugf("%v", node) return nil } - msg.Answer(msg.Subject, ws.nodes.UpdateNode(&node)) + originNode := runtime.Node{ + NodeID: node.NodeID, + } + err := ws.db.First(&originNode) + + originNode.Hostname = node.Hostname + originNode.Owner = node.Owner + originNode.Wireless = node.Wireless + originNode.Location = node.Location + if err.Error == nil { + err = ws.db.Save(&originNode) + } else { + logger.Debug(err.Error.Error(), err) + err = ws.db.Create(&originNode) + } + hasError := (err.Error != nil) + + msg.Answer(msg.Subject, !hasError) + + if hasError { + logger.Warnf("could not change %s: %s", node.NodeID, err.Error.Error()) + return err.Error + } + ws.SendNode(&node, true) logger.Infof("change %s", node.NodeID) return nil } diff --git a/websocket/send.go b/websocket/send.go index f6ef5f0..fd1de5d 100644 --- a/websocket/send.go +++ b/websocket/send.go @@ -1,7 +1,7 @@ package websocket import ( - wsLib "github.com/genofire/golang-lib/websocket" + wsLib "dev.sum7.eu/genofire/golang-lib/websocket" yanicRuntime "github.com/FreifunkBremen/yanic/runtime" diff --git a/websocket/server.go b/websocket/server.go index bc1fc28..602aafa 100644 --- a/websocket/server.go +++ b/websocket/server.go @@ -3,14 +3,16 @@ package websocket import ( "net/http" - wsLib "github.com/genofire/golang-lib/websocket" + wsLib "dev.sum7.eu/genofire/golang-lib/websocket" "github.com/google/uuid" + "github.com/jinzhu/gorm" - "github.com/FreifunkBremen/freifunkmanager/runtime" + "github.com/FreifunkBremen/yanic/runtime" ) type WebsocketServer struct { nodes *runtime.Nodes + db *gorm.DB secret string loggedIn map[uuid.UUID]bool @@ -19,9 +21,10 @@ type WebsocketServer struct { handlers map[string]WebsocketHandlerFunc } -func NewWebsocketServer(secret string, nodes *runtime.Nodes) *WebsocketServer { +func NewWebsocketServer(secret string, db *gorm.DB, nodes *runtime.Nodes) *WebsocketServer { ownWS := WebsocketServer{ nodes: nodes, + db: db, handlers: make(map[string]WebsocketHandlerFunc), loggedIn: make(map[uuid.UUID]bool), inputMSG: make(chan *wsLib.Message),