From 08095aa9a0d7b9b7636cdf36a5a5b6df2592bc05 Mon Sep 17 00:00:00 2001
From: Sebastien Douheret <sebastien.douheret@iot.bzh>
Date: Thu, 15 Mar 2018 14:50:27 +0100
Subject: Added Target and Terminal events through WS.

Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
---
 lib/xdsserver/apiv1-targets.go | 44 ++++++++++++++++++++++++-------
 lib/xdsserver/targets.go       | 42 ++++++++++++++++++-----------
 lib/xdsserver/terminal-ssh.go  |  2 ++
 lib/xdsserver/terminals.go     | 53 ++++++++++++++++++++++++++++++++-----
 lib/xsapiv1/events.go          | 60 ++++++++++++++++++++++++++++++++++++++----
 5 files changed, 163 insertions(+), 38 deletions(-)

diff --git a/lib/xdsserver/apiv1-targets.go b/lib/xdsserver/apiv1-targets.go
index 978dc75..a7048eb 100644
--- a/lib/xdsserver/apiv1-targets.go
+++ b/lib/xdsserver/apiv1-targets.go
@@ -58,9 +58,16 @@ func (s *APIService) addTarget(c *gin.Context) {
 		return
 	}
 
+	// Retrieve session info
+	sess := s.sessions.Get(c)
+	if sess == nil {
+		common.APIError(c, "Unknown sessions")
+		return
+	}
+
 	s.Log.Debugln("Add target config: ", cfgArg)
 
-	newTgt, err := s.targets.Add(cfgArg)
+	newTgt, err := s.targets.Add(cfgArg, sess)
 	if err != nil {
 		common.APIError(c, err.Error())
 		return
@@ -77,9 +84,16 @@ func (s *APIService) delTarget(c *gin.Context) {
 		return
 	}
 
+	// Retrieve session info
+	sess := s.sessions.Get(c)
+	if sess == nil {
+		common.APIError(c, "Unknown sessions")
+		return
+	}
+
 	s.Log.Debugln("Delete target id ", id)
 
-	delEntry, err := s.targets.Delete(id)
+	delEntry, err := s.targets.Delete(id, sess)
 	if err != nil {
 		common.APIError(c, err.Error())
 		return
@@ -190,13 +204,8 @@ func (s *APIService) openTgtTerm(c *gin.Context) {
 		common.APIError(c, "Unknown sessions")
 		return
 	}
-	sock := sess.IOSocket
-	if sock == nil {
-		common.APIError(c, "Websocket not established")
-		return
-	}
 
-	term, err := s.targets.OpenTerminal(id, tid, sock, sess.ID)
+	term, err := s.targets.OpenTerminal(id, tid, sess)
 	if err != nil {
 		common.APIError(c, err.Error())
 		return
@@ -211,7 +220,15 @@ func (s *APIService) closeTgtTerm(c *gin.Context) {
 		common.APIError(c, err.Error())
 		return
 	}
-	term, err := s.targets.CloseTerminal(id, tid)
+
+	// Retrieve session info
+	sess := s.sessions.Get(c)
+	if sess == nil {
+		common.APIError(c, "Unknown sessions")
+		return
+	}
+
+	term, err := s.targets.CloseTerminal(id, tid, sess)
 	if err != nil {
 		common.APIError(c, err.Error())
 		return
@@ -233,7 +250,14 @@ func (s *APIService) resizeTgtTerm(c *gin.Context) {
 		return
 	}
 
-	term, err := s.targets.ResizeTerminal(id, tid, sizeArg.Cols, sizeArg.Rows)
+	// Retrieve session info
+	sess := s.sessions.Get(c)
+	if sess == nil {
+		common.APIError(c, "Unknown sessions")
+		return
+	}
+
+	term, err := s.targets.ResizeTerminal(id, tid, sizeArg.Cols, sizeArg.Rows, sess)
 	if err != nil {
 		common.APIError(c, err.Error())
 		return
diff --git a/lib/xdsserver/targets.go b/lib/xdsserver/targets.go
index 663233d..ded3c1b 100644
--- a/lib/xdsserver/targets.go
+++ b/lib/xdsserver/targets.go
@@ -27,7 +27,6 @@ import (
 	common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/golib"
 	"gerrit.automotivelinux.org/gerrit/src/xds/xds-server/lib/xdsconfig"
 	"gerrit.automotivelinux.org/gerrit/src/xds/xds-server/lib/xsapiv1"
-	socketio "github.com/googollee/go-socket.io"
 	"github.com/syncthing/syncthing/lib/sync"
 )
 
@@ -80,7 +79,7 @@ func (t *Targets) LoadConfig() error {
 	// Update targets
 	t.Log.Infof("Loading initial targets config: %d targets found", len(tgts))
 	for _, tc := range tgts {
-		if _, err := t.createUpdate(tc, false, true); err != nil {
+		if _, err := t.createUpdate(tc, false, true, nil); err != nil {
 			return err
 		}
 	}
@@ -149,12 +148,12 @@ func (t *Targets) getConfigArrUnsafe() []xsapiv1.TargetConfig {
 }
 
 // Add adds a new target
-func (t *Targets) Add(newT xsapiv1.TargetConfig) (*xsapiv1.TargetConfig, error) {
-	return t.createUpdate(newT, true, false)
+func (t *Targets) Add(newT xsapiv1.TargetConfig, sess *ClientSession) (*xsapiv1.TargetConfig, error) {
+	return t.createUpdate(newT, true, false, sess)
 }
 
 // CreateUpdate creates or update a target
-func (t *Targets) createUpdate(newT xsapiv1.TargetConfig, create bool, initial bool) (*xsapiv1.TargetConfig, error) {
+func (t *Targets) createUpdate(newT xsapiv1.TargetConfig, create bool, initial bool, sess *ClientSession) (*xsapiv1.TargetConfig, error) {
 	var err error
 
 	tcMutex.Lock()
@@ -227,6 +226,14 @@ func (t *Targets) createUpdate(newT xsapiv1.TargetConfig, create bool, initial b
 	// Add to folders list
 	t.tgts[newT.ID] = &tgt
 
+	// Notify target Add
+	newTgt := tgt.GetConfig()
+	if !initial {
+		if err = t.events.Emit(xsapiv1.EVTTargetAdd, &newTgt, sess.ID); err != nil {
+			t.Log.Errorf("WS Emit EVTTargetAdd : %v", err)
+		}
+	}
+
 	// Save config on disk
 	if !initial {
 		if err := t.SaveConfig(); err != nil {
@@ -234,12 +241,11 @@ func (t *Targets) createUpdate(newT xsapiv1.TargetConfig, create bool, initial b
 		}
 	}
 
-	newTgt := tgt.GetConfig()
 	return &newTgt, nil
 }
 
 // Delete deletes a specific target
-func (t *Targets) Delete(id string) (xsapiv1.TargetConfig, error) {
+func (t *Targets) Delete(id string, sess *ClientSession) (xsapiv1.TargetConfig, error) {
 	var err error
 
 	tcMutex.Lock()
@@ -262,6 +268,11 @@ func (t *Targets) Delete(id string) (xsapiv1.TargetConfig, error) {
 	// Save config on disk
 	err = t.SaveConfig()
 
+	// Notify target remove
+	if err = t.events.Emit(xsapiv1.EVTTargetRemove, &tgc, sess.ID); err != nil {
+		t.Log.Errorf("WS Emit EVTTargetRemove : %v", err)
+	}
+
 	return tgc, err
 }
 
@@ -341,10 +352,8 @@ func (t *Targets) CreateUpdateTerminal(targetID string, tmCfg xsapiv1.TerminalCo
 		}
 	}
 
-	term.Status = xsapiv1.StatusTermEnable
-
-	// Save config on disk
 	if !initial {
+		// Save config on disk
 		if err := t.SaveConfig(); err != nil {
 			return term, err
 		}
@@ -374,30 +383,31 @@ func (t *Targets) DeleteTerminal(targetID, termID string) (*xsapiv1.TerminalConf
 }
 
 // OpenTerminal Open a target terminal
-func (t *Targets) OpenTerminal(targetID, termID string, sock *socketio.Socket, sessID string) (*xsapiv1.TerminalConfig, error) {
+func (t *Targets) OpenTerminal(targetID, termID string, sess *ClientSession) (*xsapiv1.TerminalConfig, error) {
 	terms, exist := t.terminals[targetID]
 	if !exist {
 		return nil, fmt.Errorf("unknown target id")
 	}
-	return (*terms).Open(termID, sock, sessID)
+
+	return (*terms).Open(termID, sess)
 }
 
 // CloseTerminal Close a target terminal
-func (t *Targets) CloseTerminal(targetID, termID string) (*xsapiv1.TerminalConfig, error) {
+func (t *Targets) CloseTerminal(targetID, termID string, sess *ClientSession) (*xsapiv1.TerminalConfig, error) {
 	terms, exist := t.terminals[targetID]
 	if !exist {
 		return nil, fmt.Errorf("unknown target id")
 	}
-	return (*terms).Close(termID)
+	return (*terms).Close(termID, sess)
 }
 
 // ResizeTerminal Set size (row+col) of a target terminal
-func (t *Targets) ResizeTerminal(targetID, termID string, cols, rows uint16) (*xsapiv1.TerminalConfig, error) {
+func (t *Targets) ResizeTerminal(targetID, termID string, cols, rows uint16, sess *ClientSession) (*xsapiv1.TerminalConfig, error) {
 	terms, exist := t.terminals[targetID]
 	if !exist {
 		return nil, fmt.Errorf("unknown target id")
 	}
-	return (*terms).Resize(termID, cols, rows)
+	return (*terms).Resize(termID, cols, rows, sess)
 }
 
 // SignalTerminal Send a signal to a target terminal
diff --git a/lib/xdsserver/terminal-ssh.go b/lib/xdsserver/terminal-ssh.go
index 9a9f5fd..c275173 100644
--- a/lib/xdsserver/terminal-ssh.go
+++ b/lib/xdsserver/terminal-ssh.go
@@ -246,6 +246,8 @@ func (t *TermSSH) Resize(cols, rows uint16) (*xsapiv1.TerminalConfig, error) {
 		t.termCfg.Rows = rows
 	}
 
+	t.LogSillyf("Terminal resize id=%v, cols=%v, rows=%v", t.termCfg.ID, cols, rows)
+
 	err := t.sshWS.TerminalSetSize(t.termCfg.Rows, t.termCfg.Cols)
 	if err != nil {
 		t.Log.Errorf("Error ssh TerminalSetSize: %v", err)
diff --git a/lib/xdsserver/terminals.go b/lib/xdsserver/terminals.go
index 36623ab..b52b351 100644
--- a/lib/xdsserver/terminals.go
+++ b/lib/xdsserver/terminals.go
@@ -21,7 +21,6 @@ import (
 	"fmt"
 
 	"gerrit.automotivelinux.org/gerrit/src/xds/xds-server/lib/xsapiv1"
-	socketio "github.com/googollee/go-socket.io"
 	"github.com/syncthing/syncthing/lib/sync"
 )
 
@@ -62,6 +61,13 @@ func (t *Terminals) New(cfg xsapiv1.TerminalConfig, targetID string) (*xsapiv1.T
 
 	t.terms[termCfg.ID] = &newT
 
+	termCfg.Status = xsapiv1.StatusTermEnable
+
+	// Notify terminal add
+	if err := t.events.Emit(xsapiv1.EVTTargetTerminalAdd, &termCfg, ""); err != nil {
+		t.Log.Errorf("WS Emit EVTTargetTerminalAdd : %v", err)
+	}
+
 	return &termCfg, nil
 }
 
@@ -84,6 +90,11 @@ func (t *Terminals) Free(id string) (*xsapiv1.TerminalConfig, error) {
 
 	delete(t.terms, id)
 
+	// Notify terminal state change or add
+	if err := t.events.Emit(xsapiv1.EVTTargetTerminalRemove, &resTerm, ""); err != nil {
+		t.Log.Errorf("WS Emit EVTTargetTerminalRemove : %v", err)
+	}
+
 	return &resTerm, nil
 }
 
@@ -117,25 +128,45 @@ func (t *Terminals) getConfigArrUnsafe() []xsapiv1.TerminalConfig {
 }
 
 // Open adds a new terminal
-func (t *Terminals) Open(id string, sock *socketio.Socket, sessID string) (*xsapiv1.TerminalConfig, error) {
+func (t *Terminals) Open(id string, sess *ClientSession) (*xsapiv1.TerminalConfig, error) {
 	tc := t.Get(id)
 	if tc == nil {
 		return nil, fmt.Errorf("Unknown id")
 	}
-	return (*tc).Open(sock, sessID)
+
+	if sess.IOSocket == nil {
+		return nil, fmt.Errorf("Websocket not established")
+	}
+
+	term, err := (*tc).Open(sess.IOSocket, sess.ID)
+
+	// Notify term state change
+	if errEmit := t.events.Emit(xsapiv1.EVTTargetTerminalStateChange, &term, sess.ID); errEmit != nil {
+		t.Log.Errorf("WS Emit EVTTargetTerminalStateChange : %v", errEmit)
+	}
+
+	return term, err
 }
 
 // Close a specific terminal
-func (t *Terminals) Close(id string) (*xsapiv1.TerminalConfig, error) {
+func (t *Terminals) Close(id string, sess *ClientSession) (*xsapiv1.TerminalConfig, error) {
 	tc := t.Get(id)
 	if tc == nil {
 		return nil, fmt.Errorf("Unknown id")
 	}
-	return (*tc).Close()
+
+	term, err := (*tc).Close()
+
+	// Notify term state change
+	if errEmit := t.events.Emit(xsapiv1.EVTTargetTerminalStateChange, &term, sess.ID); errEmit != nil {
+		t.Log.Errorf("WS Emit EVTTargetTerminalStateChange : %v", errEmit)
+	}
+
+	return term, err
 }
 
 // Resize a specific terminal
-func (t *Terminals) Resize(id string, cols, rows uint16) (*xsapiv1.TerminalConfig, error) {
+func (t *Terminals) Resize(id string, cols, rows uint16, sess *ClientSession) (*xsapiv1.TerminalConfig, error) {
 	tmMutex.Lock()
 	defer tmMutex.Unlock()
 
@@ -143,7 +174,15 @@ func (t *Terminals) Resize(id string, cols, rows uint16) (*xsapiv1.TerminalConfi
 	if tc == nil {
 		return nil, fmt.Errorf("Unknown id")
 	}
-	return (*tc).Resize(cols, rows)
+
+	term, err := (*tc).Resize(cols, rows)
+
+	// Notify term state change
+	if errEmit := t.events.Emit(xsapiv1.EVTTargetTerminalStateChange, &term, sess.ID); errEmit != nil {
+		t.Log.Errorf("WS Emit EVTTargetTerminalStateChange : %v", errEmit)
+	}
+
+	return term, err
 }
 
 // Signal Send a Signal a specific terminal
diff --git a/lib/xsapiv1/events.go b/lib/xsapiv1/events.go
index 84a364c..e42563c 100644
--- a/lib/xsapiv1/events.go
+++ b/lib/xsapiv1/events.go
@@ -48,13 +48,23 @@ const (
 	EventTypePrefix = "event:" // following by event type
 
 	// Supported Events type
-	EVTAll               = EventTypePrefix + "all"
+	EVTAll = EventTypePrefix + "all"
+
 	EVTFolderChange      = EventTypePrefix + "folder-change"       // type EventMsg with Data type xsapiv1.FolderConfig
 	EVTFolderStateChange = EventTypePrefix + "folder-state-change" // type EventMsg with Data type xsapiv1.FolderConfig
-	EVTSDKAdd            = EventTypePrefix + "sdk-add"             // type EventMsg with Data type xsapiv1.SDK
-	EVTSDKRemove         = EventTypePrefix + "sdk-remove"          // type EventMsg with Data type xsapiv1.SDK
-	EVTSDKManagement     = EventTypePrefix + "sdk-management"      // type EventMsg with Data type xsapiv1.SDKManagementMsg
-	EVTSDKStateChange    = EventTypePrefix + "sdk-state-change"    // type EventMsg with Data type xsapiv1.SDK
+
+	EVTSDKAdd         = EventTypePrefix + "sdk-add"          // type EventMsg with Data type xsapiv1.SDK
+	EVTSDKRemove      = EventTypePrefix + "sdk-remove"       // type EventMsg with Data type xsapiv1.SDK
+	EVTSDKManagement  = EventTypePrefix + "sdk-management"   // type EventMsg with Data type xsapiv1.SDKManagementMsg
+	EVTSDKStateChange = EventTypePrefix + "sdk-state-change" // type EventMsg with Data type xsapiv1.SDK
+
+	EVTTargetAdd         = EventTypePrefix + "target-add"          // type EventMsg with Data type xsapiv1.TargetConfig
+	EVTTargetRemove      = EventTypePrefix + "target-remove"       // type EventMsg with Data type xsapiv1.TargetConfig
+	EVTTargetStateChange = EventTypePrefix + "target-state-change" // type EventMsg with Data type xsapiv1.TargetConfig
+
+	EVTTargetTerminalAdd         = EventTypePrefix + "target-terminal-add"          // type EventMsg with Data type xsapiv1.TerminalConfig
+	EVTTargetTerminalRemove      = EventTypePrefix + "target-terminal-remove"       // type EventMsg with Data type xsapiv1.TerminalConfig
+	EVTTargetTerminalStateChange = EventTypePrefix + "target-terminal-state-change" // type EventMsg with Data type xsapiv1.TerminalConfig
 )
 
 // EVTAllList List of all supported events
@@ -65,6 +75,12 @@ var EVTAllList = []string{
 	EVTSDKRemove,
 	EVTSDKManagement,
 	EVTSDKStateChange,
+	EVTTargetAdd,
+	EVTTargetRemove,
+	EVTTargetStateChange,
+	EVTTargetTerminalAdd,
+	EVTTargetTerminalRemove,
+	EVTTargetTerminalStateChange,
 }
 
 // DecodeFolderConfig Helper to decode Data field type FolderConfig
@@ -100,3 +116,37 @@ func (e *EventMsg) DecodeSDKEvent() (SDK, error) {
 	}
 	return s, err
 }
+
+// DecodeTargetEvent Helper to decode Data field type TargetConfig
+func (e *EventMsg) DecodeTargetEvent() (TargetConfig, error) {
+	var err error
+	p := TargetConfig{}
+	switch e.Type {
+	case EVTTargetAdd, EVTTargetRemove, EVTTargetStateChange:
+		d := []byte{}
+		d, err = json.Marshal(e.Data)
+		if err == nil {
+			err = json.Unmarshal(d, &p)
+		}
+	default:
+		err = fmt.Errorf("Invalid type")
+	}
+	return p, err
+}
+
+// DecodeTerminalEvent Helper to decode Data field type TerminalConfig
+func (e *EventMsg) DecodeTerminalEvent() (TerminalConfig, error) {
+	var err error
+	p := TerminalConfig{}
+	switch e.Type {
+	case EVTTargetTerminalAdd, EVTTargetTerminalRemove, EVTTargetTerminalStateChange:
+		d := []byte{}
+		d, err = json.Marshal(e.Data)
+		if err == nil {
+			err = json.Unmarshal(d, &p)
+		}
+	default:
+		err = fmt.Errorf("Invalid type")
+	}
+	return p, err
+}
-- 
cgit