diff --git a/.gitignore b/.gitignore
index a38df26..0c12c4d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -124,6 +124,11 @@ __pycache__
# IDE's go
.idea/
+# webroot
+webroot/node_modules
+webroot/data
+webroot/app.js
+webroot/app.js.map
# go project
profile.cov
diff --git a/config/main_test.go b/config/main_test.go
deleted file mode 100644
index 6712e4d..0000000
--- a/config/main_test.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package config
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestReadConfig(t *testing.T) {
- assert := assert.New(t)
-
- config := ReadConfigFile("../config_example.conf")
- assert.NotNil(config)
-
- assert.Equal(":8080", config.WebserverBind)
-
- assert.Panics(func() {
- ReadConfigFile("../config_example.co")
- }, "wrong file")
-
- assert.Panics(func() {
- ReadConfigFile("testdata/config_panic.conf")
- }, "wrong toml")
-}
diff --git a/config/testdata/config_panic.conf b/config/testdata/config_panic.conf
deleted file mode 100644
index 3d07101..0000000
--- a/config/testdata/config_panic.conf
+++ /dev/null
@@ -1 +0,0 @@
-not unmarshalable
diff --git a/config_example.conf b/config_example.conf
index b623c57..a6321d7 100644
--- a/config_example.conf
+++ b/config_example.conf
@@ -1,12 +1,14 @@
+state_path = "/tmp/freifunkmanager.json"
+
webserver_bind = ":8080"
webroot = "./webroot"
-state_path = "/tmp/freifunkmanager.json"
-ssh_key = "/etc/id_rsa"
+ssh_key = "~/.ssh/id_rsa"
ssh_interface = "wlp4s0"
[yanic]
-enable = true
-type = "tcp"
-address = "localhost:8081"
+enable = true
+ifname = "lo"
+address = "::1"
+port = 10001
diff --git a/controller/main.go b/controller/main.go
deleted file mode 100644
index b99d683..0000000
--- a/controller/main.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package controller
-
-import (
- "fmt"
- "net"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "github.com/genofire/golang-lib/log"
-
- "github.com/FreifunkBremen/freifunkmanager/ssh"
-)
-
-const (
- maxDB = -75
-)
-
-type Controller struct {
- sshMgmt *ssh.Manager
- no24Ghz map[string]bool
- node map[string]map[string]time.Time
- quit chan struct{}
- sync.Mutex
-}
-
-func NewController(ssh *ssh.Manager) *Controller {
- return &Controller{
- sshMgmt: ssh,
- quit: make(chan struct{}),
- }
-}
-func (c *Controller) Start() {
- ticker := time.NewTicker(time.Second)
- for {
- select {
- case <-ticker.C:
- c.tick()
- case <-c.quit:
- ticker.Stop()
- return
- }
- }
-}
-
-func (c *Controller) Close() {
- close(c.quit)
-}
-
-func (c *Controller) tick() {
- c.sshMgmt.RunEverywhere("if [ \"$(uci get wireless.radio0.hwmode | grep -c a)\" -ne 0 ]; then echo \"client0\"; elif [ \"$(uci get wireless.radio1.hwmode | grep -c a)\" -ne 0 ]; then echo \"client1\"; fi", ssh.SSHResultToStringHandler(func(ip string, iface string, err error) {
- if err != nil {
- return
- }
- addr := net.TCPAddr{IP: net.ParseIP(ip), Port: 22}
- result, err := c.sshMgmt.RunOn(addr, fmt.Sprintf("iwinfo %s assoclist | grep SNR", iface))
- if err != nil {
- return
- }
- for _, line := range strings.Split(result, "\n") {
- parts := strings.Fields(line)
- mac := parts[0]
- db, err := strconv.Atoi(parts[1])
- if err != nil {
- return
- }
-
- c.no24Ghz[mac] = true
-
- if db < maxDB {
-
- node, ok := c.node[ip]
- if !ok {
- node = make(map[string]time.Time)
- c.node[ip] = node
- }
-
- now := time.Now()
-
- if last, ok := node[mac]; ok && last.After(now.Add(-3*time.Second)) {
- continue
- }
- log.Log.Info("force roamed %s from %s", mac, addr)
- cmd := fmt.Sprintf("ubus call hostapd.%s del_client '{\"addr\":\"%s\", \"reason\":1, \"deauth\":true, \"ban_time\":1000}'", iface, mac)
- c.sshMgmt.ExecuteOn(addr, cmd)
- node[mac] = now
-
- }
- }
-
- }))
-
- c.sshMgmt.RunEverywhere("if [ \"$(uci get wireless.radio0.hwmode | grep -c g)\" -ne 0 ]; then echo \"client0\"; elif [ \"$(uci get wireless.radio1.hwmode | grep -c g)\" -ne 0 ]; then echo \"client1\"; fi", ssh.SSHResultToStringHandler(func(ip string, iface string, err error) {
- if err != nil {
- return
- }
- addr := net.TCPAddr{IP: net.ParseIP(ip), Port: 22}
- result, err := c.sshMgmt.RunOn(addr, fmt.Sprintf("iwinfo %s assoclist | grep SNR", iface))
- if err != nil {
- return
- }
- for _, line := range strings.Split(result, "\n") {
- parts := strings.Fields(line)
- mac := parts[0]
- db, err := strconv.Atoi(parts[1])
- if err != nil {
- return
- }
-
- cmd := fmt.Sprintf("ubus call hostapd.%s del_client '{\"addr\":\"%s\", \"reason\":1, \"deauth\":true, \"ban_time\":1000}'", iface, mac)
-
- if c.no24Ghz[mac] {
- log.Log.Info("kicked becouse it use 2.4 Ghz %s from %s", mac, addr)
- c.sshMgmt.ExecuteOn(addr, cmd)
- }
-
- if db < maxDB {
-
- node, ok := c.node[ip]
- if !ok {
- node = make(map[string]time.Time)
- c.node[ip] = node
- }
-
- now := time.Now()
-
- if last, ok := node[mac]; ok && last.After(now.Add(-3*time.Second)) {
- continue
- }
- log.Log.Info("force roamed %s from %s", mac, addr)
- c.sshMgmt.ExecuteOn(addr, cmd)
- node[mac] = now
-
- }
- }
-
- }))
-}
diff --git a/cmd/freifunkmanager/main.go b/main.go
similarity index 53%
rename from cmd/freifunkmanager/main.go
rename to main.go
index 9508d6f..1bbd947 100644
--- a/cmd/freifunkmanager/main.go
+++ b/main.go
@@ -8,68 +8,70 @@ import (
"syscall"
"time"
- yanic "github.com/FreifunkBremen/yanic/database/socket/client"
- runtimeYanic "github.com/FreifunkBremen/yanic/runtime"
"github.com/NYTimes/gziphandler"
+ "github.com/genofire/golang-lib/file"
httpLib "github.com/genofire/golang-lib/http"
- "github.com/genofire/golang-lib/log"
"github.com/genofire/golang-lib/worker"
+ log "github.com/sirupsen/logrus"
+
+ respondYanic "github.com/FreifunkBremen/yanic/respond"
+ runtimeYanic "github.com/FreifunkBremen/yanic/runtime"
- configPackage "github.com/FreifunkBremen/freifunkmanager/config"
- wifiController "github.com/FreifunkBremen/freifunkmanager/controller"
"github.com/FreifunkBremen/freifunkmanager/runtime"
"github.com/FreifunkBremen/freifunkmanager/ssh"
"github.com/FreifunkBremen/freifunkmanager/websocket"
)
var (
- configFile string
- config *configPackage.Config
- nodes *runtime.Nodes
- commands *runtime.Commands
- yanicDialer *yanic.Dialer
- stats *runtimeYanic.GlobalStats
+ configFile string
+ config = &runtime.Config{}
+ nodes *runtime.Nodes
+ collector *respondYanic.Collector
+ verbose bool
)
func main() {
flag.StringVar(&configFile, "config", "config.conf", "path of configuration file (default:config.conf)")
+ flag.BoolVar(&verbose, "v", false, "verbose logging")
flag.Parse()
+ if verbose {
+ log.SetLevel(log.DebugLevel)
+ }
- config = configPackage.ReadConfigFile(configFile)
+ if err := file.ReadTOML(configFile, config); err != nil {
+ log.Panicf("Error during read config: %s", err)
+ }
- log.Log.Info("starting...")
+ log.Info("starting...")
sshmanager := ssh.NewManager(config.SSHPrivateKey)
nodes = runtime.NewNodes(config.StatePath, config.SSHInterface, sshmanager)
- commands = runtime.NewCommands(sshmanager)
- // nodesUpdateWorker := worker.NewWorker(time.Duration(3)*time.Minute, nodes.Updater)
nodesSaveWorker := worker.NewWorker(time.Duration(3)*time.Second, nodes.Saver)
- controller := wifiController.NewController(sshmanager)
+ nodesUpdateWorker := worker.NewWorker(time.Duration(3)*time.Minute, nodes.Updater)
+ nodesYanic := runtimeYanic.NewNodes(&runtimeYanic.NodesConfig{})
- // go nodesUpdateWorker.Start()
+ db := runtime.NewYanicDB(nodes)
go nodesSaveWorker.Start()
- go controller.Start()
+ go nodesUpdateWorker.Start()
- websocket.Start(nodes, commands)
+ websocket.Start(nodes)
+ db.NotifyStats = websocket.NotifyStats
if config.Yanic.Enable {
- yanicDialer = yanic.Dial(config.Yanic.Type, config.Yanic.Address)
- yanicDialer.NodeHandler = nodes.LearnNode
- yanicDialer.GlobalsHandler = func(data *runtimeYanic.GlobalStats) {
- stats = data
- websocket.NotifyStats(data)
- }
- go yanicDialer.Start()
+ collector = respondYanic.NewCollector(db, nodesYanic, make(map[string][]string), []respondYanic.InterfaceConfig{respondYanic.InterfaceConfig{
+ InterfaceName: config.Yanic.InterfaceName,
+ IPAddress: config.Yanic.Address,
+ Port: config.Yanic.Port,
+ }})
+ defer collector.Close()
}
// Startwebserver
http.HandleFunc("/nodes", func(w http.ResponseWriter, r *http.Request) {
httpLib.Write(w, nodes)
- log.HTTP(r).Info("done")
})
http.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
- httpLib.Write(w, stats)
- log.HTTP(r).Info("done")
+ httpLib.Write(w, db.Statistics)
})
http.Handle("/", gziphandler.GzipHandler(http.FileServer(http.Dir(config.Webroot))))
@@ -79,27 +81,26 @@ func main() {
go func() {
if err := srv.ListenAndServe(); err != nil {
- log.Log.Panic(err)
+ log.Panic(err)
}
}()
- log.Log.Info("started")
+ log.Info("started")
// Wait for system signal
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
sig := <-sigs
- // Stop services
websocket.Close()
+
+ // Stop services
srv.Close()
- controller.Close()
if config.Yanic.Enable {
- yanicDialer.Close()
+ collector.Close()
}
nodesSaveWorker.Close()
- // nodesUpdateWorker.Close()
- sshmanager.Close()
+ nodesUpdateWorker.Close()
- log.Log.Info("stop recieve:", sig)
+ log.Info("stop recieve:", sig)
}
diff --git a/runtime/cmd.go b/runtime/cmd.go
deleted file mode 100644
index da17c7b..0000000
--- a/runtime/cmd.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package runtime
-
-import (
- "time"
-
- "github.com/FreifunkBremen/freifunkmanager/ssh"
-)
-
-type Commands struct {
- List map[string]*Command
- mgmt *ssh.Manager
-}
-
-type Command struct {
- ssh.List
- Timestemp time.Time `json:"timestemp"`
- ID string `json:"id"`
-}
-
-func NewCommands(mgmt *ssh.Manager) *Commands {
- return &Commands{
- mgmt: mgmt,
- List: make(map[string]*Command),
- }
-}
-
-func (cmds *Commands) AddCommand(c *Command) *Command {
- cmd := mapCommand(cmds.mgmt, c)
- cmds.List[cmd.ID] = cmd
- return cmd
-}
-
-func mapCommand(mgmt *ssh.Manager, c *Command) *Command {
- list := mgmt.CreateList(c.Command)
- command := &Command{List: *list}
- command.ID = c.ID
- command.Timestemp = c.Timestemp
- return command
-}
-
-func (cmd *Command) Run(f func()) {
- cmd.List.Run()
- f()
-}
diff --git a/config/main.go b/runtime/config.go
similarity index 50%
rename from config/main.go
rename to runtime/config.go
index 153607f..4718581 100644
--- a/config/main.go
+++ b/runtime/config.go
@@ -1,19 +1,12 @@
-package config
-
-import (
- "io/ioutil"
-
- "github.com/BurntSushi/toml"
- "github.com/genofire/golang-lib/log"
-)
+package runtime
//config file of this daemon (for more the config_example.conf in git repository)
type Config struct {
// prevent crashes
StatePath string `toml:"state_path"`
+
// address on which the api and static content webserver runs
WebserverBind string `toml:"webserver_bind"`
-
// path to deliver static content
Webroot string `toml:"webroot"`
@@ -23,23 +16,9 @@ type Config struct {
// yanic socket
Yanic struct {
- Enable bool `toml:"enable"`
- Type string `toml:"type"`
- Address string `toml:"address"`
+ Enable bool `toml:"enable"`
+ InterfaceName string `toml:"ifname"`
+ Address string `toml:"address"`
+ Port int `toml:"port"`
} `toml:"yanic"`
}
-
-//reads a config model from path of a yml file
-func ReadConfigFile(path string) *Config {
- config := &Config{}
- file, err := ioutil.ReadFile(path)
- if err != nil {
- log.Log.Panic(err)
- }
-
- if err := toml.Unmarshal(file, config); err != nil {
- log.Log.Panic(err)
- }
-
- return config
-}
diff --git a/runtime/node.go b/runtime/node.go
index 57d1255..4279f27 100644
--- a/runtime/node.go
+++ b/runtime/node.go
@@ -5,10 +5,10 @@ import (
"fmt"
"net"
- "github.com/genofire/golang-lib/log"
+ log "github.com/sirupsen/logrus"
- "github.com/FreifunkBremen/yanic/data"
- "github.com/FreifunkBremen/yanic/jsontime"
+ yanicData "github.com/FreifunkBremen/yanic/data"
+ "github.com/FreifunkBremen/yanic/lib/jsontime"
yanicRuntime "github.com/FreifunkBremen/yanic/runtime"
"github.com/FreifunkBremen/freifunkmanager/ssh"
@@ -23,16 +23,16 @@ const (
)
type Node struct {
- Lastseen jsontime.Time `json:"lastseen"`
- NodeID string `json:"node_id"`
- Hostname string `json:"hostname"`
- Location data.Location `json:"location"`
- Wireless data.Wireless `json:"wireless"`
- Owner string `json:"owner"`
- Address net.IP `json:"-"`
+ Lastseen jsontime.Time `json:"lastseen"`
+ NodeID string `json:"node_id"`
+ Hostname string `json:"hostname"`
+ Location yanicData.Location `json:"location"`
+ Wireless yanicData.Wireless `json:"wireless"`
+ Owner string `json:"owner"`
+ Address net.IP `json:"-"`
Stats struct {
- Wireless data.WirelessStatistics `json:"wireless"`
- Clients data.Clients `json:"clients"`
+ Wireless yanicData.WirelessStatistics `json:"wireless"`
+ Clients yanicData.Clients `json:"clients"`
} `json:"statistics"`
}
@@ -41,7 +41,12 @@ func NewNode(nodeOrigin *yanicRuntime.Node) *Node {
node := &Node{
Hostname: nodeinfo.Hostname,
NodeID: nodeinfo.NodeID,
- Address: nodeOrigin.Address,
+ }
+ for _, ip := range nodeinfo.Network.Addresses {
+ ipAddr := net.ParseIP(ip)
+ if node.Address == nil || ipAddr.IsGlobalUnicast() {
+ node.Address = ipAddr
+ }
}
if owner := nodeinfo.Owner; owner != nil {
node.Owner = owner.Contact
@@ -71,14 +76,14 @@ func (n *Node) SSHUpdate(ssh *ssh.Manager, iface string, oldnode *Node) {
ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateOwner, n.Owner))
}
if oldnode == nil || !locationEqual(n.Location, oldnode.Location) {
- ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateLocation, n.Location.Latitude, n.Location.Longtitude))
+ ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateLocation, n.Location.Latitude, n.Location.Longitude))
}
if oldnode == nil || !wirelessEqual(n.Wireless, oldnode.Wireless) {
ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateWifiFreq24, n.Wireless.Channel24, n.Wireless.TxPower24, n.Wireless.Channel24, n.Wireless.TxPower24))
ssh.ExecuteOn(addr, fmt.Sprintf(SSHUpdateWifiFreq5, n.Wireless.Channel5, n.Wireless.TxPower5, n.Wireless.Channel5, n.Wireless.TxPower5))
ssh.ExecuteOn(addr, "wifi")
// send warning for running wifi, because it kicks clients from node
- log.Log.Warn("[cmd] wifi ", n.NodeID)
+ log.Warn("[cmd] wifi ", n.NodeID)
}
oldnode = n
}
@@ -89,7 +94,7 @@ 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
+ n.Address = node.Address.IP
if owner := nodeinfo.Owner; owner != nil {
n.Owner = owner.Contact
@@ -124,11 +129,11 @@ func (n *Node) IsEqual(node *Node) bool {
return true
}
-func locationEqual(a, b data.Location) bool {
+func locationEqual(a, b yanicData.Location) bool {
if a.Latitude != b.Latitude {
return false
}
- if a.Longtitude != b.Longtitude {
+ if a.Longitude != b.Longitude {
return false
}
if a.Altitude != b.Altitude {
@@ -137,7 +142,7 @@ func locationEqual(a, b data.Location) bool {
return true
}
-func wirelessEqual(a, b data.Wireless) bool {
+func wirelessEqual(a, b yanicData.Wireless) bool {
if a.Channel24 != b.Channel24 {
return false
}
diff --git a/runtime/node_test.go b/runtime/node_test.go
index 010ae0f..9cbb4ec 100644
--- a/runtime/node_test.go
+++ b/runtime/node_test.go
@@ -1,24 +1,27 @@
package runtime
import (
+ "net"
"testing"
"github.com/stretchr/testify/assert"
- "github.com/FreifunkBremen/yanic/data"
+ yanicData "github.com/FreifunkBremen/yanic/data"
yanicRuntime "github.com/FreifunkBremen/yanic/runtime"
)
func TestNode(t *testing.T) {
assert := assert.New(t)
- node1 := &yanicRuntime.Node{}
+ node1 := &yanicRuntime.Node{
+ Address: &net.UDPAddr{IP: net.ParseIP("ff02::1")},
+ }
n1 := NewNode(node1)
assert.Nil(n1)
- node1.Nodeinfo = &data.NodeInfo{
- Owner: &data.Owner{Contact: "blub"},
- Wireless: &data.Wireless{},
- Location: &data.Location{Altitude: 13},
+ node1.Nodeinfo = &yanicData.NodeInfo{
+ Owner: &yanicData.Owner{Contact: "blub"},
+ Wireless: &yanicData.Wireless{},
+ Location: &yanicData.Location{Altitude: 13},
}
n1 = NewNode(node1)
assert.NotNil(n1)
diff --git a/runtime/nodes.go b/runtime/nodes.go
index df0a4a6..2f8dabe 100644
--- a/runtime/nodes.go
+++ b/runtime/nodes.go
@@ -1,13 +1,13 @@
package runtime
import (
- "encoding/json"
- "os"
"sync"
- "github.com/FreifunkBremen/yanic/jsontime"
- yanic "github.com/FreifunkBremen/yanic/runtime"
- "github.com/genofire/golang-lib/log"
+ "github.com/FreifunkBremen/yanic/lib/jsontime"
+ log "github.com/sirupsen/logrus"
+
+ yanicRuntime "github.com/FreifunkBremen/yanic/runtime"
+ "github.com/genofire/golang-lib/file"
"github.com/FreifunkBremen/freifunkmanager/ssh"
)
@@ -30,17 +30,17 @@ func NewNodes(path string, iface string, mgmt *ssh.Manager) *Nodes {
statePath: path,
iface: iface,
}
- nodes.load()
+ file.ReadJSON(path, nodes)
return nodes
}
-func (nodes *Nodes) LearnNode(n *yanic.Node) {
+func (nodes *Nodes) LearnNode(n *yanicRuntime.Node) {
node := NewNode(n)
if node == nil {
return
}
node.Lastseen = jsontime.Now()
- logger := log.Log.WithField("method", "LearnNode").WithField("node_id", node.NodeID)
+ logger := log.WithField("method", "LearnNode").WithField("node_id", node.NodeID)
nodes.Lock()
defer nodes.Unlock()
if lNode := nodes.List[node.NodeID]; lNode != nil {
@@ -83,7 +83,7 @@ func (nodes *Nodes) notify(node *Node, system bool) {
func (nodes *Nodes) UpdateNode(node *Node) {
if node == nil {
- log.Log.Warn("no new node to update")
+ log.Warn("no new node to update")
return
}
nodes.Lock()
@@ -91,7 +91,7 @@ func (nodes *Nodes) UpdateNode(node *Node) {
if n, ok := nodes.List[node.NodeID]; ok {
node.Address = n.Address
go node.SSHUpdate(nodes.ssh, nodes.iface, n)
- log.Log.Info("update node", node.NodeID)
+ log.Info("update node", node.NodeID)
}
nodes.List[node.NodeID] = node
nodes.notify(node, true)
@@ -105,24 +105,12 @@ func (nodes *Nodes) Updater() {
go node.SSHUpdate(nodes.ssh, nodes.iface, n)
}
}
- log.Log.Info("updater per ssh")
-}
-
-func (nodes *Nodes) load() {
- if f, err := os.Open(nodes.statePath); err == nil {
- if err = json.NewDecoder(f).Decode(nodes); err == nil {
- log.Log.Infof("loaded %d nodes", len(nodes.List))
- } else {
- log.Log.Error("failed to unmarshal nodes:", err)
- }
- } else {
- log.Log.Error("failed to load cached nodes:", err)
- }
+ log.Info("updater per ssh")
}
func (nodes *Nodes) Saver() {
nodes.Lock()
- yanic.SaveJSON(nodes, nodes.statePath)
+ file.SaveJSON(nodes.statePath, nodes)
nodes.Unlock()
- log.Log.Debug("saved state file")
+ log.Debug("saved state file")
}
diff --git a/runtime/yanic.go b/runtime/yanic.go
new file mode 100644
index 0000000..a1ba5c4
--- /dev/null
+++ b/runtime/yanic.go
@@ -0,0 +1,41 @@
+package runtime
+
+import (
+ "time"
+
+ databaseYanic "github.com/FreifunkBremen/yanic/database"
+ runtimeYanic "github.com/FreifunkBremen/yanic/runtime"
+)
+
+type YanicDB struct {
+ databaseYanic.Connection
+ nodes *Nodes
+ Statistics *runtimeYanic.GlobalStats
+ NotifyStats func(data *runtimeYanic.GlobalStats)
+}
+
+func NewYanicDB(nodes *Nodes) *YanicDB {
+ return &YanicDB{
+ nodes: nodes,
+ }
+}
+
+func (conn *YanicDB) InsertNode(node *runtimeYanic.Node) {
+ conn.nodes.LearnNode(node)
+}
+
+func (conn *YanicDB) InsertLink(link *runtimeYanic.Link, time time.Time) {
+}
+
+func (conn *YanicDB) InsertGlobals(stats *runtimeYanic.GlobalStats, time time.Time, site string, domain string) {
+ conn.Statistics = stats
+ if conn.NotifyStats != nil {
+ conn.NotifyStats(stats)
+ }
+}
+
+func (conn *YanicDB) PruneNodes(deleteAfter time.Duration) {
+}
+
+func (conn *YanicDB) Close() {
+}
diff --git a/ssh/execute.go b/ssh/execute.go
index 6a7008b..253b8c1 100644
--- a/ssh/execute.go
+++ b/ssh/execute.go
@@ -3,23 +3,17 @@ package ssh
import (
"net"
- "github.com/genofire/golang-lib/log"
+ log "github.com/sirupsen/logrus"
+
"golang.org/x/crypto/ssh"
)
-func (m *Manager) ExecuteEverywhere(cmd string) {
- m.clientsMUX.Lock()
- defer m.clientsMUX.Unlock()
- for host, client := range m.clients {
- m.execute(host, client, cmd)
- }
-}
-
func (m *Manager) ExecuteOn(addr net.TCPAddr, cmd string) error {
client, err := m.ConnectTo(addr)
if err != nil {
return err
}
+ defer client.Close()
return m.execute(addr.IP.String(), client, cmd)
}
@@ -27,14 +21,9 @@ func (m *Manager) execute(host string, client *ssh.Client, cmd string) error {
session, err := client.NewSession()
defer session.Close()
- if err != nil {
- log.Log.Warnf("can not create session on %s: %s", host, err)
- delete(m.clients, host)
- return err
- }
err = session.Run(cmd)
if err != nil {
- log.Log.Warnf("could not run %s on %s: %s", cmd, host, err)
+ log.Warnf("could not run %s on %s: %s", cmd, host, err)
return err
}
return nil
diff --git a/ssh/execute_test.go b/ssh/execute_test.go
index f70f16b..ebf13f6 100644
--- a/ssh/execute_test.go
+++ b/ssh/execute_test.go
@@ -15,10 +15,9 @@ func TestExecute(t *testing.T) {
mgmt := NewManager("~/.ssh/id_rsa")
assert.NotNil(mgmt, "no new manager created")
- _, err := mgmt.ConnectTo(addr)
+ client, err := mgmt.ConnectTo(addr)
assert.NoError(err)
- mgmt.ExecuteEverywhere("echo $HOSTNAME")
err = mgmt.ExecuteOn(addr, "uptime")
assert.NoError(err)
err = mgmt.ExecuteOn(addr, "echo $HOSTNAME")
@@ -26,5 +25,5 @@ func TestExecute(t *testing.T) {
err = mgmt.ExecuteOn(addr, "exit 1")
assert.Error(err)
- mgmt.Close()
+ client.Close()
}
diff --git a/ssh/list.go b/ssh/list.go
deleted file mode 100644
index 7aa0c10..0000000
--- a/ssh/list.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package ssh
-
-import (
- "sync"
-
- "golang.org/x/crypto/ssh"
-)
-
-type List struct {
- Command string `json:"cmd"`
- Clients map[string]*ListResult `json:"clients"`
- sshManager *Manager
- sync.Mutex
-}
-type ListResult struct {
- ssh *ssh.Client
- Running bool `json:"running"`
- WithError bool `json:"with_error"`
- Result string `json:"result"`
-}
-
-func (m *Manager) CreateList(cmd string) *List {
- list := &List{
- Command: cmd,
- sshManager: m,
- Clients: make(map[string]*ListResult),
- }
- m.clientsMUX.Lock()
- defer m.clientsMUX.Unlock()
- for host, client := range m.clients {
- list.Clients[host] = &ListResult{Running: true, ssh: client}
- }
- return list
-}
-
-func (l List) Run() {
- wg := new(sync.WaitGroup)
- for host, client := range l.Clients {
- wg.Add(1)
- go l.runlistelement(host, client, wg)
-
- }
- wg.Wait()
-}
-
-func (l List) runlistelement(host string, client *ListResult, wg *sync.WaitGroup) {
- defer wg.Done()
- result, err := l.sshManager.run(host, client.ssh, l.Command)
-
- l.Lock()
- defer l.Unlock()
-
- client.Running = false
- if err != nil {
- client.WithError = true
- return
- }
- client.Result = SSHResultToString(result)
-}
diff --git a/ssh/list_test.go b/ssh/list_test.go
deleted file mode 100644
index 30bc73f..0000000
--- a/ssh/list_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package ssh
-
-import (
- "net"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestList(t *testing.T) {
- assert := assert.New(t)
- addr := net.TCPAddr{IP: net.ParseIP("2a06:8782:ffbb:1337::127"), Port: 22}
-
- mgmt := NewManager("~/.ssh/id_rsa")
- assert.NotNil(mgmt, "no new manager created")
- _, err := mgmt.ConnectTo(addr)
- assert.NoError(err)
-
- list := mgmt.CreateList("exit 1")
- assert.Len(list.Clients, 1)
- client := list.Clients[addr.IP.String()]
- assert.True(client.Running)
- list.Run()
- assert.False(client.Running)
- assert.True(client.WithError)
- assert.Equal("", client.Result)
-
- list = mgmt.CreateList("echo 15")
- assert.Len(list.Clients, 1)
- client = list.Clients[addr.IP.String()]
- assert.True(client.Running)
- list.Run()
- assert.False(client.Running)
- assert.False(client.WithError)
- assert.Equal("15", client.Result)
-}
diff --git a/ssh/manager.go b/ssh/manager.go
index 6690ff2..710a07f 100644
--- a/ssh/manager.go
+++ b/ssh/manager.go
@@ -7,14 +7,13 @@ import (
"sync"
"time"
- "github.com/genofire/golang-lib/log"
+ log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
)
// the SSH Connection Manager for multiple connections
type Manager struct {
config *ssh.ClientConfig
- clients map[string]*ssh.Client
clientsBlacklist map[string]time.Time
clientsMUX sync.Mutex
}
@@ -36,7 +35,6 @@ func NewManager(file string) *Manager {
}
return &Manager{
config: sshConfig,
- clients: make(map[string]*ssh.Client),
clientsBlacklist: make(map[string]time.Time),
}
}
@@ -52,27 +50,15 @@ func (m *Manager) ConnectTo(addr net.TCPAddr) (*ssh.Client, error) {
}
}
- if client, ok := m.clients[addr.IP.String()]; ok {
- return client, nil
- }
-
client, err := ssh.Dial("tcp", addr.String(), m.config)
if err != nil {
if strings.Contains(err.Error(), "no supported methods remain") {
m.clientsBlacklist[addr.IP.String()] = time.Now()
- log.Log.Warnf("node was set on the blacklist: %s", err)
+ log.Warnf("node was set on the blacklist: %s", err)
return nil, errors.New("node on blacklist")
}
return nil, err
}
- m.clients[addr.IP.String()] = client
return client, nil
}
-
-func (m *Manager) Close() {
- for host, client := range m.clients {
- client.Close()
- delete(m.clients, host)
- }
-}
diff --git a/ssh/manager_test.go b/ssh/manager_test.go
index 85be983..1d7fed2 100644
--- a/ssh/manager_test.go
+++ b/ssh/manager_test.go
@@ -13,7 +13,6 @@ func TestManager(t *testing.T) {
mgmt := NewManager("~/.ssh/id_rsa")
assert.NotNil(mgmt, "no new manager created")
- mgmt.ConnectTo(net.TCPAddr{IP: net.ParseIP("2a06:8782:ffbb:1337::127"), Port: 22})
-
- mgmt.Close()
+ client, _ := mgmt.ConnectTo(net.TCPAddr{IP: net.ParseIP("2a06:8782:ffbb:1337::127"), Port: 22})
+ client.Close()
}
diff --git a/ssh/run.go b/ssh/run.go
index 2cdf030..e4365db 100644
--- a/ssh/run.go
+++ b/ssh/run.go
@@ -4,7 +4,7 @@ import (
"bytes"
"net"
- "github.com/genofire/golang-lib/log"
+ log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
)
@@ -23,22 +23,12 @@ func SSHResultToStringHandler(handler SSHResultHandler) SSHResultHandler {
}
}
-func (m *Manager) RunEverywhere(cmd string, handler SSHResultHandler) {
- m.clientsMUX.Lock()
- defer m.clientsMUX.Unlock()
- for host, client := range m.clients {
- go func() {
- result, err := m.run(host, client, cmd)
- handler(host, result, err)
- }()
- }
-}
-
func (m *Manager) RunOn(addr net.TCPAddr, cmd string) (string, error) {
client, err := m.ConnectTo(addr)
if err != nil {
return "", err
}
+ defer client.Close()
return m.run(addr.IP.String(), client, cmd)
}
@@ -47,22 +37,18 @@ func (m *Manager) run(host string, client *ssh.Client, cmd string) (string, erro
defer session.Close()
if err != nil {
- log.Log.Warnf("can not create session on %s: %s", host, err)
- m.clientsMUX.Lock()
- delete(m.clients, host)
- m.clientsMUX.Unlock()
+ log.Warnf("can not create session on %s: %s", host, err)
return "", err
}
buffer := &bytes.Buffer{}
session.Stdout = buffer
if err != nil {
- log.Log.Warnf("can not create pipe for run on %s: %s", host, err)
- delete(m.clients, host)
+ log.Warnf("can not create pipe for run on %s: %s", host, err)
return "", err
}
err = session.Run(cmd)
if err != nil {
- log.Log.Debugf("could not run %s on %s: %s", cmd, host, err)
+ log.Debugf("could not run %s on %s: %s", cmd, host, err)
return "", err
}
return buffer.String(), nil
diff --git a/ssh/run_test.go b/ssh/run_test.go
index 3026631..54f78ac 100644
--- a/ssh/run_test.go
+++ b/ssh/run_test.go
@@ -14,14 +14,10 @@ func TestRun(t *testing.T) {
mgmt := NewManager("~/.ssh/id_rsa")
assert.NotNil(mgmt, "no new manager created")
- _, err := mgmt.ConnectTo(addr)
+ client, err := mgmt.ConnectTo(addr)
assert.NoError(err)
+ client.Close()
- mgmt.RunEverywhere("echo 13", SSHResultToStringHandler(func(result string, err error) {
- assert.NoError(err)
-
- assert.Equal("13", result)
- }))
result, err := mgmt.RunOn(addr, "echo 16")
assert.NoError(err)
@@ -29,6 +25,4 @@ func TestRun(t *testing.T) {
resultInt, _ := strconv.Atoi(str)
assert.Equal(16, resultInt)
-
- mgmt.Close()
}
diff --git a/vendor/github.com/FreifunkBremen/yanic b/vendor/github.com/FreifunkBremen/yanic
deleted file mode 160000
index 7978107..0000000
--- a/vendor/github.com/FreifunkBremen/yanic
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 79781076be6e810eff663064cf68295e7f6e6487
diff --git a/webroot/index.html b/webroot/index.html
index 0d957a6..7f5302f 100644
--- a/webroot/index.html
+++ b/webroot/index.html
@@ -24,7 +24,6 @@
-
diff --git a/webroot/js/gui.js b/webroot/js/gui.js
index efe1b94..1d0ce4d 100644
--- a/webroot/js/gui.js
+++ b/webroot/js/gui.js
@@ -1,5 +1,5 @@
/* exported gui,router */
-/* globals socket,notify,domlib,guiList,guiMap,guiStats,guiNode,guiConsole */
+/* globals socket,notify,domlib,guiList,guiMap,guiStats,guiNode */
const gui = {},
router = new Navigo(null, true, '#');
@@ -58,9 +58,6 @@ const gui = {},
}
router.on({
- '/console': function routerConsole () {
- setView(guiConsole);
- },
'/list': function routerList () {
setView(guiList);
},
diff --git a/webroot/js/gui_console.js b/webroot/js/gui_console.js
deleted file mode 100644
index d485b7a..0000000
--- a/webroot/js/gui_console.js
+++ /dev/null
@@ -1,277 +0,0 @@
-/* exported guiConsole */
-/* globals domlib,store,socket */
-const guiConsole = {};
-
-(function init () {
- 'use strict';
-
- const view = guiConsole,
- ownCMDs = ['0'],
- cmdRow = {};
- let container = null,
- el = null,
- output = null,
- editing = false,
- ownfilter = false;
-
- function createID () {
- let digit = new Date().getTime();
-
- // Use high-precision timer if available
- /* eslint-disable */
- if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
- digit += performance.now();
- }
-
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (char) => {
- const result = (digit + Math.random() * 16) % 16 | 0;
-
- digit = Math.floor(digit / 16);
-
- return (char === 'x'
- ? result
- : result & 0x3 | 0x8).toString(16);
- });
- /* eslint-enable*/
- }
-
- function updateCMD (row, cmd) {
- if (cmd.cmd === '' && cmd.timestemp === 0) {
- return;
- }
- row.cmd.innerHTML = cmd.cmd;
- row.timestemp.innerHTML = moment(cmd.timestemp).fromNow(true);
-
- let running = 0,
- failed = 0,
- sum = 0;
-
- if (cmd.clients) {
- sum = Object.keys(cmd.clients).length;
-
- Object.keys(cmd.clients).forEach((addr) => {
- const client = cmd.clients[addr],
- clientRow = row.clients[addr];
-
- clientRow.status.classList.remove('running', 'failed', 'success');
- if (client.running) {
- running += 1;
- clientRow.status.classList.add('running');
- } else if (client.with_error) {
- failed += 1;
- clientRow.status.classList.add('failed');
- } else {
- clientRow.status.classList.add('success');
- }
-
- clientRow.result.innerHTML = client.result;
- clientRow.host.innerHTML = addr;
- });
- }
-
- row.status.classList.remove('running', 'failed', 'success');
- if (running > 0) {
- row.status.innerHTML = `running (${running}`;
- row.status.classList.add('running');
- } else if (failed > 0 || sum === 0) {
- row.status.innerHTML = `failed (${failed}`;
- row.status.classList.add('failed');
- } else {
- row.status.innerHTML = `success (${sum}`;
- row.status.classList.add('success');
- }
- row.status.innerHTML += `/${sum})`;
- }
-
- function createRow (cmd) {
- const row = {
- 'clients': {},
- 'clientsContainer': document.createElement('tr'),
- 'clientsEl': {},
- 'el': document.createElement('tr')
- },
- tab = domlib.newAt(row.clientsContainer, 'td'),
- clientRow = domlib.newAt(tab, 'table');
-
- tab.setAttribute('colspan', '3');
-
-
- if (cmd.cmd === '' && cmd.timestemp === 0) {
- const initRow = domlib.newAt(row.el, 'td');
-
- initRow.setAttribute('colspan', '3');
- initRow.innerHTML = '\n' +
- ' _______ ________ __\n' +
- ' | |.-----.-----.-----.| | | |.----.| |_\n' +
- ' | - || _ | -__| || | | || _|| _|\n' +
- ' |_______|| __|_____|__|__||________||__| |____|\n' +
- ' |__| W I R E L E S S F R E E D O M\n' +
- ' -----------------------------------------------------\n' +
- ' FreifunkManager shell for openwrt/Lede/gluon systems \n' +
- ' -----------------------------------------------------\n' +
- ' * 1 1/2 oz Gin Shake with a glassful\n' +
- ' * 1/4 oz Triple Sec of broken ice and pour\n' +
- ' * 3/4 oz Lime Juice unstrained into a goblet.\n' +
- ' * 1 1/2 oz Orange Juice\n' +
- ' * 1 tsp. Grenadine Syrup\n' +
- ' -----------------------------------------------------\n';
-
- return row;
- }
- row.timestemp = domlib.newAt(row.el, 'td');
- row.cmd = domlib.newAt(row.el, 'td');
- row.status = domlib.newAt(row.el, 'td');
-
- row.el.classList.add('cmd');
- row.timestemp.classList.add('time');
- row.status.classList.add('status');
-
- if (cmd.clients) {
- Object.keys(cmd.clients).forEach((addr) => {
- const clientEl = domlib.newAt(clientRow, 'tr'),
- clients = {
- 'host': domlib.newAt(clientEl, 'td'),
- 'result': domlib.newAt(clientEl, 'td'),
- 'status': domlib.newAt(clientEl, 'td')
- };
-
- clients.host.classList.add('host');
- clients.status.classList.add('status');
-
- row.clientsEl[addr] = clientEl;
- row.clients[addr] = clients;
- });
- row.el.addEventListener('click', () => {
- if (row.clientsContainer.parentElement) {
- row.el.parentElement.removeChild(row.clientsContainer);
- } else {
- row.el.parentElement.insertBefore(row.clientsContainer, row.el.nextSibling);
- }
- });
- }
-
-
- updateCMD(row, cmd);
-
- return row;
- }
-
- function update () {
- if (editing) {
- return;
- }
- let cmds = store.getCMDs();
-
- if (ownfilter) {
- const tmp = cmds;
-
- cmds = {};
- Object.keys(tmp).
- forEach((id) => {
- if (ownCMDs.indexOf(id) >= 0) {
- cmds[id] = tmp[id];
- }
- });
- }
- Object.keys(cmdRow).forEach((id) => {
- if (cmdRow[id].el.parentElement) {
- output.removeChild(cmdRow[id].el);
- }
- });
-
- Object.keys(cmds).forEach((id) => {
- const cmd = cmds[id];
-
- if (cmdRow[id]) {
- updateCMD(cmdRow[id], cmd);
- } else {
- cmdRow[id] = createRow(cmd);
- }
- });
-
- Object.keys(cmdRow).
- sort((aID, bID) => {
- if (!cmds[aID] || !cmds[bID]) {
- return 0;
- }
-
- return new Date(cmds[aID].timestemp) - new Date(cmds[bID].timestemp);
- }).
- forEach((id) => {
- if (cmds[id] && !cmdRow[id].el.parentElement) {
- output.appendChild(cmdRow[id].el);
- if (cmdRow[id].clientsContainer.parentElement) {
- cmdRow[id].el.parentElement.insertBefore(cmdRow[id].clientsContainer, cmdRow[id].el.nextSibling);
- }
- }
- });
- }
-
- view.bind = function bind (bindEl) {
- container = bindEl;
- };
- view.render = function render () {
- if (!container) {
- return;
- } else if (el) {
- container.appendChild(el);
- update();
-
- return;
- }
- console.log('generate new view for console');
- el = domlib.newAt(container, 'div');
-
- store.updateCMD({
- 'cmd': '',
- 'id': '0',
- 'timestemp': 0
- });
-
- output = domlib.newAt(el, 'table');
- output.classList.add('console');
-
- const prompt = domlib.newAt(el, 'div'),
- filterBtn = domlib.newAt(prompt, 'span'),
- promptInput = domlib.newAt(prompt, 'input');
-
- prompt.classList.add('prompt');
-
- promptInput.addEventListener('keyup', (event) => {
- // eslint-disable-next-line no-magic-numbers
- if (event.keyCode !== 13) {
- return;
- }
- const cmd = {
- 'cmd': promptInput.value,
- 'id': createID(),
- 'timestemp': new Date()
- };
-
- ownCMDs.push(cmd.id);
- socket.sendcmd(cmd);
- promptInput.value = '';
- });
- promptInput.addEventListener('focusin', () => {
- editing = true;
- });
- promptInput.addEventListener('focusout', () => {
- editing = false;
- update();
- });
-
- filterBtn.classList.add('btn');
- filterBtn.innerHTML = 'Show all';
- filterBtn.addEventListener('click', () => {
- ownfilter = !ownfilter;
- filterBtn.classList.toggle('active');
- filterBtn.innerHTML = ownfilter
- ? 'Show own'
- : 'Show all';
- update();
- });
-
-
- update();
- };
-})();
diff --git a/websocket/client.go b/websocket/client.go
index b884595..ce419a0 100644
--- a/websocket/client.go
+++ b/websocket/client.go
@@ -2,10 +2,8 @@ package websocket
import (
"io"
- "time"
- "github.com/genofire/golang-lib/log"
- "github.com/genofire/golang-lib/worker"
+ log "github.com/sirupsen/logrus"
"golang.org/x/net/websocket"
)
@@ -22,7 +20,7 @@ type Client struct {
func NewClient(ip string, ws *websocket.Conn) *Client {
if ws == nil {
- log.Log.Panic("ws cannot be nil")
+ log.Panic("ws cannot be nil")
}
return &Client{
@@ -41,14 +39,14 @@ func (c *Client) Write(msg *Message) {
clientsMutex.Lock()
delete(clients, c.ip)
clientsMutex.Unlock()
- log.HTTP(c.ws.Request()).Error("client disconnected")
+ log.Error("client disconnected")
}
}
func (c *Client) Close() {
c.writeQuit <- true
c.readQuit <- true
- log.HTTP(c.ws.Request()).Info("client disconnecting...")
+ log.Info("client disconnecting...")
}
// Listen Write and Read request via chanel
@@ -68,11 +66,6 @@ func (c *Client) publishAllData() {
for _, node := range nodes.Current {
c.Write(&Message{Type: MessageTypeCurrentNode, Node: node})
}
- if commands != nil {
- for _, cmd := range commands.List {
- c.Write(&Message{Type: MessageTypeCommand, Command: cmd})
- }
- }
}
func (c *Client) handleMessage(msg *Message) {
@@ -80,22 +73,6 @@ func (c *Client) handleMessage(msg *Message) {
case MessageTypeSystemNode:
nodes.UpdateNode(msg.Node)
break
- case MessageTypeCommand:
- if commands == nil {
- break
- }
- cmd := commands.AddCommand(msg.Command)
- w := worker.NewWorker(time.Millisecond*300, func() {
- cmd.Lock()
- SendAll(Message{Type: MessageTypeCommand, Command: cmd})
- cmd.Unlock()
- })
- go w.Start()
- go cmd.Run(func() {
- w.Close()
- SendAll(Message{Type: MessageTypeCommand, Command: cmd})
- })
- break
}
}
@@ -137,7 +114,7 @@ func (c *Client) listenRead() {
c.writeQuit <- true
return
} else if err != nil {
- log.HTTP(c.ws.Request()).Error(err)
+ log.Error(err)
} else {
c.handleMessage(&msg)
}
diff --git a/websocket/msg.go b/websocket/msg.go
index bd755dc..b655f29 100644
--- a/websocket/msg.go
+++ b/websocket/msg.go
@@ -3,15 +3,13 @@ package websocket
import "github.com/FreifunkBremen/freifunkmanager/runtime"
type Message struct {
- Type string `json:"type"`
- Body interface{} `json:"body,omitempty"`
- Node *runtime.Node `json:"node,omitempty"`
- Command *runtime.Command `json:"cmd,omitempty"`
+ Type string `json:"type"`
+ Body interface{} `json:"body,omitempty"`
+ Node *runtime.Node `json:"node,omitempty"`
}
const (
MessageTypeSystemNode = "system"
MessageTypeCurrentNode = "current"
MessageTypeStats = "stats"
- MessageTypeCommand = "cmd"
)
diff --git a/websocket/server.go b/websocket/server.go
index 23a192a..62aa78d 100644
--- a/websocket/server.go
+++ b/websocket/server.go
@@ -6,7 +6,7 @@ import (
runtimeYanic "github.com/FreifunkBremen/yanic/runtime"
httpLib "github.com/genofire/golang-lib/http"
- "github.com/genofire/golang-lib/log"
+ log "github.com/sirupsen/logrus"
"golang.org/x/net/websocket"
"github.com/FreifunkBremen/freifunkmanager/runtime"
@@ -16,11 +16,9 @@ var nodes *runtime.Nodes
var clients map[string]*Client
var clientsMutex sync.Mutex
var stats *runtimeYanic.GlobalStats
-var commands *runtime.Commands
-func Start(nodeBind *runtime.Nodes, commandsBind *runtime.Commands) {
+func Start(nodeBind *runtime.Nodes) {
nodes = nodeBind
- commands = commandsBind
clients = make(map[string]*Client)
http.Handle("/websocket", websocket.Handler(func(ws *websocket.Conn) {
@@ -32,10 +30,10 @@ func Start(nodeBind *runtime.Nodes, commandsBind *runtime.Commands) {
clientsMutex.Lock()
delete(clients, ip)
clientsMutex.Unlock()
- log.HTTP(r).Info("client disconnected")
+ log.Info("client disconnected")
}()
- log.HTTP(r).Infof("new client")
+ log.Infof("new client")
client := NewClient(ip, ws)
clientsMutex.Lock()
@@ -68,5 +66,5 @@ func SendAll(msg Message) {
}
func Close() {
- log.Log.Infof("websocket stopped with %d clients", len(clients))
+ log.Infof("websocket stopped with %d clients", len(clients))
}
diff --git a/websocket/server_test.go b/websocket/server_test.go
index 3a3318b..4782bb5 100644
--- a/websocket/server_test.go
+++ b/websocket/server_test.go
@@ -10,9 +10,8 @@ import (
func TestStart(t *testing.T) {
assert := assert.New(t)
nodes := &runtime.Nodes{}
- commands := &runtime.Commands{}
assert.Nil(clients)
- Start(nodes, commands)
+ Start(nodes)
assert.NotNil(clients)
Close()
}
diff --git a/yanic_example.conf b/yanic_example.conf
new file mode 100644
index 0000000..820164e
--- /dev/null
+++ b/yanic_example.conf
@@ -0,0 +1,31 @@
+[respondd]
+enable = true
+collect_interval = "1m"
+
+[[respondd.interfaces]]
+ifname = "wlp4s0"
+
+[webserver]
+enable = false
+
+[nodes]
+state_path = "/tmp/state.json"
+prune_after = "7d"
+save_interval = "5s"
+offline_after = "10m"
+
+[[nodes.output.meshviewer-ffrgb]]
+enable = true
+path = "./webroot/data/meshviewer.json"
+
+[nodes.output.meshviewer-ffrgb.filter]
+no_owner = false
+
+[database]
+delete_after = "1y"
+delete_interval = "1h"
+
+[[database.connection.respondd]]
+enable = true
+type = "udp6"
+address = "[::1]:10001"