diff --git a/cmd/freifunkmanager/main.go b/cmd/freifunkmanager/main.go index 0fa80f1..5f3e497 100644 --- a/cmd/freifunkmanager/main.go +++ b/cmd/freifunkmanager/main.go @@ -25,6 +25,7 @@ var ( configFile string config *configPackage.Config nodes *runtime.Nodes + commands *runtime.Commands yanicDialer *yanic.Dialer stats *runtimeYanic.GlobalStats ) @@ -38,14 +39,15 @@ func main() { log.Log.Info("starting...") sshmanager := ssh.NewManager(config.SSHPrivateKey) - nodes := runtime.NewNodes(config.StatePath, config.SSHInterface, sshmanager) + 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) go nodesUpdateWorker.Start() go nodesSaveWorker.Start() - websocket.Start(nodes) + websocket.Start(nodes, commands) if config.Yanic.Enable { yanicDialer := yanic.Dial(config.Yanic.Type, config.Yanic.Address) diff --git a/runtime/cmd.go b/runtime/cmd.go new file mode 100644 index 0000000..da17c7b --- /dev/null +++ b/runtime/cmd.go @@ -0,0 +1,44 @@ +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/ssh/list.go b/ssh/list.go index 56ba0da..9bbf509 100644 --- a/ssh/list.go +++ b/ssh/list.go @@ -7,7 +7,7 @@ import ( ) type List struct { - cmd string `json:"cmd"` + Command string `json:"cmd"` Clients map[string]*ListResult `json:"clients"` sshManager *Manager } @@ -20,7 +20,7 @@ type ListResult struct { func (m *Manager) CreateList(cmd string) *List { list := &List{ - cmd: cmd, + Command: cmd, sshManager: m, Clients: make(map[string]*ListResult), } @@ -42,7 +42,7 @@ func (l List) Run() { func (l List) runlistelement(host string, client *ListResult, wg *sync.WaitGroup) { defer wg.Done() - result, err := l.sshManager.run(host, client.ssh, l.cmd) + result, err := l.sshManager.run(host, client.ssh, l.Command) client.Running = false if err != nil { client.WithError = true diff --git a/webroot/css/console.css b/webroot/css/console.css index 4d2843b..db1c88e 100644 --- a/webroot/css/console.css +++ b/webroot/css/console.css @@ -26,7 +26,6 @@ width: 15%; } .console .cmd > div { - clear: both; background-color: #ccc; margin-bottom: 3px; } @@ -34,3 +33,9 @@ width: 15%; height: 20px; } +.console .cmd > div > div { + clear: both; +} +.console .cmd div .status { + width: 20px; +} diff --git a/webroot/js/gui_console.js b/webroot/js/gui_console.js index d407e46..5989ee9 100644 --- a/webroot/js/gui_console.js +++ b/webroot/js/gui_console.js @@ -120,6 +120,7 @@ const guiConsole = {}; if (cmd.clients) { Object.keys(cmd.clients).forEach((addr) => { + console.log(cmd, row, addr); const clientEl = domlib.newAt(row.clientsContainer, 'div'), clients = { 'host': domlib.newAt(clientEl, 'span'), diff --git a/webroot/js/socket.js b/webroot/js/socket.js index cc13f0d..e8e1909 100644 --- a/webroot/js/socket.js +++ b/webroot/js/socket.js @@ -36,9 +36,7 @@ let socket = {'readyState': 0}; } break; case 'cmd': - if (msg.body) { - store.updateCMD(msg.body); - } + store.updateCMD(msg.cmd); break; default: notify.send('warn', `unable to identify message: ${raw}`); @@ -69,7 +67,7 @@ let socket = {'readyState': 0}; function sendcmd (cmd) { const notifyMsg = `Befehl '${cmd.cmd}' wird überall ausgeführt.`, socketMsg = JSON.stringify({ - 'body': cmd, + 'cmd': cmd, 'type': 'cmd' }); diff --git a/websocket/client.go b/websocket/client.go index 446193f..6ae284c 100644 --- a/websocket/client.go +++ b/websocket/client.go @@ -2,8 +2,10 @@ package websocket import ( "io" + "time" "github.com/genofire/golang-lib/log" + "github.com/genofire/golang-lib/worker" "golang.org/x/net/websocket" ) @@ -53,23 +55,38 @@ func (c *Client) Close() { func (c *Client) Listen() { go c.listenWrite() c.Write(&Message{Type: MessageTypeStats, Body: stats}) - c.allNodes() + c.publishAllData() c.listenRead() } -func (c *Client) allNodes() { +func (c *Client) publishAllData() { for _, node := range nodes.List { c.Write(&Message{Type: MessageTypeSystemNode, Node: node}) } for _, node := range nodes.Current { c.Write(&Message{Type: MessageTypeCurrentNode, Node: node}) } + for _, cmd := range commands.List { + c.Write(&Message{Type: MessageTypeCommand, Command: cmd}) + } } func (c *Client) handleMessage(msg *Message) { switch msg.Type { case MessageTypeSystemNode: nodes.UpdateNode(msg.Node) + break + case MessageTypeCommand: + cmd := commands.AddCommand(msg.Command) + w := worker.NewWorker(time.Millisecond*300, func() { + SendAll(Message{Type: MessageTypeCommand, Command: cmd}) + }) + go w.Start() + go cmd.Run(func() { + w.Close() + SendAll(Message{Type: MessageTypeCommand, Command: cmd}) + }) + break } } diff --git a/websocket/msg.go b/websocket/msg.go index c5b77b9..bd755dc 100644 --- a/websocket/msg.go +++ b/websocket/msg.go @@ -3,14 +3,15 @@ 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"` + Type string `json:"type"` + Body interface{} `json:"body,omitempty"` + Node *runtime.Node `json:"node,omitempty"` + Command *runtime.Command `json:"cmd,omitempty"` } const ( MessageTypeSystemNode = "system" MessageTypeCurrentNode = "current" MessageTypeStats = "stats" - MessageTypeCmd = "cmd" + MessageTypeCommand = "cmd" ) diff --git a/websocket/server.go b/websocket/server.go index 93ecea3..23a192a 100644 --- a/websocket/server.go +++ b/websocket/server.go @@ -16,9 +16,11 @@ 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) { +func Start(nodeBind *runtime.Nodes, commandsBind *runtime.Commands) { nodes = nodeBind + commands = commandsBind clients = make(map[string]*Client) http.Handle("/websocket", websocket.Handler(func(ws *websocket.Conn) { diff --git a/websocket/server_test.go b/websocket/server_test.go index 4782bb5..3a3318b 100644 --- a/websocket/server_test.go +++ b/websocket/server_test.go @@ -10,8 +10,9 @@ import ( func TestStart(t *testing.T) { assert := assert.New(t) nodes := &runtime.Nodes{} + commands := &runtime.Commands{} assert.Nil(clients) - Start(nodes) + Start(nodes, commands) assert.NotNil(clients) Close() }