summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.vscode/settings.json3
-rw-r--r--Makefile47
-rw-r--r--config.json.in2
-rw-r--r--glide.yaml4
-rw-r--r--lib/apiv1/agent.go70
-rw-r--r--lib/apiv1/apiv1.go11
-rw-r--r--lib/apiv1/events.go9
-rw-r--r--lib/apiv1/exec.go25
-rw-r--r--lib/apiv1/folders.go22
-rw-r--r--lib/apiv1/make.go30
-rw-r--r--lib/apiv1/sdks.go6
-rw-r--r--lib/apiv1/version.go2
-rw-r--r--lib/crosssdk/sdk.go7
-rw-r--r--lib/crosssdk/sdks.go75
-rw-r--r--lib/folder/folder-interface.go15
-rw-r--r--lib/folder/folder-pathmap.go52
-rw-r--r--lib/folder/folder-st-disable.go6
-rw-r--r--lib/model/folders.go47
-rw-r--r--lib/session/session.go32
-rw-r--r--lib/syncthing/folder-st.go10
-rw-r--r--lib/syncthing/st.go18
-rw-r--r--lib/syncthing/stfolder.go24
-rw-r--r--lib/webserver/server.go6
-rw-r--r--lib/xdsconfig/builderconfig.go5
-rw-r--r--lib/xdsconfig/config.go32
-rw-r--r--lib/xdsconfig/data.go87
-rw-r--r--lib/xdsconfig/fileconfig.go19
-rw-r--r--main.go40
-rwxr-xr-xtest/test_stdoutstderr.sh7
-rw-r--r--webapp/README.md46
-rw-r--r--webapp/assets/images/background_iot_bzh_light.pngbin0 -> 637576 bytes
-rw-r--r--webapp/assets/images/iot-graphx.jpgbin138350 -> 0 bytes
-rw-r--r--webapp/assets/xds-agent-tarballs/.gitkeep0
-rw-r--r--webapp/bs-config.json9
-rw-r--r--webapp/gulp.conf.js34
-rw-r--r--webapp/gulpfile.js123
-rw-r--r--webapp/package.json76
-rw-r--r--webapp/src/app/alert/alert.component.ts30
-rw-r--r--webapp/src/app/app.component.css31
-rw-r--r--webapp/src/app/app.component.html30
-rw-r--r--webapp/src/app/app.component.ts37
-rw-r--r--webapp/src/app/app.module.ts97
-rw-r--r--webapp/src/app/app.routing.ts19
-rw-r--r--webapp/src/app/config/config.component.css35
-rw-r--r--webapp/src/app/config/config.component.html106
-rw-r--r--webapp/src/app/config/config.component.ts106
-rw-r--r--webapp/src/app/config/downloadXdsAgent.component.ts69
-rw-r--r--webapp/src/app/devel/build/build.component.css54
-rw-r--r--webapp/src/app/devel/build/build.component.html115
-rw-r--r--webapp/src/app/devel/build/build.component.ts223
-rw-r--r--webapp/src/app/devel/deploy/deploy.component.css45
-rw-r--r--webapp/src/app/devel/deploy/deploy.component.html31
-rw-r--r--webapp/src/app/devel/deploy/deploy.component.ts63
-rw-r--r--webapp/src/app/devel/devel.component.css19
-rw-r--r--webapp/src/app/devel/devel.component.html40
-rw-r--r--webapp/src/app/devel/devel.component.ts35
-rw-r--r--webapp/src/app/home/home.component.ts81
-rw-r--r--webapp/src/app/main.ts6
-rw-r--r--webapp/src/app/projects/projectAddModal.component.css24
-rw-r--r--webapp/src/app/projects/projectAddModal.component.html54
-rw-r--r--webapp/src/app/projects/projectAddModal.component.ts152
-rw-r--r--webapp/src/app/projects/projectCard.component.ts91
-rw-r--r--webapp/src/app/projects/projectsListAccordion.component.ts39
-rw-r--r--webapp/src/app/sdks/sdkAddModal.component.html23
-rw-r--r--webapp/src/app/sdks/sdkAddModal.component.ts24
-rw-r--r--webapp/src/app/sdks/sdkCard.component.ts51
-rw-r--r--webapp/src/app/sdks/sdkSelectDropdown.component.ts48
-rw-r--r--webapp/src/app/sdks/sdksListAccordion.component.ts26
-rw-r--r--webapp/src/app/services/alert.service.ts66
-rw-r--r--webapp/src/app/services/config.service.ts422
-rw-r--r--webapp/src/app/services/sdk.service.ts47
-rw-r--r--webapp/src/app/services/syncthing.service.ts348
-rw-r--r--webapp/src/app/services/utils.service.ts33
-rw-r--r--webapp/src/app/services/xdsagent.service.ts216
-rw-r--r--webapp/src/app/services/xdsserver.service.ts296
-rw-r--r--webapp/src/index.html110
-rw-r--r--webapp/src/systemjs.config.js69
-rw-r--r--webapp/tsconfig.json18
-rw-r--r--webapp/tslint.json55
-rw-r--r--webapp/tslint.prod.json56
-rw-r--r--webapp/typings.json11
81 files changed, 537 insertions, 4015 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 826f7fd..d2c6144 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -55,6 +55,7 @@
"mfolders",
"IFOLDER",
"flds",
- "dflt"
+ "dflt",
+ "stconfig"
]
}
diff --git a/Makefile b/Makefile
index 222e708..8eacc1f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,26 +1,19 @@
-# Makefile used to build XDS daemon Web Server
-
-# Application Version
-VERSION := 0.3.4
+# Makefile used to build XDS Server
# Syncthing version to install
-SYNCTHING_VERSION = 0.14.28
-SYNCTHING_INOTIFY_VERSION = 0.8.6
-
-
-# Retrieve git tag/commit to set sub-version string
-ifeq ($(origin SUB_VERSION), undefined)
- SUB_VERSION := $(shell git describe --exact-match --tags 2>/dev/null | sed 's/^v//')
- ifneq ($(SUB_VERSION), )
- VERSION := $(firstword $(subst -, ,$(SUB_VERSION)))
- SUB_VERSION := $(word 2,$(subst -, ,$(SUB_VERSION)))
- endif
- ifeq ($(SUB_VERSION), )
- SUB_VERSION := $(shell git rev-parse --short HEAD)
- ifeq ($(SUB_VERSION), )
- SUB_VERSION := unknown-dev
- endif
- endif
+SYNCTHING_VERSION = 0.14.38
+SYNCTHING_INOTIFY_VERSION = 0.8.7
+
+
+# Retrieve git tag/commit to set version & sub-version strings
+GIT_DESC := $(shell git describe --always --tags)
+VERSION := $(firstword $(subst -, ,$(GIT_DESC)))
+SUB_VERSION := $(subst $(VERSION)-,,$(GIT_DESC))
+ifeq ($(VERSION), )
+ VERSION := unknown-dev
+endif
+ifeq ($(SUB_VERSION), )
+ SUB_VERSION := $(shell date +'%Y-%m-%d_%H%M%S')
endif
# for backward compatibility
@@ -103,7 +96,7 @@ fmt: tools/glide
run: build/xds tools/syncthing/copytobin
$(LOCAL_BINDIR)/xds-server$(EXT) --log info -c config.json.in
-debug: build/xds webapp/debug tools/syncthing/copytobin
+debug: build/xds tools/syncthing/copytobin
$(LOCAL_BINDIR)/xds-server$(EXT) --log debug -c config.json.in
.PHONY: clean
@@ -112,17 +105,15 @@ clean:
.PHONY: distclean
distclean: clean
- rm -rf $(LOCAL_BINDIR) $(ROOT_SRCDIR)/tools glide.lock vendor webapp/node_modules webapp/dist webapp/assets/xds-agent-tarballs/*.zip
+ rm -rf $(LOCAL_BINDIR) $(ROOT_SRCDIR)/tools glide.lock vendor $(ROOT_SRCDIR)/webapp/dist $(ROOT_SRCDIR)/webapp/node_modules
webapp: webapp/install
- (cd webapp && gulp build)
-
-webapp/debug:
- (cd webapp && gulp watch &)
+ mkdir -p $(ROOT_SRCDIR)/webapp/dist $(ROOT_SRCDIR)/webapp/dist/fonts
+ (cd $(ROOT_SRCDIR)/webapp && cp -a ./assets ./src/index.html ./node_modules/font-awesome/css/font-awesome.min.css ./dist/)
+ (cd $(ROOT_SRCDIR)/webapp && cp -a ./node_modules/font-awesome/fonts/* ./dist/fonts/)
webapp/install:
(cd webapp && npm install)
- @if [ -d ${DESTDIR}/usr/local/etc ]; then rm -rf ${DESTDIR}/usr; fi
.PHONY: scripts
scripts:
diff --git a/config.json.in b/config.json.in
index ac2f891..3dcc04a 100644
--- a/config.json.in
+++ b/config.json.in
@@ -1,6 +1,6 @@
{
"webAppDir": "www",
- "httpPort": "8000",
+ "httpPort": "8010",
"shareRootDir": "${HOME}/.xds-server/projects",
"logsDir": "/tmp/xds-server/logs",
"sdkRootDir": "/xdt/sdk",
diff --git a/glide.yaml b/glide.yaml
index e017281..94ef2db 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -9,7 +9,7 @@ import:
- package: github.com/gin-contrib/static
version: master
- package: github.com/syncthing/syncthing
- version: =0.14.28
+ version: =0.14.38
subpackages:
- lib/sync
- lib/config
@@ -25,7 +25,7 @@ import:
- package: github.com/satori/go.uuid
version: ^1.1.0
- package: github.com/iotbzh/xds-common
- version: 4b8e35b6786b
+ version: ^0.1.0
subpackages:
- golib/common
- golib/eows
diff --git a/lib/apiv1/agent.go b/lib/apiv1/agent.go
deleted file mode 100644
index 925f12b..0000000
--- a/lib/apiv1/agent.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package apiv1
-
-import (
- "net/http"
- "path"
- "strings"
-
- "path/filepath"
-
- "github.com/gin-gonic/gin"
- common "github.com/iotbzh/xds-common/golib"
-)
-
-// XDSAgentTarball .
-type XDSAgentTarball struct {
- OS string `json:"os"`
- Arch string `json:"arch"`
- Version string `json:"version"`
- RawVersion string `json:"raw-version"`
- FileURL string `json:"fileUrl"`
-}
-
-// XDSAgentInfo .
-type XDSAgentInfo struct {
- Tarballs []XDSAgentTarball `json:"tarballs"`
-}
-
-// getXdsAgentInfo : return various information about Xds Agent
-func (s *APIService) getXdsAgentInfo(c *gin.Context) {
-
- res := XDSAgentInfo{}
- tarballURL := "assets/xds-agent-tarballs"
- tarballDir := filepath.Join(s.cfg.FileConf.WebAppDir, "assets", "xds-agent-tarballs")
- if common.Exists(tarballDir) {
- files, err := filepath.Glob(path.Join(tarballDir, "xds-agent_*.zip"))
- if err != nil {
- s.log.Debugf("Error while retrieving xds-agent tarballs: dir=%s, error=%v", tarballDir, err)
- }
- for _, ff := range files {
- file := filepath.Base(ff)
- // Assume that tarball name format is: xds-agent_OS-ARCH-RAWVERSION.zip
- fs := strings.TrimSuffix(strings.TrimPrefix(file, "xds-agent_"), ".zip")
- f := strings.Split(fs, "-")
-
- if len(f) >= 3 {
- vers := strings.Split(f[2], "_")
- ver := f[2]
- if len(vers) > 1 {
- ver = vers[0]
- }
-
- newT := XDSAgentTarball{
- OS: f[0],
- Arch: f[1],
- Version: ver,
- RawVersion: f[2],
- FileURL: filepath.Join(tarballURL, file),
- }
-
- s.log.Infof("Added XDS-Agent tarball: %s", file)
- res.Tarballs = append(res.Tarballs, newT)
-
- } else {
- s.log.Debugf("Error while retrieving xds-agent, decoding failure: file:%v", ff)
- }
- }
- }
-
- c.JSON(http.StatusOK, res)
-}
diff --git a/lib/apiv1/apiv1.go b/lib/apiv1/apiv1.go
index 262f513..d10a08e 100644
--- a/lib/apiv1/apiv1.go
+++ b/lib/apiv1/apiv1.go
@@ -34,19 +34,18 @@ func New(r *gin.Engine, sess *session.Sessions, cfg *xdsconfig.Config, mfolders
}
s.apiRouter.GET("/version", s.getVersion)
- s.apiRouter.GET("/xdsagent/info", s.getXdsAgentInfo)
s.apiRouter.GET("/config", s.getConfig)
s.apiRouter.POST("/config", s.setConfig)
s.apiRouter.GET("/folders", s.getFolders)
- s.apiRouter.GET("/folder/:id", s.getFolder)
- s.apiRouter.POST("/folder", s.addFolder)
- s.apiRouter.POST("/folder/sync/:id", s.syncFolder)
- s.apiRouter.DELETE("/folder/:id", s.delFolder)
+ s.apiRouter.GET("/folders/:id", s.getFolder)
+ s.apiRouter.POST("/folders", s.addFolder)
+ s.apiRouter.POST("/folders/sync/:id", s.syncFolder)
+ s.apiRouter.DELETE("/folders/:id", s.delFolder)
s.apiRouter.GET("/sdks", s.getSdks)
- s.apiRouter.GET("/sdk/:id", s.getSdk)
+ s.apiRouter.GET("/sdks/:id", s.getSdk)
s.apiRouter.POST("/make", s.buildMake)
s.apiRouter.POST("/make/:id", s.buildMake)
diff --git a/lib/apiv1/events.go b/lib/apiv1/events.go
index da8298c..9444262 100644
--- a/lib/apiv1/events.go
+++ b/lib/apiv1/events.go
@@ -112,6 +112,9 @@ func (s *APIService) eventsRegister(c *gin.Context) {
Folder: *cfg,
}
+ s.log.Debugf("WS Emit %s - Status=%10s, IsInSync=%6v, ID=%s",
+ EventEventType+evType, cfg.Status, cfg.IsInSync, cfg.ID)
+
if err := (*so).Emit(EventEventType+evType, msg); err != nil {
s.log.Errorf("WS Emit Folder StateChanged event : %v", err)
}
@@ -119,11 +122,15 @@ func (s *APIService) eventsRegister(c *gin.Context) {
data := make(folder.EventCBData)
data["sid"] = sess.ID
- err := s.mfolders.RegisterEventChange(args.ProjectID, &cbFunc, &data)
+ prjID, err := s.mfolders.ResolveID(args.ProjectID)
if err != nil {
common.APIError(c, err.Error())
return
}
+ if err = s.mfolders.RegisterEventChange(prjID, &cbFunc, &data); err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
c.JSON(http.StatusOK, gin.H{"status": "OK"})
}
diff --git a/lib/apiv1/exec.go b/lib/apiv1/exec.go
index de40c70..30444c1 100644
--- a/lib/apiv1/exec.go
+++ b/lib/apiv1/exec.go
@@ -19,7 +19,8 @@ type (
// ExecArgs JSON parameters of /exec command
ExecArgs struct {
ID string `json:"id" binding:"required"`
- SdkID string `json:"sdkid"` // sdk ID to use for setting env
+ SdkID string `json:"sdkID"` // sdk ID to use for setting env
+ CmdID string `json:"cmdID"` // command unique ID
Cmd string `json:"cmd" binding:"required"`
Args []string `json:"args"`
Env []string `json:"env"`
@@ -104,15 +105,19 @@ func (s *APIService) execCmd(c *gin.Context) {
}
// Allow to pass id in url (/exec/:id) or as JSON argument
- id := c.Param("id")
- if id == "" {
- id = args.ID
+ idArg := c.Param("id")
+ if idArg == "" {
+ idArg = args.ID
}
- if id == "" {
+ if idArg == "" {
common.APIError(c, "Invalid id")
return
}
-
+ id, err := s.mfolders.ResolveID(idArg)
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
f := s.mfolders.Get(id)
if f == nil {
common.APIError(c, "Unknown id")
@@ -168,11 +173,13 @@ func (s *APIService) execCmd(c *gin.Context) {
}
// Unique ID for each commands
- cmdID := strconv.Itoa(execCommandID)
- execCommandID++
+ if args.CmdID == "" {
+ args.CmdID = s.cfg.ServerUID[:18] + "_" + strconv.Itoa(execCommandID)
+ execCommandID++
+ }
// Create new execution over WS context
- execWS := eows.New(strings.Join(cmd, " "), cmdArgs, sop, sess.ID, cmdID)
+ execWS := eows.New(strings.Join(cmd, " "), cmdArgs, sop, sess.ID, args.CmdID)
execWS.Log = s.log
// Append client project dir to environment
diff --git a/lib/apiv1/folders.go b/lib/apiv1/folders.go
index a231b86..398e21c 100644
--- a/lib/apiv1/folders.go
+++ b/lib/apiv1/folders.go
@@ -16,7 +16,12 @@ func (s *APIService) getFolders(c *gin.Context) {
// getFolder returns a specific folder configuration
func (s *APIService) getFolder(c *gin.Context) {
- f := s.mfolders.Get(c.Param("id"))
+ id, err := s.mfolders.ResolveID(c.Param("id"))
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
+ f := s.mfolders.Get(id)
if f == nil {
common.APIError(c, "Invalid id")
return
@@ -67,11 +72,14 @@ func (s *APIService) addFolder(c *gin.Context) {
// syncFolder force synchronization of folder files
func (s *APIService) syncFolder(c *gin.Context) {
- id := c.Param("id")
-
+ id, err := s.mfolders.ResolveID(c.Param("id"))
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
s.log.Debugln("Sync folder id: ", id)
- err := s.mfolders.ForceSync(id)
+ err = s.mfolders.ForceSync(id)
if err != nil {
common.APIError(c, err.Error())
return
@@ -82,7 +90,11 @@ func (s *APIService) syncFolder(c *gin.Context) {
// delFolder deletes folder from server config
func (s *APIService) delFolder(c *gin.Context) {
- id := c.Param("id")
+ id, err := s.mfolders.ResolveID(c.Param("id"))
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
s.log.Debugln("Delete folder id ", id)
diff --git a/lib/apiv1/make.go b/lib/apiv1/make.go
index cf76476..6e0c7d6 100644
--- a/lib/apiv1/make.go
+++ b/lib/apiv1/make.go
@@ -15,7 +15,8 @@ import (
// MakeArgs is the parameters (json format) of /make command
type MakeArgs struct {
ID string `json:"id"`
- SdkID string `json:"sdkid"` // sdk ID to use for setting env
+ SdkID string `json:"sdkID"` // sdk ID to use for setting env
+ CmdID string `json:"cmdID"` // command unique ID
Args []string `json:"args"` // args to pass to make command
Env []string `json:"env"`
RPath string `json:"rpath"` // relative path into project
@@ -67,15 +68,19 @@ func (s *APIService) buildMake(c *gin.Context) {
}
// Allow to pass id in url (/make/:id) or as JSON argument
- id := c.Param("id")
- if id == "" {
- id = args.ID
+ idArg := c.Param("id")
+ if idArg == "" {
+ idArg = args.ID
}
- if id == "" {
+ if idArg == "" {
common.APIError(c, "Invalid id")
return
}
-
+ id, err := s.mfolders.ResolveID(idArg)
+ if err != nil {
+ common.APIError(c, err.Error())
+ return
+ }
pf := s.mfolders.Get(id)
if pf == nil {
common.APIError(c, "Unknown id")
@@ -171,8 +176,11 @@ func (s *APIService) buildMake(c *gin.Context) {
}
}
- cmdID := strconv.Itoa(makeCommandID)
- makeCommandID++
+ // Unique ID for each commands
+ if args.CmdID == "" {
+ args.CmdID = s.cfg.ServerUID[:18] + "_" + strconv.Itoa(makeCommandID)
+ makeCommandID++
+ }
cmd := []string{}
// Retrieve env command regarding Sdk ID
@@ -186,14 +194,14 @@ func (s *APIService) buildMake(c *gin.Context) {
cmd = append(cmd, args.Args...)
}
- s.log.Debugf("Execute [Cmd ID %d]: %v", cmdID, cmd)
+ s.log.Debugf("Execute [Cmd ID %d]: %v", args.CmdID, cmd)
data := make(map[string]interface{})
data["ID"] = prj.ID
data["RootPath"] = prj.RootPath
data["ExitImmediate"] = args.ExitImmediate
- err := common.ExecPipeWs(cmd, args.Env, sop, sess.ID, cmdID, execTmo, s.log, oCB, eCB, &data)
+ err = common.ExecPipeWs(cmd, args.Env, sop, sess.ID, args.CmdID, execTmo, s.log, oCB, eCB, &data)
if err != nil {
common.APIError(c, err.Error())
return
@@ -202,6 +210,6 @@ func (s *APIService) buildMake(c *gin.Context) {
c.JSON(http.StatusOK,
gin.H{
"status": "OK",
- "cmdID": cmdID,
+ "cmdID": args.CmdID,
})
}
diff --git a/lib/apiv1/sdks.go b/lib/apiv1/sdks.go
index 52af506..f67a0ef 100644
--- a/lib/apiv1/sdks.go
+++ b/lib/apiv1/sdks.go
@@ -2,7 +2,6 @@ package apiv1
import (
"net/http"
- "strconv"
"github.com/gin-gonic/gin"
common "github.com/iotbzh/xds-common/golib"
@@ -15,12 +14,11 @@ func (s *APIService) getSdks(c *gin.Context) {
// getSdk returns a specific Sdk configuration
func (s *APIService) getSdk(c *gin.Context) {
- id, err := strconv.Atoi(c.Param("id"))
+ id, err := s.sdks.ResolveID(c.Param("id"))
if err != nil {
- common.APIError(c, "Invalid id")
+ common.APIError(c, err.Error())
return
}
-
sdk := s.sdks.Get(id)
if sdk.Profile == "" {
common.APIError(c, "Invalid id")
diff --git a/lib/apiv1/version.go b/lib/apiv1/version.go
index e022441..8f928ec 100644
--- a/lib/apiv1/version.go
+++ b/lib/apiv1/version.go
@@ -7,6 +7,7 @@ import (
)
type version struct {
+ ID string `json:"id"`
Version string `json:"version"`
APIVersion string `json:"apiVersion"`
VersionGitTag string `json:"gitTag"`
@@ -15,6 +16,7 @@ type version struct {
// getInfo : return various information about server
func (s *APIService) getVersion(c *gin.Context) {
response := version{
+ ID: s.cfg.ServerUID,
Version: s.cfg.Version,
APIVersion: s.cfg.APIVersion,
VersionGitTag: s.cfg.VersionGitTag,
diff --git a/lib/crosssdk/sdk.go b/lib/crosssdk/sdk.go
index 5a5770d..5be8954 100644
--- a/lib/crosssdk/sdk.go
+++ b/lib/crosssdk/sdk.go
@@ -3,6 +3,8 @@ package crosssdk
import (
"fmt"
"path/filepath"
+
+ uuid "github.com/satori/go.uuid"
)
// SDK Define a cross tool chain used to build application
@@ -31,8 +33,9 @@ func NewCrossSDK(path string) (*SDK, error) {
d = filepath.Dir(d)
s.Profile = filepath.Base(d)
- s.ID = s.Profile + "_" + s.Arch + "_" + s.Version
- s.Name = s.Arch + " (" + s.Version + ")"
+ // Use V3 to ensure that we get same uuid on restart
+ s.ID = uuid.NewV3(uuid.FromStringOrNil("sdks"), s.Profile+"_"+s.Arch+"_"+s.Version).String()
+ s.Name = s.Arch + " (" + s.Version + ")"
envFile := filepath.Join(path, "environment-setup*")
ef, err := filepath.Glob(envFile)
diff --git a/lib/crosssdk/sdks.go b/lib/crosssdk/sdks.go
index 0da0d1b..e3d6607 100644
--- a/lib/crosssdk/sdks.go
+++ b/lib/crosssdk/sdks.go
@@ -1,8 +1,10 @@
package crosssdk
import (
+ "fmt"
"path"
"path/filepath"
+ "strings"
"sync"
"github.com/Sirupsen/logrus"
@@ -12,14 +14,16 @@ import (
// SDKs List of installed SDK
type SDKs struct {
- Sdks []SDK
+ Sdks map[string]*SDK
mutex sync.Mutex
}
// Init creates a new instance of Syncthing
func Init(cfg *xdsconfig.Config, log *logrus.Logger) (*SDKs, error) {
- s := SDKs{}
+ s := SDKs{
+ Sdks: make(map[string]*SDK),
+ }
// Retrieve installed sdks
sdkRD := cfg.FileConf.SdkRootDir
@@ -44,7 +48,7 @@ func Init(cfg *xdsconfig.Config, log *logrus.Logger) (*SDKs, error) {
log.Debugf("Error while processing SDK dir=%s, err=%s", d, err.Error())
continue
}
- s.Sdks = append(s.Sdks, *sdk)
+ s.Sdks[sdk.ID] = sdk
}
}
@@ -53,23 +57,50 @@ func Init(cfg *xdsconfig.Config, log *logrus.Logger) (*SDKs, error) {
return &s, nil
}
-// GetAll returns all existing SDKs
-func (s *SDKs) GetAll() []SDK {
- s.mutex.Lock()
- defer s.mutex.Unlock()
- res := s.Sdks
- return res
+// ResolveID Complete an SDK ID (helper for user that can use partial ID value)
+func (s *SDKs) ResolveID(id string) (string, error) {
+ if id == "" {
+ return "", nil
+ }
+
+ match := []string{}
+ for iid := range s.Sdks {
+ fmt.Printf("SEB prefix iid=%v id=%v\n", iid, id)
+ if strings.HasPrefix(iid, id) {
+ match = append(match, iid)
+ fmt.Printf(" SEB match (%d): %v\n", len(match), match)
+ }
+ }
+ fmt.Printf("SEB match (%d): %v\n", len(match), match)
+
+ if len(match) == 1 {
+ return match[0], nil
+ } else if len(match) == 0 {
+ return id, fmt.Errorf("Unknown id")
+ }
+ return id, fmt.Errorf("Multiple IDs found with provided prefix: " + id)
}
// Get returns an SDK from id
-func (s *SDKs) Get(id int) SDK {
+func (s *SDKs) Get(id string) *SDK {
s.mutex.Lock()
defer s.mutex.Unlock()
- if id < 0 || id > len(s.Sdks) {
- return SDK{}
+ sc, exist := s.Sdks[id]
+ if !exist {
+ return nil
+ }
+ return sc
+}
+
+// GetAll returns all existing SDKs
+func (s *SDKs) GetAll() []SDK {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+ res := []SDK{}
+ for _, v := range s.Sdks {
+ res = append(res, *v)
}
- res := s.Sdks[id]
return res
}
@@ -82,15 +113,15 @@ func (s *SDKs) GetEnvCmd(id string, defaultID string) []string {
s.mutex.Lock()
defer s.mutex.Unlock()
- defaultEnv := []string{}
- for _, sdk := range s.Sdks {
- if sdk.ID == id {
- return sdk.GetEnvCmd()
- }
- if sdk.ID == defaultID {
- defaultEnv = sdk.GetEnvCmd()
- }
+
+ if sdk, exist := s.Sdks[id]; exist {
+ return sdk.GetEnvCmd()
}
+
+ if sdk, exist := s.Sdks[defaultID]; defaultID != "" && exist {
+ return sdk.GetEnvCmd()
+ }
+
// Return default env that may be empty
- return defaultEnv
+ return []string{}
}
diff --git a/lib/folder/folder-interface.go b/lib/folder/folder-interface.go
index 4beccb8..9eb6829 100644
--- a/lib/folder/folder-interface.go
+++ b/lib/folder/folder-interface.go
@@ -1,12 +1,12 @@
package folder
// FolderType definition
-type FolderType int
+type FolderType string
const (
- TypePathMap = 1
- TypeCloudSync = 2
- TypeCifsSmb = 3
+ TypePathMap = "PathMap"
+ TypeCloudSync = "CloudSync"
+ TypeCifsSmb = "CIFS"
)
// Folder Status definition
@@ -61,10 +61,13 @@ type FolderConfig struct {
// PathMapConfig Path mapping specific data
type PathMapConfig struct {
ServerPath string `json:"serverPath"`
+
+ // Don't keep temporary file name (IOW we don't want to save it and reuse it)
+ CheckFile string `json:"checkFile" xml:"-"`
+ CheckContent string `json:"checkContent" xml:"-"`
}
// CloudSyncConfig CloudSync (AKA Syncthing) specific data
type CloudSyncConfig struct {
- SyncThingID string `json:"syncThingID"`
- BuilderSThgID string `json:"builderSThgID"`
+ SyncThingID string `json:"syncThingID"`
}
diff --git a/lib/folder/folder-pathmap.go b/lib/folder/folder-pathmap.go
index 1020026..e200164 100644
--- a/lib/folder/folder-pathmap.go
+++ b/lib/folder/folder-pathmap.go
@@ -24,13 +24,20 @@ type PathMap struct {
func NewFolderPathMap(gc *xdsconfig.Config) *PathMap {
f := PathMap{
globalConfig: gc,
+ config: FolderConfig{
+ Status: StatusDisable,
+ },
}
return &f
}
// NewUID Get a UUID
func (f *PathMap) NewUID(suffix string) string {
- return uuid.NewV1().String() + "_" + suffix
+ uuid := uuid.NewV1().String()
+ if len(suffix) > 0 {
+ uuid += "_" + suffix
+ }
+ return uuid
}
// Add a new folder
@@ -55,22 +62,43 @@ func (f *PathMap) Add(cfg FolderConfig) (*FolderConfig, error) {
if !common.Exists(dir) {
return nil, fmt.Errorf("ServerPath directory is not accessible: %s", dir)
}
- file, err := ioutil.TempFile(dir, "xds_pathmap_check")
- if err != nil {
- return nil, fmt.Errorf("ServerPath sanity check error: %s", err.Error())
- }
- defer os.Remove(file.Name())
-
- msg := "sanity check PathMap Add folder"
- n, err := file.Write([]byte(msg))
- if err != nil || n != len(msg) {
- return nil, fmt.Errorf("ServerPath sanity check error: %s", err.Error())
- }
f.config = cfg
f.config.RootPath = dir
f.config.DataPathMap.ServerPath = dir
f.config.IsInSync = true
+
+ // Verify file created by XDS agent when needed
+ if cfg.DataPathMap.CheckFile != "" {
+ errMsg := "ServerPath sanity check error (%d): %v"
+ ckFile := f.ConvPathCli2Svr(cfg.DataPathMap.CheckFile)
+ if !common.Exists(ckFile) {
+ return nil, fmt.Errorf(errMsg, 1, "file not present")
+ }
+ if cfg.DataPathMap.CheckContent != "" {
+ fd, err := os.OpenFile(ckFile, os.O_APPEND|os.O_RDWR, 0600)
+ if err != nil {
+ return nil, fmt.Errorf(errMsg, 2, err)
+ }
+ defer fd.Close()
+
+ // Check specific message written by agent
+ content, err := ioutil.ReadAll(fd)
+ if err != nil {
+ return nil, fmt.Errorf(errMsg, 3, err)
+ }
+ if string(content) != cfg.DataPathMap.CheckContent {
+ return nil, fmt.Errorf(errMsg, 4, "file content differ")
+ }
+
+ // Write a specific message that will be check back on agent side
+ msg := "Pathmap checked message written by xds-server ID: " + f.globalConfig.ServerUID + "\n"
+ if n, err := fd.WriteString(msg); n != len(msg) || err != nil {
+ return nil, fmt.Errorf(errMsg, 5, err)
+ }
+ }
+ }
+
f.config.Status = StatusEnable
return &f.config, nil
diff --git a/lib/folder/folder-st-disable.go b/lib/folder/folder-st-disable.go
index f90b776..7b53ca8 100644
--- a/lib/folder/folder-st-disable.go
+++ b/lib/folder/folder-st-disable.go
@@ -25,7 +25,11 @@ func NewFolderSTDisable(gc *xdsconfig.Config) *STFolderDisable {
// NewUID Get a UUID
func (f *STFolderDisable) NewUID(suffix string) string {
- return uuid.NewV1().String() + "_" + suffix
+ uuid := uuid.NewV1().String()
+ if len(suffix) > 0 {
+ uuid += "_" + suffix
+ }
+ return uuid
}
// Add a new folder
diff --git a/lib/model/folders.go b/lib/model/folders.go
index 576c4a2..b8e6cf5 100644
--- a/lib/model/folders.go
+++ b/lib/model/folders.go
@@ -146,6 +146,27 @@ func (f *Folders) SaveConfig() error {
return foldersConfigWrite(f.fileOnDisk, f.getConfigArrUnsafe())
}
+// ResolveID Complete a Folder ID (helper for user that can use partial ID value)
+func (f *Folders) ResolveID(id string) (string, error) {
+ if id == "" {
+ return "", nil
+ }
+
+ match := []string{}
+ for iid := range f.folders {
+ if strings.HasPrefix(iid, id) {
+ match = append(match, iid)
+ }
+ }
+
+ if len(match) == 1 {
+ return match[0], nil
+ } else if len(match) == 0 {
+ return id, fmt.Errorf("Unknown id")
+ }
+ return id, fmt.Errorf("Multiple IDs found with provided prefix: " + id)
+}
+
// Get returns the folder config or nil if not existing
func (f *Folders) Get(id string) *folder.IFOLDER {
if id == "" {
@@ -168,8 +189,7 @@ func (f *Folders) GetConfigArr() []folder.FolderConfig {
// getConfigArrUnsafe Same as GetConfigArr without mutex protection
func (f *Folders) getConfigArrUnsafe() []folder.FolderConfig {
- var conf []folder.FolderConfig
-
+ conf := []folder.FolderConfig{}
for _, v := range f.folders {
conf = append(conf, (*v).GetConfig())
}
@@ -214,24 +234,23 @@ func (f *Folders) createUpdate(newF folder.FolderConfig, create bool, initial bo
return nil, fmt.Errorf("Unsupported folder type")
}
+ // Allocate a new UUID
+ if create {
+ newF.ID = fld.NewUID("")
+ }
+ if !create && newF.ID == "" {
+ return nil, fmt.Errorf("Cannot update folder with null ID")
+ }
+
// Set default value if needed
if newF.Status == "" {
newF.Status = folder.StatusDisable
}
if newF.Label == "" {
- newF.Label = filepath.Base(newF.ClientPath) + "_" + newF.ID[0:8]
- }
-
- // Allocate a new UUID
- if create {
- i := len(newF.Label)
- if i > 20 {
- i = 20
+ newF.Label = filepath.Base(newF.ClientPath)
+ if len(newF.ID) > 8 {
+ newF.Label += "_" + newF.ID[0:8]
}
- newF.ID = fld.NewUID(newF.Label[:i])
- }
- if !create && newF.ID == "" {
- return nil, fmt.Errorf("Cannot update folder with null ID")
}
// Normalize path (needed for Windows path including bashlashes)
diff --git a/lib/session/session.go b/lib/session/session.go
index d4e1ad3..60b7b8a 100644
--- a/lib/session/session.go
+++ b/lib/session/session.go
@@ -36,27 +36,29 @@ type ClientSession struct {
// Sessions holds client sessions
type Sessions struct {
- router *gin.Engine
- cookieMaxAge int64
- sessMap map[string]ClientSession
- mutex sync.Mutex
- log *logrus.Logger
- stop chan struct{} // signals intentional stop
+ router *gin.Engine
+ cookieMaxAge int64
+ sessMap map[string]ClientSession
+ mutex sync.Mutex
+ log *logrus.Logger
+ LogLevelSilly bool
+ stop chan struct{} // signals intentional stop
}
// NewClientSessions .
-func NewClientSessions(router *gin.Engine, log *logrus.Logger, cookieMaxAge string) *Sessions {
+func NewClientSessions(router *gin.Engine, log *logrus.Logger, cookieMaxAge string, sillyLog bool) *Sessions {
ckMaxAge, err := strconv.ParseInt(cookieMaxAge, 10, 0)
if err != nil {
ckMaxAge = 0
}
s := Sessions{
- router: router,
- cookieMaxAge: ckMaxAge,
- sessMap: make(map[string]ClientSession),
- mutex: sync.NewMutex(),
- log: log,
- stop: make(chan struct{}),
+ router: router,
+ cookieMaxAge: ckMaxAge,
+ sessMap: make(map[string]ClientSession),
+ mutex: sync.NewMutex(),
+ log: log,
+ LogLevelSilly: sillyLog,
+ stop: make(chan struct{}),
}
s.router.Use(s.Middleware())
@@ -197,15 +199,13 @@ func (s *Sessions) refresh(sid string) {
}
func (s *Sessions) monitorSessMap() {
- const dbgFullTrace = false // for debugging
-
for {
select {
case <-s.stop:
s.log.Debugln("Stop monitorSessMap")
return
case <-time.After(sessionMonitorTime * time.Second):
- if dbgFullTrace {
+ if s.LogLevelSilly {
s.log.Debugf("Sessions Map size: %d", len(s.sessMap))
s.log.Debugf("Sessions Map : %v", s.sessMap)
}
diff --git a/lib/syncthing/folder-st.go b/lib/syncthing/folder-st.go
index 7e1fe55..f25a505 100644
--- a/lib/syncthing/folder-st.go
+++ b/lib/syncthing/folder-st.go
@@ -39,7 +39,11 @@ func (f *STFolder) NewUID(suffix string) string {
if i > 15 {
i = 15
}
- return uuid.NewV1().String()[:14] + f.st.MyID[:i] + "_" + suffix
+ uuid := uuid.NewV1().String()[:14] + f.st.MyID[:i]
+ if len(suffix) > 0 {
+ uuid += "_" + suffix
+ }
+ return uuid
}
// Add a new folder
@@ -57,10 +61,8 @@ func (f *STFolder) Add(cfg folder.FolderConfig) (*folder.FolderConfig, error) {
f.fConfig = cfg
- f.fConfig.DataCloudSync.BuilderSThgID = f.st.MyID // FIXME - should be removed after local ST config rework
-
// Update Syncthing folder
- // (expect if status is ErrorConfig)
+ // (except if status is ErrorConfig)
// TODO: add cache to avoid multiple requests on startup
if f.fConfig.Status != folder.StatusErrorConfig {
id, err := f.st.FolderChange(f.fConfig)
diff --git a/lib/syncthing/st.go b/lib/syncthing/st.go
index 99a17a1..d1ebbe6 100644
--- a/lib/syncthing/st.go
+++ b/lib/syncthing/st.go
@@ -34,16 +34,16 @@ type SyncThing struct {
STICmd *exec.Cmd
MyID string
Connected bool
+ Events *Events
// Private fields
binDir string
logsDir string
exitSTChan chan ExitChan
exitSTIChan chan ExitChan
- conf *xdsconfig.Config
client *common.HTTPClient
log *logrus.Logger
- Events *Events
+ conf *xdsconfig.Config
}
// ExitChan Channel used for process exit
@@ -134,7 +134,8 @@ func (s *SyncThing) startProc(exeName string, args []string, env []string, eChan
// Kill existing process (useful for debug ;-) )
if os.Getenv("DEBUG_MODE") != "" {
- exec.Command("bash", "-c", "pkill -9 "+exeName).Output()
+ fmt.Printf("\n!!! DEBUG_MODE set: KILL existing %s process(es) !!!\n", exeName)
+ exec.Command("bash", "-c", "ps -ax |grep "+exeName+" |grep "+s.BaseURL+" |cut -d' ' -f 1|xargs -I{} kill -9 {}").Output()
}
// When not set (or set to '.') set bin to path of xds-agent executable
@@ -227,7 +228,6 @@ func (s *SyncThing) Start() (*exec.Cmd, error) {
env := []string{
"STNODEFAULTFOLDER=1",
"STNOUPGRADE=1",
- "STNORESTART=1", // FIXME SEB remove ?
}
s.STCmd, err = s.startProc("syncthing", args, env, &s.exitSTChan)
@@ -317,7 +317,12 @@ func (s *SyncThing) Connect() error {
common.HTTPClientConfig{
URLPrefix: "/rest",
HeaderClientKeyName: "X-Syncthing-ID",
+ LogOut: s.conf.LogVerboseOut,
+ LogPrefix: "SYNCTHING: ",
+ LogLevel: common.HTTPLogLevelWarning,
})
+ s.client.SetLogLevel(s.log.Level.String())
+
if err != nil {
msg := ": " + err.Error()
if strings.Contains(err.Error(), "connection refused") {
@@ -329,11 +334,6 @@ func (s *SyncThing) Connect() error {
return fmt.Errorf("ERROR: cannot connect to Syncthing (null client)")
}
- // Redirect HTTP log into a file
- s.client.SetLogLevel(s.conf.Log.Level.String())
- s.client.LoggerPrefix = "SYNCTHING: "
- s.client.LoggerOut = s.conf.LogVerboseOut
-
s.MyID, err = s.IDGet()
if err != nil {
return fmt.Errorf("ERROR: cannot retrieve ID")
diff --git a/lib/syncthing/stfolder.go b/lib/syncthing/stfolder.go
index 70ac70a..503ba4b 100644
--- a/lib/syncthing/stfolder.go
+++ b/lib/syncthing/stfolder.go
@@ -7,7 +7,7 @@ import (
"strings"
"github.com/iotbzh/xds-server/lib/folder"
- "github.com/syncthing/syncthing/lib/config"
+ stconfig "github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/protocol"
)
@@ -32,9 +32,9 @@ func (s *SyncThing) FolderLoadFromStConfig(f *[]folder.FolderConfig) error {
}
for _, stFld := range stCfg.Folders {
- cliPath := strings.TrimPrefix(stFld.RawPath, s.conf.FileConf.ShareRootDir)
+ cliPath := strings.TrimPrefix(stFld.Path, s.conf.FileConf.ShareRootDir)
if cliPath == "" {
- cliPath = stFld.RawPath
+ cliPath = stFld.Path
}
*f = append(*f, folder.FolderConfig{
ID: stFld.ID,
@@ -69,7 +69,7 @@ func (s *SyncThing) FolderChange(f folder.FolderConfig) (string, error) {
return "", err
}
- newDevice := config.DeviceConfiguration{
+ newDevice := stconfig.DeviceConfiguration{
DeviceID: devID,
Name: stClientID,
Addresses: []string{"dynamic"},
@@ -95,22 +95,22 @@ func (s *SyncThing) FolderChange(f folder.FolderConfig) (string, error) {
id = stClientID[0:15] + "_" + label
}
- folder := config.FolderConfiguration{
- ID: id,
- Label: label,
- RawPath: filepath.Join(s.conf.FileConf.ShareRootDir, f.ClientPath),
+ folder := stconfig.FolderConfiguration{
+ ID: id,
+ Label: label,
+ Path: filepath.Join(s.conf.FileConf.ShareRootDir, f.ClientPath),
}
if s.conf.FileConf.SThgConf.RescanIntervalS > 0 {
folder.RescanIntervalS = s.conf.FileConf.SThgConf.RescanIntervalS
}
- folder.Devices = append(folder.Devices, config.FolderDeviceConfiguration{
+ folder.Devices = append(folder.Devices, stconfig.FolderDeviceConfiguration{
DeviceID: newDevice.DeviceID,
})
found = false
- var fld config.FolderConfiguration
+ var fld stconfig.FolderConfiguration
for _, fld = range stCfg.Folders {
if folder.ID == fld.ID {
fld = folder
@@ -155,8 +155,8 @@ func (s *SyncThing) FolderDelete(id string) error {
}
// FolderConfigGet Returns the configuration of a specific folder
-func (s *SyncThing) FolderConfigGet(folderID string) (config.FolderConfiguration, error) {
- fc := config.FolderConfiguration{}
+func (s *SyncThing) FolderConfigGet(folderID string) (stconfig.FolderConfiguration, error) {
+ fc := stconfig.FolderConfiguration{}
if folderID == "" {
return fc, fmt.Errorf("folderID not set")
}
diff --git a/lib/webserver/server.go b/lib/webserver/server.go
index a2fdf6f..85a2c40 100644
--- a/lib/webserver/server.go
+++ b/lib/webserver/server.go
@@ -30,6 +30,7 @@ type Server struct {
mfolders *model.Folders
sdks *crosssdk.SDKs
log *logrus.Logger
+ sillyLog bool
stop chan struct{} // signals intentional stop
}
@@ -37,7 +38,7 @@ const indexFilename = "index.html"
const cookieMaxAge = "3600"
// New creates an instance of Server
-func New(cfg *xdsconfig.Config, mfolders *model.Folders, sdks *crosssdk.SDKs, logr *logrus.Logger) *Server {
+func New(cfg *xdsconfig.Config, mfolders *model.Folders, sdks *crosssdk.SDKs, logr *logrus.Logger, sillyLog bool) *Server {
// Setup logging for gin router
if logr.Level == logrus.DebugLevel {
@@ -66,6 +67,7 @@ func New(cfg *xdsconfig.Config, mfolders *model.Folders, sdks *crosssdk.SDKs, lo
mfolders: mfolders,
sdks: sdks,
log: logr,
+ sillyLog: sillyLog,
stop: make(chan struct{}),
}
@@ -83,7 +85,7 @@ func (s *Server) Serve() error {
s.router.Use(s.middlewareCORS())
// Sessions manager
- s.sessions = session.NewClientSessions(s.router, s.log, cookieMaxAge)
+ s.sessions = session.NewClientSessions(s.router, s.log, cookieMaxAge, s.sillyLog)
// Create REST API
s.api = apiv1.New(s.router, s.sessions, s.cfg, s.mfolders, s.sdks)
diff --git a/lib/xdsconfig/builderconfig.go b/lib/xdsconfig/builderconfig.go
index c64fe9c..6fc1814 100644
--- a/lib/xdsconfig/builderconfig.go
+++ b/lib/xdsconfig/builderconfig.go
@@ -28,10 +28,7 @@ func NewBuilderConfig(stID string) (BuilderConfig, error) {
return b, nil
}
-// Copy makes a real copy of BuilderConfig
-func (c *BuilderConfig) Copy(n BuilderConfig) {
- // TODO
-}
+/*** Private ***/
func getLocalIP() (string, error) {
addrs, err := net.InterfaceAddrs()
diff --git a/lib/xdsconfig/config.go b/lib/xdsconfig/config.go
index 84e0778..0fc1346 100644
--- a/lib/xdsconfig/config.go
+++ b/lib/xdsconfig/config.go
@@ -13,10 +13,12 @@ import (
// Config parameters (json format) of /config command
type Config struct {
- Version string `json:"version"`
- APIVersion string `json:"apiVersion"`
- VersionGitTag string `json:"gitTag"`
- Builder BuilderConfig `json:"builder"`
+ ServerUID string `json:"id"`
+ Version string `json:"version"`
+ APIVersion string `json:"apiVersion"`
+ VersionGitTag string `json:"gitTag"`
+ SupportedSharing map[string]bool `json:"supportedSharing"`
+ Builder BuilderConfig `json:"builder"`
// Private (un-exported fields in REST GET /config route)
Options Options `json:"-"`
@@ -55,12 +57,19 @@ func Init(cliCtx *cli.Context, log *logrus.Logger) (*Config, error) {
dfltSTHomeDir = resDir
}
+ uuid, err := ServerIDGet()
+ if err != nil {
+ return nil, err
+ }
+
// Define default configuration
c := Config{
- Version: cliCtx.App.Metadata["version"].(string),
- APIVersion: DefaultAPIVersion,
- VersionGitTag: cliCtx.App.Metadata["git-tag"].(string),
- Builder: BuilderConfig{},
+ ServerUID: uuid,
+ Version: cliCtx.App.Metadata["version"].(string),
+ APIVersion: DefaultAPIVersion,
+ VersionGitTag: cliCtx.App.Metadata["git-tag"].(string),
+ Builder: BuilderConfig{},
+ SupportedSharing: map[string]bool{ /*FIXME USE folder.TypePathMap*/ "PathMap": true},
Options: Options{
ConfigFile: cliCtx.GlobalString("config"),
@@ -79,6 +88,8 @@ func Init(cliCtx *cli.Context, log *logrus.Logger) (*Config, error) {
Log: log,
}
+ c.Log.Infoln("Server UUID: ", uuid)
+
// config file settings overwrite default config
err = readGlobalConfig(&c, c.Options.ConfigFile)
if err != nil {
@@ -121,8 +132,9 @@ func Init(cliCtx *cli.Context, log *logrus.Logger) (*Config, error) {
return nil, fmt.Errorf("Cannot create logs dir: %v", err)
}
}
- c.Log.Infoln("Logs file: ", c.Options.LogFile)
- c.Log.Infoln("Logs directory: ", c.FileConf.LogsDir)
+
+ c.Log.Infoln("Logs file: ", c.Options.LogFile)
+ c.Log.Infoln("Logs directory: ", c.FileConf.LogsDir)
return &c, nil
}
diff --git a/lib/xdsconfig/data.go b/lib/xdsconfig/data.go
new file mode 100644
index 0000000..65e0fc6
--- /dev/null
+++ b/lib/xdsconfig/data.go
@@ -0,0 +1,87 @@
+package xdsconfig
+
+import (
+ "encoding/xml"
+ "fmt"
+ "os"
+
+ common "github.com/iotbzh/xds-common/golib"
+ uuid "github.com/satori/go.uuid"
+ "github.com/syncthing/syncthing/lib/sync"
+)
+
+// xmlServerData contains persistent data stored/loaded by server
+type xmlServerData struct {
+ XMLName xml.Name `xml:"XDS-Server"`
+ Version string `xml:"version,attr"`
+ Data ServerData `xml:"server-data"`
+}
+
+type ServerData struct {
+ ID string `xml:"id"`
+}
+
+var sdMutex = sync.NewMutex()
+
+// ServerIDGet
+func ServerIDGet() (string, error) {
+ var f string
+ var err error
+
+ d := ServerData{}
+ if f, err = ServerDataFilenameGet(); err != nil {
+ return "", err
+ }
+ if err = serverDataRead(f, &d); err != nil || d.ID == "" {
+ // Create a new uuid when not found
+ d.ID = uuid.NewV1().String()
+ if err := serverDataWrite(f, d); err != nil {
+ return "", err
+ }
+ }
+ return d.ID, nil
+}
+
+// serverDataRead reads data saved on disk
+func serverDataRead(file string, data *ServerData) error {
+ if !common.Exists(file) {
+ return fmt.Errorf("No folder config file found (%s)", file)
+ }
+
+ sdMutex.Lock()
+ defer sdMutex.Unlock()
+
+ fd, err := os.Open(file)
+ defer fd.Close()
+ if err != nil {
+ return err
+ }
+
+ xsd := xmlServerData{}
+ err = xml.NewDecoder(fd).Decode(&xsd)
+ if err == nil {
+ *data = xsd.Data
+ }
+ return err
+}
+
+// serverDataWrite writes persistant data to disk
+func serverDataWrite(file string, data ServerData) error {
+ sdMutex.Lock()
+ defer sdMutex.Unlock()
+
+ fd, err := os.OpenFile(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
+ defer fd.Close()
+ if err != nil {
+ return err
+ }
+
+ xsd := &xmlServerData{
+ Version: "1",
+ Data: data,
+ }
+
+ enc := xml.NewEncoder(fd)
+ enc.Indent("", " ")
+ return enc.Encode(xsd)
+}
diff --git a/lib/xdsconfig/fileconfig.go b/lib/xdsconfig/fileconfig.go
index 2651caf..dafb034 100644
--- a/lib/xdsconfig/fileconfig.go
+++ b/lib/xdsconfig/fileconfig.go
@@ -16,6 +16,8 @@ const (
ConfigDir = ".xds-server"
// GlobalConfigFilename Global config filename
GlobalConfigFilename = "config.json"
+ // ServerDataFilename Server data filename
+ ServerDataFilename = "server-data.xml"
// FoldersConfigFilename Folders config filename
FoldersConfigFilename = "server-config_folders.xml"
)
@@ -82,7 +84,7 @@ func readGlobalConfig(c *Config, confFile string) error {
// No config file found
return nil
}
- c.Log.Infof("Use config file: %s", *cFile)
+ c.Log.Infof("Use config file: %s", *cFile)
// TODO move on viper package to support comments in JSON and also
// bind with flags (command line options)
@@ -146,11 +148,20 @@ func readGlobalConfig(c *Config, confFile string) error {
return nil
}
-// FoldersConfigFilenameGet
-func FoldersConfigFilenameGet() (string, error) {
+func configFilenameGet(cfgFile string) (string, error) {
usr, err := user.Current()
if err != nil {
return "", err
}
- return path.Join(usr.HomeDir, ConfigDir, FoldersConfigFilename), nil
+ return path.Join(usr.HomeDir, ConfigDir, cfgFile), nil
+}
+
+// FoldersConfigFilenameGet
+func FoldersConfigFilenameGet() (string, error) {
+ return configFilenameGet(FoldersConfigFilename)
+}
+
+// ServerDataFilenameGet
+func ServerDataFilenameGet() (string, error) {
+ return configFilenameGet(ServerDataFilename)
}
diff --git a/main.go b/main.go
index c73d881..6089e74 100644
--- a/main.go
+++ b/main.go
@@ -14,6 +14,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
"github.com/iotbzh/xds-server/lib/crosssdk"
+ "github.com/iotbzh/xds-server/lib/folder"
"github.com/iotbzh/xds-server/lib/model"
"github.com/iotbzh/xds-server/lib/syncthing"
"github.com/iotbzh/xds-server/lib/webserver"
@@ -40,17 +41,18 @@ var AppSubVersion = "unknown-dev"
// Context holds the XDS server context
type Context struct {
- ProgName string
- Cli *cli.Context
- Config *xdsconfig.Config
- Log *logrus.Logger
- SThg *st.SyncThing
- SThgCmd *exec.Cmd
- SThgInotCmd *exec.Cmd
- MFolders *model.Folders
- SDKs *crosssdk.SDKs
- WWWServer *webserver.Server
- Exit chan os.Signal
+ ProgName string
+ Cli *cli.Context
+ Config *xdsconfig.Config
+ Log *logrus.Logger
+ LogLevelSilly bool
+ SThg *st.SyncThing
+ SThgCmd *exec.Cmd
+ SThgInotCmd *exec.Cmd
+ MFolders *model.Folders
+ SDKs *crosssdk.SDKs
+ WWWServer *webserver.Server
+ Exit chan os.Signal
}
// NewContext Create a new instance of XDS server
@@ -70,12 +72,15 @@ func NewContext(cliCtx *cli.Context) *Context {
}
log.Formatter = &logrus.TextFormatter{}
+ sillyVal, sillyLog := os.LookupEnv("XDS_LOG_SILLY")
+
// Define default configuration
ctx := Context{
- ProgName: cliCtx.App.Name,
- Cli: cliCtx,
- Log: log,
- Exit: make(chan os.Signal, 1),
+ ProgName: cliCtx.App.Name,
+ Cli: cliCtx,
+ Log: log,
+ LogLevelSilly: (sillyLog && sillyVal == "1"),
+ Exit: make(chan os.Signal, 1),
}
// register handler on SIGTERM / exit
@@ -147,7 +152,7 @@ func xdsApp(cliCtx *cli.Context) error {
}
ctx.Config.LogVerboseOut = fdLH
- logPrint(ctx, "Logging file for HTTP requests: %s\n", logFileHTTPReq)
+ logPrint(ctx, "Logging file for HTTP requests: %s\n", logFileHTTPReq)
}
// Create syncthing instance when section "syncthing" is present in config.json
@@ -193,6 +198,7 @@ func xdsApp(cliCtx *cli.Context) error {
if ctx.Config.Builder, err = xdsconfig.NewBuilderConfig(ctx.SThg.MyID); err != nil {
return cli.NewExitError(err, -4)
}
+ ctx.Config.SupportedSharing[folder.TypeCloudSync] = true
}
// Init model folder
@@ -210,7 +216,7 @@ func xdsApp(cliCtx *cli.Context) error {
}
// Create Web Server
- ctx.WWWServer = webserver.New(ctx.Config, ctx.MFolders, ctx.SDKs, ctx.Log)
+ ctx.WWWServer = webserver.New(ctx.Config, ctx.MFolders, ctx.SDKs, ctx.Log, ctx.LogLevelSilly)
// Run Web Server until exit requested (blocking call)
if err = ctx.WWWServer.Serve(); err != nil {
diff --git a/test/test_stdoutstderr.sh b/test/test_stdoutstderr.sh
new file mode 100755
index 0000000..652c4f8
--- /dev/null
+++ b/test/test_stdoutstderr.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+echo "1:STDOUT"
+>&2 echo "2:STDERR"
+echo "3:STDOUT"
+>&2 echo "4:STDERR"
+>&2 echo "5:STDERR"
+echo "6:STDOUT"
diff --git a/webapp/README.md b/webapp/README.md
index acee846..015a70d 100644
--- a/webapp/README.md
+++ b/webapp/README.md
@@ -1,45 +1,5 @@
-XDS Dashboard
-=============
+# XDS Server Web page
-This is the web application dashboard for Cross Development System.
+This a basic web page that just gives basic instructions.
-## 1. Prerequisites
-
-*nodejs* must be installed on your system and the below global node packages must be installed:
-
-> sudo npm install -g gulp-cli
-
-## 2. Installing dependencies
-
-Install dependencies by running the following command:
-
-> npm install
-
-`node_modules` and `typings` directories will be created during the install.
-
-## 3. Building the project
-
-Build the project by running the following command:
-
-> npm run clean & npm run build
-
-`dist` directory will be created during the build
-
-## 4. Starting the application
-
-Start the application by running the following command:
-
-> npm start
-
-The application will be displayed in the browser.
-
-
-## TODO
-
-- Upgrade to angular 2.4.9 or 2.4.10 AND rxjs 5.2.0
-- Complete README + package.json
-- Add prod mode and use update gulpfile tslint: "./tslint/prod.json"
-- Generate a bundle minified file, using systemjs-builder or find a better way
- http://stackoverflow.com/questions/35280582/angular2-too-many-file-requests-on-load
-- Add SASS support
- http://foundation.zurb.com/sites/docs/sass.html \ No newline at end of file
+XDS Dashboard is now part of [xds-agent](https://github.com/iotbzh/xds-agent).
diff --git a/webapp/assets/images/background_iot_bzh_light.png b/webapp/assets/images/background_iot_bzh_light.png
new file mode 100644
index 0000000..a119d63
--- /dev/null
+++ b/webapp/assets/images/background_iot_bzh_light.png
Binary files differ
diff --git a/webapp/assets/images/iot-graphx.jpg b/webapp/assets/images/iot-graphx.jpg
deleted file mode 100644
index 74c640a..0000000
--- a/webapp/assets/images/iot-graphx.jpg
+++ /dev/null
Binary files differ
diff --git a/webapp/assets/xds-agent-tarballs/.gitkeep b/webapp/assets/xds-agent-tarballs/.gitkeep
deleted file mode 100644
index e69de29..0000000
--- a/webapp/assets/xds-agent-tarballs/.gitkeep
+++ /dev/null
diff --git a/webapp/bs-config.json b/webapp/bs-config.json
deleted file mode 100644
index 0041c6d..0000000
--- a/webapp/bs-config.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "port": 8000,
- "files": [
- "dist/**/*.{html,htm,css,js}"
- ],
- "server": {
- "baseDir": "dist"
- }
-} \ No newline at end of file
diff --git a/webapp/gulp.conf.js b/webapp/gulp.conf.js
deleted file mode 100644
index 0529c02..0000000
--- a/webapp/gulp.conf.js
+++ /dev/null
@@ -1,34 +0,0 @@
-"use strict";
-
-module.exports = {
- prodMode: process.env.PRODUCTION || false,
- outDir: "dist",
- paths: {
- tsSources: ["src/**/*.ts"],
- srcDir: "src",
- assets: ["assets/**"],
- node_modules_libs: [
- 'core-js/client/shim.min.js',
- 'reflect-metadata/Reflect.js',
- 'rxjs-system-bundle/*.min.js',
- 'socket.io-client/dist/socket.io*.js',
- 'systemjs/dist/system-polyfills.js',
- 'systemjs/dist/system.src.js',
- 'zone.js/dist/**',
- '@angular/**/bundles/**',
- 'ngx-cookie/bundles/**',
- 'ngx-bootstrap/bundles/**',
- 'bootstrap/dist/**',
- 'moment/*.min.js',
- 'font-awesome-animation/dist/font-awesome-animation.min.css',
- 'font-awesome/css/font-awesome.min.css',
- 'font-awesome/fonts/**'
- ]
- },
- deploy: {
- target_ip: 'ip',
- username: "user",
- //port: 6666,
- dir: '/tmp/xds-server'
- }
-} \ No newline at end of file
diff --git a/webapp/gulpfile.js b/webapp/gulpfile.js
deleted file mode 100644
index 0226380..0000000
--- a/webapp/gulpfile.js
+++ /dev/null
@@ -1,123 +0,0 @@
-"use strict";
-//FIXME in VSC/eslint or add to typings declare function require(v: string): any;
-
-// FIXME: Rework based on
-// https://github.com/iotbzh/app-framework-templates/blob/master/templates/hybrid-html5/gulpfile.js
-// AND
-// https://github.com/antonybudianto/angular-starter
-// and/or
-// https://github.com/smmorneau/tour-of-heroes/blob/master/gulpfile.js
-
-const gulp = require("gulp"),
- gulpif = require('gulp-if'),
- del = require("del"),
- sourcemaps = require('gulp-sourcemaps'),
- tsc = require("gulp-typescript"),
- tsProject = tsc.createProject("tsconfig.json"),
- tslint = require('gulp-tslint'),
- gulpSequence = require('gulp-sequence'),
- rsync = require('gulp-rsync'),
- conf = require('./gulp.conf');
-
-
-var tslintJsonFile = "./tslint.json"
-if (conf.prodMode) {
- tslintJsonFile = "./tslint.prod.json"
-}
-
-
-/**
- * Remove output directory.
- */
-gulp.task('clean', (cb) => {
- return del([conf.outDir], cb);
-});
-
-/**
- * Lint all custom TypeScript files.
- */
-gulp.task('tslint', function() {
- return gulp.src(conf.paths.tsSources)
- .pipe(tslint({
- formatter: 'verbose',
- configuration: tslintJsonFile
- }))
- .pipe(tslint.report());
-});
-
-/**
- * Compile TypeScript sources and create sourcemaps in build directory.
- */
-gulp.task("compile", ["tslint"], function() {
- var tsResult = gulp.src(conf.paths.tsSources)
- .pipe(sourcemaps.init())
- .pipe(tsProject());
- return tsResult.js
- .pipe(sourcemaps.write(".", { sourceRoot: '/src' }))
- .pipe(gulp.dest(conf.outDir));
-});
-
-/**
- * Copy all resources that are not TypeScript files into build directory.
- */
-gulp.task("resources", function() {
- return gulp.src(["src/**/*", "!**/*.ts"])
- .pipe(gulp.dest(conf.outDir));
-});
-
-/**
- * Copy all assets into build directory.
- */
-gulp.task("assets", function() {
- return gulp.src(conf.paths.assets)
- .pipe(gulp.dest(conf.outDir + "/assets"));
-});
-
-/**
- * Copy all required libraries into build directory.
- */
-gulp.task("libs", function() {
- return gulp.src(conf.paths.node_modules_libs,
- { cwd: "node_modules/**" }) /* Glob required here. */
- .pipe(gulp.dest(conf.outDir + "/lib"));
-});
-
-/**
- * Watch for changes in TypeScript, HTML and CSS files.
- */
-gulp.task('watch', function () {
- gulp.watch([conf.paths.tsSources], ['compile']).on('change', function (e) {
- console.log('TypeScript file ' + e.path + ' has been changed. Compiling.');
- });
- gulp.watch(["src/**/*.html", "src/**/*.css"], ['resources']).on('change', function (e) {
- console.log('Resource file ' + e.path + ' has been changed. Updating.');
- });
-});
-
-/**
- * Build the project.
- */
-gulp.task("build", ['compile', 'resources', 'libs', 'assets'], function() {
- console.log("Building the project ...");
-});
-
-/**
- * Deploy the project on another machine/container
- */
-gulp.task('rsync', function () {
- return gulp.src(conf.outDir)
- .pipe(rsync({
- root: conf.outDir,
- username: conf.deploy.username,
- hostname: conf.deploy.target_ip,
- port: conf.deploy.port || null,
- archive: true,
- recursive: true,
- compress: true,
- progress: false,
- incremental: true,
- destination: conf.deploy.dir
- }));
-});
-
-gulp.task('deploy', gulpSequence('build', 'rsync')); \ No newline at end of file
diff --git a/webapp/package.json b/webapp/package.json
index b08ce0b..5acda9f 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -1,63 +1,17 @@
{
- "name": "xds-server-dashboard",
- "version": "1.0.0",
- "description": "X (cross) Development System dashboard",
- "scripts": {
- "clean": "gulp clean",
- "compile": "gulp compile",
- "build": "gulp build",
- "start": "concurrently --kill-others \"gulp watch\" \"lite-server\""
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/iotbzh/xds-server"
- },
- "author": "Sebastien Douheret [IoT.bzh]",
- "license": "Apache-2.0",
- "bugs": {
- "url": "https://github.com/iotbzh/xds-server/issues"
- },
- "dependencies": {
- "@angular/common": "2.4.4",
- "@angular/compiler": "2.4.4",
- "@angular/core": "2.4.4",
- "@angular/forms": "2.4.4",
- "@angular/http": "2.4.4",
- "@angular/platform-browser": "2.4.4",
- "@angular/platform-browser-dynamic": "2.4.4",
- "@angular/router": "3.4.4",
- "@angular/upgrade": "2.4.4",
- "@types/core-js": "0.9.35",
- "@types/node": "7.0.5",
- "@types/socket.io-client": "^1.4.29",
- "bootstrap": "^3.3.7",
- "core-js": "^2.4.1",
- "font-awesome": "^4.7.0",
- "font-awesome-animation": "0.0.10",
- "ngx-bootstrap": "1.6.6",
- "ngx-cookie": "1.0.0",
- "reflect-metadata": "^0.1.8",
- "rxjs": "5.0.3",
- "rxjs-system-bundle": "5.0.3",
- "socket.io-client": "^1.7.3",
- "socketio": "^1.0.0",
- "systemjs": "0.20.0",
- "zone.js": "^0.7.6"
- },
- "devDependencies": {
- "concurrently": "^3.1.0",
- "del": "^2.2.0",
- "gulp": "^3.9.1",
- "gulp-if": "2.0.2",
- "gulp-rsync": "0.0.7",
- "gulp-sequence": "^0.4.6",
- "gulp-sourcemaps": "^1.9.1",
- "gulp-tslint": "^7.0.1",
- "gulp-typescript": "^3.1.3",
- "lite-server": "^2.2.2",
- "ts-node": "^1.7.2",
- "tslint": "^4.0.2",
- "typescript": "^2.2.1",
- "typings": "^2.0.0"
+ "name": "xds-server-minimal-dashboard",
+ "version": "1.0.0",
+ "description": "X (cross) Development System minimal dashboard",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/iotbzh/xds-server"
+ },
+ "author": "Sebastien Douheret [IoT.bzh]",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://github.com/iotbzh/xds-server/issues"
+ },
+ "dependencies": {
+ "font-awesome": "^4.7.0"
+ }
}
-}
diff --git a/webapp/src/app/alert/alert.component.ts b/webapp/src/app/alert/alert.component.ts
deleted file mode 100644
index 672d7bf..0000000
--- a/webapp/src/app/alert/alert.component.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { Component } from '@angular/core';
-import { Observable } from 'rxjs';
-
-import {AlertService, IAlert} from '../services/alert.service';
-
-@Component({
- selector: 'app-alert',
- template: `
- <div style="width:80%; margin-left:auto; margin-right:auto;" *ngFor="let alert of (alerts$ | async)">
- <alert *ngIf="alert.show" [type]="alert.type" [dismissible]="alert.dismissible" [dismissOnTimeout]="alert.dismissTimeout"
- (onClose)="onClose(alert)">
- <div style="text-align:center;" [innerHtml]="alert.msg"></div>
- </alert>
- </div>
- `
-})
-
-export class AlertComponent {
-
- alerts$: Observable<IAlert[]>;
-
- constructor(private alertSvr: AlertService) {
- this.alerts$ = this.alertSvr.alerts;
- }
-
- onClose(al) {
- this.alertSvr.del(al);
- }
-
-}
diff --git a/webapp/src/app/app.component.css b/webapp/src/app/app.component.css
deleted file mode 100644
index a47ad13..0000000
--- a/webapp/src/app/app.component.css
+++ /dev/null
@@ -1,31 +0,0 @@
-.navbar {
- background-color: whitesmoke;
-}
-
-.navbar-brand {
- font-size: x-large;
- font-variant: small-caps;
- color: #5a28a1;
-}
-
-a.navbar-brand {
- margin-top: 5px;
-}
-
-
-.navbar-nav ul li a {
- color: #fff;
-}
-
-.menu-text {
- color: #fff;
-}
-
-#logo-iot {
- padding: 0 2px;
- height: 60px;
-}
-
-li>a {
- color:#5a28a1;
-}
diff --git a/webapp/src/app/app.component.html b/webapp/src/app/app.component.html
deleted file mode 100644
index a889b12..0000000
--- a/webapp/src/app/app.component.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<nav class="navbar navbar-fixed-top">
- <!-- navbar-inverse"> -->
- <div class="container-fluid">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#myNavbar"
- [attr.aria-expanded]="!isCollapsed" (click)="isCollapsed = !isCollapsed;" [ngClass]="{'collapsed': isCollapsed}">
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
-
- <img class="navbar-brand" id="logo-iot" src="assets/images/iot-bzh-logo-small.png">
- <a class="navbar-brand" href="#">X(cross) Development System Dashboard</a>
- </div>
-
- <div class="collapse navbar-collapse" [ngClass]="{'in': !isCollapsed}" id="myNavbar">
- <ul class="nav navbar-nav navbar-right">
- <li><a routerLink="/config"><i class="fa fa-2x fa-cog" title="Open configuration page" (click)="isCollapsed=true;"></i></a></li>
- <li><a routerLink="/devel"><i class="fa fa-2x fa-play-circle" title="Open build page" (click)="isCollapsed=true;"></i></a></li>
- <li><a routerLink="/home"><i class="fa fa-2x fa-home" title="Back to home page" (click)="isCollapsed=true;"></i></a></li>
- </ul>
- </div>
- </div>
-</nav>
-
-<app-alert id="alert"></app-alert>
-
-<div style="margin:10px;">
- <router-outlet></router-outlet>
-</div>
diff --git a/webapp/src/app/app.component.ts b/webapp/src/app/app.component.ts
deleted file mode 100644
index 40cfb24..0000000
--- a/webapp/src/app/app.component.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Component, OnInit, OnDestroy } from "@angular/core";
-import { Router } from '@angular/router';
-//TODO import {TranslateService} from "ng2-translate";
-
-@Component({
- selector: 'app',
- templateUrl: './app/app.component.html',
- styleUrls: ['./app/app.component.css']
-})
-
-export class AppComponent implements OnInit, OnDestroy {
-
- isCollapsed: boolean = true;
-
- private defaultLanguage: string = 'en';
-
- // I initialize the app component.
- //TODO constructor(private translate: TranslateService) {
- constructor(public router: Router) {
- }
-
- ngOnInit() {
-
- /* TODO
- this.translate.addLangs(["en", "fr"]);
- this.translate.setDefaultLang(this.defaultLanguage);
-
- let browserLang = this.translate.getBrowserLang();
- this.translate.use(browserLang.match(/en|fr/) ? browserLang : this.defaultLanguage);
- */
- }
-
- ngOnDestroy(): void {
- }
-
-
-}
diff --git a/webapp/src/app/app.module.ts b/webapp/src/app/app.module.ts
deleted file mode 100644
index 10ff7a4..0000000
--- a/webapp/src/app/app.module.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { NgModule } from '@angular/core';
-import { BrowserModule } from '@angular/platform-browser';
-import { HttpModule } from "@angular/http";
-import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { CookieModule } from 'ngx-cookie';
-
-// Import bootstrap
-import { AlertModule } from 'ngx-bootstrap/alert';
-import { ModalModule } from 'ngx-bootstrap/modal';
-import { AccordionModule } from 'ngx-bootstrap/accordion';
-import { CarouselModule } from 'ngx-bootstrap/carousel';
-import { PopoverModule } from 'ngx-bootstrap/popover';
-import { CollapseModule } from 'ngx-bootstrap/collapse';
-import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
-
-// Import the application components and services.
-import { Routing, AppRoutingProviders } from './app.routing';
-import { AppComponent } from "./app.component";
-import { AlertComponent } from './alert/alert.component';
-import { ConfigComponent } from "./config/config.component";
-import { DlXdsAgentComponent, CapitalizePipe } from "./config/downloadXdsAgent.component";
-import { ProjectCardComponent } from "./projects/projectCard.component";
-import { ProjectReadableTypePipe } from "./projects/projectCard.component";
-import { ProjectsListAccordionComponent } from "./projects/projectsListAccordion.component";
-import { ProjectAddModalComponent} from "./projects/projectAddModal.component";
-import { SdkCardComponent } from "./sdks/sdkCard.component";
-import { SdksListAccordionComponent } from "./sdks/sdksListAccordion.component";
-import { SdkSelectDropdownComponent } from "./sdks/sdkSelectDropdown.component";
-import { SdkAddModalComponent} from "./sdks/sdkAddModal.component";
-
-import { HomeComponent } from "./home/home.component";
-import { DevelComponent } from "./devel/devel.component";
-import { BuildComponent } from "./devel/build/build.component";
-import { DeployComponent } from "./devel/deploy/deploy.component";
-import { XDSServerService } from "./services/xdsserver.service";
-import { XDSAgentService } from "./services/xdsagent.service";
-import { SyncthingService } from "./services/syncthing.service";
-import { ConfigService } from "./services/config.service";
-import { AlertService } from './services/alert.service';
-import { UtilsService } from './services/utils.service';
-import { SdkService } from "./services/sdk.service";
-
-
-
-@NgModule({
- imports: [
- BrowserModule,
- HttpModule,
- FormsModule,
- ReactiveFormsModule,
- Routing,
- CookieModule.forRoot(),
- AlertModule.forRoot(),
- ModalModule.forRoot(),
- AccordionModule.forRoot(),
- CarouselModule.forRoot(),
- PopoverModule.forRoot(),
- CollapseModule.forRoot(),
- BsDropdownModule.forRoot(),
- ],
- declarations: [
- AppComponent,
- AlertComponent,
- HomeComponent,
- BuildComponent,
- DevelComponent,
- DeployComponent,
- ConfigComponent,
- DlXdsAgentComponent,
- CapitalizePipe,
- ProjectCardComponent,
- ProjectReadableTypePipe,
- ProjectsListAccordionComponent,
- ProjectAddModalComponent,
- SdkCardComponent,
- SdksListAccordionComponent,
- SdkSelectDropdownComponent,
- SdkAddModalComponent,
- ],
- providers: [
- AppRoutingProviders,
- {
- provide: Window,
- useValue: window
- },
- XDSServerService,
- XDSAgentService,
- ConfigService,
- SyncthingService,
- AlertService,
- UtilsService,
- SdkService,
- ],
- bootstrap: [AppComponent]
-})
-export class AppModule {
-}
diff --git a/webapp/src/app/app.routing.ts b/webapp/src/app/app.routing.ts
deleted file mode 100644
index f0d808f..0000000
--- a/webapp/src/app/app.routing.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import {Routes, RouterModule} from "@angular/router";
-import {ModuleWithProviders} from "@angular/core";
-import {ConfigComponent} from "./config/config.component";
-import {HomeComponent} from "./home/home.component";
-import {DevelComponent} from "./devel/devel.component";
-
-
-const appRoutes: Routes = [
- {path: '', redirectTo: 'home', pathMatch: 'full'},
-
- {path: 'config', component: ConfigComponent, data: {title: 'Config'}},
- {path: 'home', component: HomeComponent, data: {title: 'Home'}},
- {path: 'devel', component: DevelComponent, data: {title: 'Build & Deploy'}}
-];
-
-export const AppRoutingProviders: any[] = [];
-export const Routing: ModuleWithProviders = RouterModule.forRoot(appRoutes, {
- useHash: true
-});
diff --git a/webapp/src/app/config/config.component.css b/webapp/src/app/config/config.component.css
deleted file mode 100644
index 6412f9a..0000000
--- a/webapp/src/app/config/config.component.css
+++ /dev/null
@@ -1,35 +0,0 @@
-.fa-big {
- font-size: 20px;
- font-weight: bold;
-}
-
-.fa-size-x2 {
- font-size: 20px;
-}
-
-h2 {
- font-family: sans-serif;
- font-variant: small-caps;
- font-size: x-large;
-}
-
-th span {
- font-weight: 100;
-}
-
-th label {
- font-weight: 100;
- margin-bottom: 0;
-}
-
-tr.info>th {
- vertical-align: middle;
-}
-
-tr.info>td {
- vertical-align: middle;
-}
-
-.panel-heading {
- background: aliceblue;
-}
diff --git a/webapp/src/app/config/config.component.html b/webapp/src/app/config/config.component.html
deleted file mode 100644
index c36ba02..0000000
--- a/webapp/src/app/config/config.component.html
+++ /dev/null
@@ -1,106 +0,0 @@
-<div class="panel panel-default">
- <div class="panel-heading">
- <h2 class="panel-title" (click)="gConfigIsCollapsed = !gConfigIsCollapsed">
- Global Configuration
- <div class="pull-right">
- <span class="fa fa-fw fa-exchange fa-size-x2" [style.color]="((serverStatus$ | async)?.WS_connected)?'green':'red'"></span>
-
- <button class="btn btn-link" (click)="gConfigIsCollapsed = !gConfigIsCollapsed; $event.stopPropagation()">
- <span class="fa fa-big" [ngClass]="{'fa-angle-double-down': gConfigIsCollapsed, 'fa-angle-double-right': !gConfigIsCollapsed}"></span>
- </button>
- </div>
- </h2>
- </div>
- <div class="panel-body" [collapse]="gConfigIsCollapsed && (agentStatus$ | async)?.connected">
- <div class="row">
- <div class="col-xs-12">
- <table class="table table-condensed">
- <tbody>
- <tr [ngClass]="{'info': (agentStatus$ | async)?.connected, 'danger': !(agentStatus$ | async)?.connected}">
- <th><label>XDS local Agent URL</label></th>
- <td> <input type="text" [(ngModel)]="xdsAgentUrl"></td>
- <td style="white-space: nowrap">
- <div class="btn-group">
- <button class="btn btn-link" (click)="xdsAgentRestartConn()"><span class="fa fa-refresh fa-size-x2"></span></button>
- <dl-xds-agent class="button" [packageUrls]="(config$ | async).xdsAgentPackages"></dl-xds-agent>
- </div>
- </td>
- </tr>
- <tr class="info">
- <th><label>Local Agent connection retry</label></th>
- <td> <input type="text" [(ngModel)]="xdsAgentRetry" (ngModelChange)="showApplyBtn['retry'] = true"></td>
- <td>
- <button *ngIf="showApplyBtn['retry']" class="btn btn-primary btn-xs" (click)="submitGlobConf('retry')">APPLY</button>
- </td>
- </tr>
- <tr [ngClass]="{'info': (localSTStatus$ | async)?.connected, 'danger': !(localSTStatus$ | async)?.connected}">
- <th><label>Local Sync-tool URL</label></th>
- <td> <input type="text" [(ngModel)]="syncToolUrl"></td>
- <td>
- <button class="btn btn-link" (click)="xdsAgentRestartConn()"><span class="fa fa-refresh fa-size-x2"></span></button>
- </td>
- </tr>
- <tr class="info">
- <th><label>Local Projects root directory</label></th>
- <td> <input type="text" [(ngModel)]="projectsRootDir" (ngModelChange)="showApplyBtn['rootDir'] = true"></td>
- <td>
- <button *ngIf="showApplyBtn['rootDir']" class="btn btn-primary btn-xs" (click)="submitGlobConf('rootDir')">APPLY</button>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- </div>
-</div>
-
-<div class="panel panel-default">
- <div class="panel-heading">
- <h2 class="panel-title" (click)="sdksIsCollapsed = !sdksIsCollapsed">
- Cross SDKs
- <div class="pull-right">
- <button class="btn btn-link" (click)="childSdkModal.show(); $event.stopPropagation()"><span class="fa fa-plus fa-size-x2"></span></button>
-
- <button class="btn btn-link" (click)="sdksIsCollapsed = !sdksIsCollapsed; $event.stopPropagation()">
- <span class="fa fa-big" [ngClass]="{'fa-angle-double-down': sdksIsCollapsed, 'fa-angle-double-right': !sdksIsCollapsed}"></span>
- </button>
- </div>
- </h2>
- </div>
- <div class="panel-body" [collapse]="sdksIsCollapsed">
- <div class="row col-xs-12">
- <sdks-list-accordion [sdks]="(sdks$ | async)"></sdks-list-accordion>
- </div>
- </div>
-</div>
-
-<div class="panel panel-default">
- <div class="panel-heading">
- <h2 class="panel-title" (click)="projectsIsCollapsed = !projectsIsCollapsed; $event.stopPropagation()">
- Projects
- <div class="pull-right">
- <button class="btn btn-link" (click)="childProjectModal.show(); $event.stopPropagation()"><span class="fa fa-plus fa-size-x2"></span></button>
-
- <button class="btn btn-link" (click)="projectsIsCollapsed = !projectsIsCollapsed; $event.stopPropagation()">
- <span class="fa fa-big" [ngClass]="{'fa-angle-double-down': projectsIsCollapsed, 'fa-angle-double-right': !projectsIsCollapsed}"></span>
- </button>
- </div>
- </h2>
- </div>
- <div class="panel-body" [collapse]="projectsIsCollapsed">
- <div class="row col-xs-12">
- <projects-list-accordion [projects]="(config$ | async).projects"></projects-list-accordion>
- </div>
- </div>
-</div>
-
-<!-- Modals -->
-<project-add-modal #childProjectModal [title]="'Add a new project'">
-</project-add-modal>
-<sdk-add-modal #childSdkModal [title]="'Add a new SDK'">
-</sdk-add-modal>
-
-<!-- only for debug -->
-<div *ngIf="false" class="row">
- {{config$ | async | json}}
-</div>
diff --git a/webapp/src/app/config/config.component.ts b/webapp/src/app/config/config.component.ts
deleted file mode 100644
index b107e81..0000000
--- a/webapp/src/app/config/config.component.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-import { Component, ViewChild, OnInit } from "@angular/core";
-import { Observable } from 'rxjs/Observable';
-import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms';
-import { CollapseModule } from 'ngx-bootstrap/collapse';
-
-import { ConfigService, IConfig, IxdsAgentPackage } from "../services/config.service";
-import { XDSServerService, IServerStatus, IXDSAgentInfo } from "../services/xdsserver.service";
-import { XDSAgentService, IAgentStatus } from "../services/xdsagent.service";
-import { SyncthingService, ISyncThingStatus } from "../services/syncthing.service";
-import { AlertService } from "../services/alert.service";
-import { ISdk, SdkService } from "../services/sdk.service";
-import { ProjectAddModalComponent } from "../projects/projectAddModal.component";
-import { SdkAddModalComponent } from "../sdks/sdkAddModal.component";
-
-@Component({
- templateUrl: './app/config/config.component.html',
- styleUrls: ['./app/config/config.component.css']
-})
-
-// Inspired from https://embed.plnkr.co/jgDTXknPzAaqcg9XA9zq/
-// and from http://plnkr.co/edit/vCdjZM?p=preview
-
-export class ConfigComponent implements OnInit {
- @ViewChild('childProjectModal') childProjectModal: ProjectAddModalComponent;
- @ViewChild('childSdkModal') childSdkModal: SdkAddModalComponent;
-
- config$: Observable<IConfig>;
- sdks$: Observable<ISdk[]>;
- serverStatus$: Observable<IServerStatus>;
- agentStatus$: Observable<IAgentStatus>;
- localSTStatus$: Observable<ISyncThingStatus>;
-
- curProj: number;
- userEditedLabel: boolean = false;
- xdsAgentPackages: IxdsAgentPackage[] = [];
-
- gConfigIsCollapsed: boolean = true;
- sdksIsCollapsed: boolean = true;
- projectsIsCollapsed: boolean = false;
-
- // TODO replace by reactive FormControl + add validation
- syncToolUrl: string;
- xdsAgentUrl: string;
- xdsAgentRetry: string;
- projectsRootDir: string; // FIXME: should be remove when projectAddModal will always return full path
- showApplyBtn = { // Used to show/hide Apply buttons
- "retry": false,
- "rootDir": false,
- };
-
- constructor(
- private configSvr: ConfigService,
- private xdsServerSvr: XDSServerService,
- private xdsAgentSvr: XDSAgentService,
- private stSvr: SyncthingService,
- private sdkSvr: SdkService,
- private alert: AlertService,
- ) {
- }
-
- ngOnInit() {
- this.config$ = this.configSvr.conf;
- this.sdks$ = this.sdkSvr.Sdks$;
- this.serverStatus$ = this.xdsServerSvr.Status$;
- this.agentStatus$ = this.xdsAgentSvr.Status$;
- this.localSTStatus$ = this.stSvr.Status$;
-
- // Bind xdsAgentUrl to baseURL
- this.config$.subscribe(cfg => {
- this.syncToolUrl = cfg.localSThg.URL;
- this.xdsAgentUrl = cfg.xdsAgent.URL;
- this.xdsAgentRetry = String(cfg.xdsAgent.retry);
- this.projectsRootDir = cfg.projectsRootDir;
- this.xdsAgentPackages = cfg.xdsAgentPackages;
- });
-
- }
-
- submitGlobConf(field: string) {
- switch (field) {
- case "retry":
- let re = new RegExp('^[0-9]+$');
- let rr = parseInt(this.xdsAgentRetry, 10);
- if (re.test(this.xdsAgentRetry) && rr >= 0) {
- this.configSvr.xdsAgentRetry = rr;
- } else {
- this.alert.warning("Not a valid number", true);
- }
- break;
- case "rootDir":
- this.configSvr.projectsRootDir = this.projectsRootDir;
- break;
- default:
- return;
- }
- this.showApplyBtn[field] = false;
- }
-
- xdsAgentRestartConn() {
- let aUrl = this.xdsAgentUrl;
- this.configSvr.syncToolURL = this.syncToolUrl;
- this.configSvr.xdsAgentUrl = aUrl;
- this.configSvr.loadProjects();
- }
-
-}
diff --git a/webapp/src/app/config/downloadXdsAgent.component.ts b/webapp/src/app/config/downloadXdsAgent.component.ts
deleted file mode 100644
index b35a17f..0000000
--- a/webapp/src/app/config/downloadXdsAgent.component.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import { Component, Input, Pipe, PipeTransform } from '@angular/core';
-
-import { IxdsAgentPackage } from "../services/config.service";
-
-@Component({
- selector: 'dl-xds-agent',
- /* XXX - cleanup
- template: `
- <template #popTemplate>
- <h3>Download xds-agent packages:</h3>
- <ul>
- <li *ngFor="let p of packageUrls">
- <a href="{{p.url}}">{{p.os | capitalize}} - {{p.arch}} ({{p.version}}) </a>
- </li>
- </ul>
- <button type="button" class="btn btn-sm" (click)="pop.hide()"> Cancel </button>
- </template>
- <button type="button" class="btn btn-link fa fa-download fa-size-x2"
- [popover]="popTemplate"
- #pop="bs-popover"
- placement="left">
- </button>
- `,
-*/
- template: `
- <template #popTemplate>
- <h3>Install xds-agent:</h3>
- <ul>
- <li>On Linux machine <a href="{{url_OS_Linux}}" target="_blank">
- <span class="fa fa-external-link"></span></a></li>
-
- <li>On Windows machine <a href="{{url_OS_Other}}" target="_blank"><span class="fa fa-external-link"></span></a></li>
-
- <li>On MacOS machine <a href="{{url_OS_Other}}" target="_blank"><span class="fa fa-external-link"></span></a></li>
- </ul>
- <button type="button" class="btn btn-sm" (click)="pop.hide()"> Cancel </button>
- </template>
- <button type="button" class="btn btn-link fa fa-download fa-size-x2"
- [popover]="popTemplate"
- #pop="bs-popover"
- placement="left">
- </button>
- `,
- styles: [`
- .fa-size-x2 {
- font-size: 20px;
- }
- `]
-})
-
-export class DlXdsAgentComponent {
-
- @Input() packageUrls: IxdsAgentPackage[];
-
- public url_OS_Linux = "https://en.opensuse.org/LinuxAutomotive#Installation_AGL_XDS";
- public url_OS_Other = "https://github.com/iotbzh/xds-agent#how-to-install-on-other-platform";
-}
-
-@Pipe({
- name: 'capitalize'
-})
-export class CapitalizePipe implements PipeTransform {
- transform(value: string): string {
- if (value) {
- return value.charAt(0).toUpperCase() + value.slice(1);
- }
- return value;
- }
-}
diff --git a/webapp/src/app/devel/build/build.component.css b/webapp/src/app/devel/build/build.component.css
deleted file mode 100644
index 695a89b..0000000
--- a/webapp/src/app/devel/build/build.component.css
+++ /dev/null
@@ -1,54 +0,0 @@
-.vcenter {
- display: inline-block;
- vertical-align: middle;
-}
-
-.blocks .btn-primary {
- margin-left: 5px;
- margin-right: 5px;
- margin-top: 5px;
- border-radius: 4px !important;
-}
-
-.table-center {
- width: 80%;
- margin-left: auto;
- margin-right: auto;
-}
-
-.table-borderless>tbody>tr>td,
-.table-borderless>tbody>tr>th,
-.table-borderless>tfoot>tr>td,
-.table-borderless>tfoot>tr>th,
-.table-borderless>thead>tr>td,
-.table-borderless>thead>tr>th {
- border: none;
-}
-
-.table-in-accordion>tbody>tr>th {
- width: 30%
-}
-
-.btn-large {
- width: 10em;
-}
-
-.fa-big {
- font-size: 18px;
- font-weight: bold;
-}
-
-.textarea-scroll {
- width: 100%;
- overflow-y: scroll;
-}
-
-h2 {
- font-family: sans-serif;
- font-variant: small-caps;
- font-size: x-large;
-}
-
-.panel-heading {
- background: aliceblue;
-}
diff --git a/webapp/src/app/devel/build/build.component.html b/webapp/src/app/devel/build/build.component.html
deleted file mode 100644
index 2bcd2c7..0000000
--- a/webapp/src/app/devel/build/build.component.html
+++ /dev/null
@@ -1,115 +0,0 @@
-<div class="panel panel-default">
- <div class="panel-heading">
- <h2 class="panel-title" (click)="buildIsCollapsed = !buildIsCollapsed">
- Build
- <div class="pull-right">
- <button class="btn btn-link" (click)="buildIsCollapsed = !buildIsCollapsed; $event.stopPropagation()">
- <span class="fa fa-big" [ngClass]="{'fa-angle-double-down': buildIsCollapsed, 'fa-angle-double-right': !buildIsCollapsed}"></span>
- </button>
- </div>
- </h2>
- </div>
- <div class="panel-body" [collapse]="buildIsCollapsed">
- <form [formGroup]="buildForm">
- <div class="col-xs-12">
- <table class="table table-borderless table-center">
- <tbody>
- <tr>
- <th>Cross SDK</th>
- <td>
- <!-- FIXME why not working ?
- <sdk-select-dropdown [sdks]="(sdks$ | async)"></sdk-select-dropdown>
- -->
- <sdk-select-dropdown></sdk-select-dropdown>
- </td>
- </tr>
- <tr>
- <th>Project root path</th>
- <td> <input type="text" disabled style="width:99%;" [value]="curProject && curProject.pathClient"></td>
- </tr>
- <tr>
- <th>Sub-path</th>
- <td> <input type="text" style="width:99%;" formControlName="subpath"> </td>
- </tr>
- <tr>
- <td colspan="2">
- <accordion>
- <accordion-group #group>
- <div accordion-heading>
- Advanced Settings
- <i class="pull-right float-xs-right fa" [ngClass]="{'fa-chevron-down': group.isOpen, 'fa-chevron-right': !group.isOpen}"></i>
- </div>
-
- <table class="table table-borderless table-in-accordion">
- <tbody>
- <tr>
- <th>Clean Command</th>
- <td> <input type="text" style="width:99%;" formControlName="cmdClean"> </td>
- </tr>
- <tr>
- <th>Pre-Build Command</th>
- <td> <input type="text" style="width:99%;" formControlName="cmdPrebuild"> </td>
- </tr>
- <tr>
- <th>Build Command</th>
- <td> <input type="text" style="width:99%;" formControlName="cmdBuild"> </td>
- </tr>
- <tr>
- <th>Populate Command</th>
- <td> <input type="text" style="width:99%;" formControlName="cmdPopulate"> </td>
- </tr>
- <tr>
- <th>Env variables</th>
- <td> <input type="text" style="width:99%;" formControlName="envVars"> </td>
- </tr>
- <tr *ngIf="debugEnable">
- <th>Args variables</th>
- <td> <input type="text" style="width:99%;" formControlName="cmdArgs"> </td>
- </tr>
- </tbody>
- </table>
- </accordion-group>
- </accordion>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="row">
- <div class="col-xs-12 text-center">
- <div class="btn-group blocks">
- <button class="btn btn-primary btn-large" (click)="clean()" [disabled]="!curProject ">Clean</button>
- <button class="btn btn-primary btn-large" (click)="preBuild()" [disabled]="!curProject">Pre-Build</button>
- <button class="btn btn-primary btn-large" (click)="build()" [disabled]="!curProject">Build</button>
- <button class="btn btn-primary btn-large" (click)="populate()" [disabled]="!curProject ">Populate</button>
- <button *ngIf="debugEnable" class="btn btn-primary btn-large" (click)="execCmd()" [disabled]="!curProject ">Execute command</button>
- <button *ngIf="debugEnable" class="btn btn-primary btn-large" (click)="make()" [disabled]="!curProject ">Make</button>
- </div>
- </div>
- </div>
- </form>
-
- <div style="margin-left: 2em; margin-right: 2em; ">
- <div class="row ">
- <div class="col-xs-10">
- <div class="row ">
- <div class="col-xs-4">
- <label>Command Output</label>
- </div>
- <div class="col-xs-8" style="font-size:x-small; margin-top:5px;">
- {{ cmdInfo }}
- </div>
- </div>
- </div>
- <div class="col-xs-2">
- <button class="btn btn-link pull-right " (click)="reset() "><span class="fa fa-eraser fa-size-x2"></span></button>
- </div>
- </div>
- <div class="row ">
- <div class="col-xs-12 text-center ">
- <textarea rows="20" class="textarea-scroll" #scrollOutput>{{ cmdOutput }}</textarea>
- </div>
- </div>
- </div>
- </div>
-</div>
diff --git a/webapp/src/app/devel/build/build.component.ts b/webapp/src/app/devel/build/build.component.ts
deleted file mode 100644
index 48a5824..0000000
--- a/webapp/src/app/devel/build/build.component.ts
+++ /dev/null
@@ -1,223 +0,0 @@
-import { Component, AfterViewChecked, ElementRef, ViewChild, OnInit, Input } from '@angular/core';
-import { Observable } from 'rxjs';
-import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms';
-import { CookieService } from 'ngx-cookie';
-
-import 'rxjs/add/operator/scan';
-import 'rxjs/add/operator/startWith';
-
-import { XDSServerService, ICmdOutput } from "../../services/xdsserver.service";
-import { ConfigService, IConfig, IProject } from "../../services/config.service";
-import { AlertService, IAlert } from "../../services/alert.service";
-import { SdkService } from "../../services/sdk.service";
-
-@Component({
- selector: 'panel-build',
- moduleId: module.id,
- templateUrl: './build.component.html',
- styleUrls: ['./build.component.css']
-})
-
-export class BuildComponent implements OnInit, AfterViewChecked {
- @ViewChild('scrollOutput') private scrollContainer: ElementRef;
-
- @Input() curProject: IProject;
-
- public buildForm: FormGroup;
- public subpathCtrl = new FormControl("", Validators.required);
- public debugEnable: boolean = false;
- public buildIsCollapsed: boolean = false;
- public cmdOutput: string;
- public cmdInfo: string;
-
- private startTime: Map<string, number> = new Map<string, number>();
-
- constructor(private configSvr: ConfigService,
- private xdsSvr: XDSServerService,
- private fb: FormBuilder,
- private alertSvr: AlertService,
- private sdkSvr: SdkService,
- private cookie: CookieService,
- ) {
- this.cmdOutput = "";
- this.cmdInfo = ""; // TODO: to be remove (only for debug)
- this.buildForm = fb.group({
- subpath: this.subpathCtrl,
- cmdClean: ["", Validators.nullValidator],
- cmdPrebuild: ["", Validators.nullValidator],
- cmdBuild: ["", Validators.nullValidator],
- cmdPopulate: ["", Validators.nullValidator],
- cmdArgs: ["", Validators.nullValidator],
- envVars: ["", Validators.nullValidator],
- });
- }
-
- ngOnInit() {
- // Set default settings
- // TODO save & restore values from cookies
- this.buildForm.patchValue({
- subpath: "",
- cmdClean: "rm -rf build",
- cmdPrebuild: "mkdir -p build && cd build && cmake ..",
- cmdBuild: "cd build && make",
- cmdPopulate: "cd build && make remote-target-populate",
- cmdArgs: "",
- envVars: "",
- });
-
- // Command output data tunneling
- this.xdsSvr.CmdOutput$.subscribe(data => {
- this.cmdOutput += data.stdout;
- this.cmdOutput += data.stderr;
- });
-
- // Command exit
- this.xdsSvr.CmdExit$.subscribe(exit => {
- if (this.startTime.has(exit.cmdID)) {
- this.cmdInfo = 'Last command duration: ' + this._computeTime(this.startTime.get(exit.cmdID));
- this.startTime.delete(exit.cmdID);
- }
-
- if (exit && exit.code !== 0) {
- this.cmdOutput += "--- Command exited with code " + exit.code + " ---\n\n";
- }
- });
-
- this._scrollToBottom();
-
- // only use for debug
- this.debugEnable = (this.cookie.get("debug_build") === "1");
- }
-
- ngAfterViewChecked() {
- this._scrollToBottom();
- }
-
- reset() {
- this.cmdOutput = '';
- }
-
- clean() {
- this._exec(
- this.buildForm.value.cmdClean,
- this.buildForm.value.subpath,
- [],
- this.buildForm.value.envVars);
- }
-
- preBuild() {
- this._exec(
- this.buildForm.value.cmdPrebuild,
- this.buildForm.value.subpath,
- [],
- this.buildForm.value.envVars);
- }
-
- build() {
- this._exec(
- this.buildForm.value.cmdBuild,
- this.buildForm.value.subpath,
- [],
- this.buildForm.value.envVars
- );
- }
-
- populate() {
- this._exec(
- this.buildForm.value.cmdPopulate,
- this.buildForm.value.subpath,
- [], // args
- this.buildForm.value.envVars
- );
- }
-
- execCmd() {
- this._exec(
- this.buildForm.value.cmdArgs,
- this.buildForm.value.subpath,
- [],
- this.buildForm.value.envVars
- );
- }
-
- private _exec(cmd: string, dir: string, args: string[], env: string) {
- if (!this.curProject) {
- this.alertSvr.warning('No active project', true);
- }
-
- let prjID = this.curProject.id;
-
- this.cmdOutput += this._outputHeader();
-
- let sdkid = this.sdkSvr.getCurrentId();
-
- // Detect key=value in env string to build array of string
- let envArr = [];
- env.split(';').forEach(v => envArr.push(v.trim()));
-
- let t0 = performance.now();
- this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0;
-
- this.xdsSvr.exec(prjID, dir, cmd, sdkid, args, envArr)
- .subscribe(res => {
- this.startTime.set(String(res.cmdID), t0);
- },
- err => {
- this.cmdInfo = 'Last command duration: ' + this._computeTime(t0);
- this.alertSvr.error('ERROR: ' + err);
- });
- }
-
- make(args: string) {
- if (!this.curProject) {
- this.alertSvr.warning('No active project', true);
- }
-
- let prjID = this.curProject.id;
-
- this.cmdOutput += this._outputHeader();
-
- let sdkid = this.sdkSvr.getCurrentId();
-
- let argsArr = args ? args.split(' ') : this.buildForm.value.cmdArgs.split(' ');
-
- // Detect key=value in env string to build array of string
- let envArr = [];
- this.buildForm.value.envVars.split(';').forEach(v => envArr.push(v.trim()));
-
- let t0 = performance.now();
- this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0;
-
- this.xdsSvr.make(prjID, this.buildForm.value.subpath, sdkid, argsArr, envArr)
- .subscribe(res => {
- this.startTime.set(String(res.cmdID), t0);
- },
- err => {
- this.cmdInfo = 'Last command duration: ' + this._computeTime(t0);
- this.alertSvr.error('ERROR: ' + err);
- });
- }
-
- private _scrollToBottom(): void {
- try {
- this.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight;
- } catch (err) { }
- }
-
- private _computeTime(t0: number, t1?: number): string {
- let enlap = Math.round((t1 || performance.now()) - t0);
- if (enlap < 1000.0) {
- return enlap.toFixed(2) + ' ms';
- } else {
- return (enlap / 1000.0).toFixed(3) + ' seconds';
- }
- }
-
- private _outputHeader(): string {
- return "--- " + new Date().toString() + " ---\n";
- }
-
- private _outputFooter(): string {
- return "\n";
- }
-}
diff --git a/webapp/src/app/devel/deploy/deploy.component.css b/webapp/src/app/devel/deploy/deploy.component.css
deleted file mode 100644
index c1b39d8..0000000
--- a/webapp/src/app/devel/deploy/deploy.component.css
+++ /dev/null
@@ -1,45 +0,0 @@
-.vcenter {
- display: inline-block;
- vertical-align: middle;
-}
-
-.blocks .btn-primary {
- margin-left: 5px;
- margin-right: 5px;
- margin-top: 5px;
- border-radius: 4px !important;
-}
-
-.table-center {
- width: 99%;
- margin-left: auto;
- margin-right: auto;
-}
-
-.table-borderless>tbody>tr>td,
-.table-borderless>tbody>tr>th,
-.table-borderless>tfoot>tr>td,
-.table-borderless>tfoot>tr>th,
-.table-borderless>thead>tr>td,
-.table-borderless>thead>tr>th {
- border: none;
-}
-
-.btn-large {
- width: 10em;
-}
-
-.fa-size-x2 {
- font-size: 18px;
-}
-
-.textarea-scroll {
- width: 100%;
- overflow-y: scroll;
-}
-
-h2 {
- font-family: sans-serif;
- font-variant: small-caps;
- font-size: x-large;
-} \ No newline at end of file
diff --git a/webapp/src/app/devel/deploy/deploy.component.html b/webapp/src/app/devel/deploy/deploy.component.html
deleted file mode 100644
index 7a15fa6..0000000
--- a/webapp/src/app/devel/deploy/deploy.component.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<div class="panel panel-default">
- <div class="panel-heading">
- <h2 class="panel-title">Deployment</h2>
- </div>
- <div class="panel-body">
- <form [formGroup]="deployForm">
- <div class="col-xs-12">
- <table class="table table-borderless table-center">
- <tbody>
- <tr>
- <th>Board IP</th>
- <td> <input type="text" style="width:99%;" formControlName="boardIP" placeholder="1.2.3.4"> </td>
- </tr>
- <tr>
- <th>File to deploy</th>
- <td> <input type="text" style="width:99%;" formControlName="wgtFile"> </td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="row">
- <div class="col-xs-12 text-center">
- <div class="btn-group blocks">
- <button class="btn btn-primary btn-large" (click)="deploy()" [disabled]="!curProject ">Deploy</button>
- </div>
- </div>
- </div>
- </form>
-
- </div>
-</div> \ No newline at end of file
diff --git a/webapp/src/app/devel/deploy/deploy.component.ts b/webapp/src/app/devel/deploy/deploy.component.ts
deleted file mode 100644
index e51b7f2..0000000
--- a/webapp/src/app/devel/deploy/deploy.component.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { Component, OnInit, Input } from "@angular/core";
-import { Observable } from 'rxjs';
-import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms';
-
-import 'rxjs/add/operator/scan';
-import 'rxjs/add/operator/startWith';
-
-import { XDSAgentService, IXDSDeploy } from "../../services/xdsagent.service";
-import { ConfigService, IConfig, IProject } from "../../services/config.service";
-import { AlertService, IAlert } from "../../services/alert.service";
-import { SdkService } from "../../services/sdk.service";
-
-@Component({
- selector: 'panel-deploy',
- moduleId: module.id,
- templateUrl: './deploy.component.html',
- styleUrls: ['./deploy.component.css']
-})
-
-export class DeployComponent implements OnInit {
-
- @Input() curProject: IProject;
-
- deploying: boolean;
- deployForm: FormGroup;
-
- constructor(private configSvr: ConfigService,
- private xdsAgent: XDSAgentService,
- private fb: FormBuilder,
- private alert: AlertService,
- ) {
- this.deployForm = fb.group({
- boardIP: ["", Validators.nullValidator],
- wgtFile: ["", Validators.nullValidator],
- });
- }
-
- ngOnInit() {
- this.deploying = false;
- if (this.curProject && this.curProject.pathClient) {
- this.deployForm.patchValue({ wgtFile: this.curProject.pathClient });
- }
- }
-
- deploy() {
- this.deploying = true;
-
- this.xdsAgent.deploy(
- {
- boardIP: this.deployForm.value.boardIP,
- file: this.deployForm.value.wgtFile
- }
- ).subscribe(res => {
- this.deploying = false;
- }, err => {
- this.deploying = false;
- let msg = '<span>ERROR while deploying "' + this.deployForm.value.wgtFile + '"<br>';
- msg += err;
- msg += '</span>';
- this.alert.error(msg);
- });
- }
-}
diff --git a/webapp/src/app/devel/devel.component.css b/webapp/src/app/devel/devel.component.css
deleted file mode 100644
index 4b03dcb..0000000
--- a/webapp/src/app/devel/devel.component.css
+++ /dev/null
@@ -1,19 +0,0 @@
-.table-center {
- width: 60%;
- margin-left: auto;
- margin-right: auto;
-}
-
-.table-borderless>tbody>tr>td,
-.table-borderless>tbody>tr>th,
-.table-borderless>tfoot>tr>td,
-.table-borderless>tfoot>tr>th,
-.table-borderless>thead>tr>td,
-.table-borderless>thead>tr>th {
- border: none;
-}
-
-a.dropdown-item.disabled {
- pointer-events:none;
- opacity:0.4;
-}
diff --git a/webapp/src/app/devel/devel.component.html b/webapp/src/app/devel/devel.component.html
deleted file mode 100644
index 8e71c58..0000000
--- a/webapp/src/app/devel/devel.component.html
+++ /dev/null
@@ -1,40 +0,0 @@
-<div class="row">
- <div class="col-md-8">
- <table class="table table-borderless table-center">
- <tbody>
- <tr>
- <th style="border: none;">Project</th>
- <td>
- <div class="btn-group" dropdown *ngIf="curPrj">
- <button dropdownToggle type="button" class="btn btn-primary dropdown-toggle" style="width: 20em;">
- {{curPrj.label}}
- <span class="caret" style="float: right; margin-top: 8px;"></span>
- </button>
- <ul *dropdownMenu class="dropdown-menu" role="menu">
- <li role="menuitem"><a class="dropdown-item" *ngFor="let prj of (config$ | async)?.projects" [class.disabled]="!prj.isUsable"
- (click)="curPrj=prj">{{prj.label}}</a>
- </li>
-
- </ul>
- </div>
- <span *ngIf="!curPrj" style="color:red; font-style: italic;">
- No project detected, please create first a project using the configuration page.
- </span>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
-</div>
-
-<div class="row">
- <!--<div class="col-md-8">-->
- <div class="col-md-12">
- <panel-build [curProject]=curPrj></panel-build>
- </div>
- <!-- TODO: disable for now
- <div class="col-md-4">
- <panel-deploy [curProject]=curPrj></panel-deploy>
- </div>
- -->
-</div>
diff --git a/webapp/src/app/devel/devel.component.ts b/webapp/src/app/devel/devel.component.ts
deleted file mode 100644
index f40f25f..0000000
--- a/webapp/src/app/devel/devel.component.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Component } from '@angular/core';
-
-import { Observable } from 'rxjs';
-
-import { ConfigService, IConfig, IProject } from "../services/config.service";
-
-@Component({
- selector: 'devel',
- moduleId: module.id,
- templateUrl: './devel.component.html',
- styleUrls: ['./devel.component.css'],
-})
-
-export class DevelComponent {
-
- curPrj: IProject;
- config$: Observable<IConfig>;
-
- constructor(private configSvr: ConfigService) {
- }
-
- ngOnInit() {
- this.config$ = this.configSvr.conf;
- this.config$.subscribe((cfg) => {
- // Select project if no one is selected or no project exists
- if (this.curPrj && "id" in this.curPrj) {
- this.curPrj = cfg.projects.find(p => p.id === this.curPrj.id) || cfg.projects[0];
- } else if (this.curPrj == null && "projects" in cfg) {
- this.curPrj = cfg.projects[0];
- } else {
- this.curPrj = null;
- }
- });
- }
-}
diff --git a/webapp/src/app/home/home.component.ts b/webapp/src/app/home/home.component.ts
deleted file mode 100644
index 0e3c995..0000000
--- a/webapp/src/app/home/home.component.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-
-export interface ISlide {
- img?: string;
- imgAlt?: string;
- hText?: string;
- hHtml?: string;
- text?: string;
- html?: string;
- btn?: string;
- btnHref?: string;
-}
-
-@Component({
- selector: 'home',
- moduleId: module.id,
- template: `
- <style>
- .wide img {
- width: 98%;
- }
- .carousel-item {
- max-height: 90%;
- }
- h1, h2, h3, h4, p {
- color: #330066;
- }
- .html-inner {
- color: #330066;
- }
- h1 {
- font-size: 4em;
- }
- p {
- font-size: 2.5em;
- }
-
- </style>
-
- <div class="wide">
- <carousel [interval]="carInterval" [(activeSlide)]="activeSlideIndex">
- <slide *ngFor="let sl of slides; let index=index">
- <img [src]="sl.img" [alt]="sl.imgAlt">
- <div class="carousel-caption">
- <h1 *ngIf="sl.hText">{{ sl.hText }}</h1>
- <h1 *ngIf="sl.hHtml" class="html-inner" [innerHtml]="sl.hHtml"></h1>
- <p *ngIf="sl.text">{{ sl.text }}</p>
- <div *ngIf="sl.html" class="html-inner" [innerHtml]="sl.html"></div>
- </div>
- </slide>
- </carousel>
- </div>
- `
-})
-
-export class HomeComponent {
-
- public carInterval: number = 4000;
-
- // FIXME SEB - Add more slides and info
- public slides: ISlide[] = [
- {
- img: 'assets/images/iot-graphx.jpg',
- imgAlt: "iot graphx image",
- hText: "Welcome to XDS Dashboard !",
- text: "X(cross) Development System allows developers to easily cross-compile applications.",
- },
- {
- img: 'assets/images/iot-graphx.jpg',
- imgAlt: "iot graphx image",
- hText: "Create, Build, Deploy, Enjoy !",
- },
- {
- img: 'assets/images/iot-graphx.jpg',
- imgAlt: "iot graphx image",
- hHtml: '<p>To Start: click on <i class="fa fa-cog" style="color:#9d9d9d;"></i> icon and add new folder</p>',
- }
- ];
-
- constructor() { }
-} \ No newline at end of file
diff --git a/webapp/src/app/main.ts b/webapp/src/app/main.ts
deleted file mode 100644
index 1f68ccc..0000000
--- a/webapp/src/app/main.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
-import {AppModule} from './app.module';
-
-const platform = platformBrowserDynamic();
-
-platform.bootstrapModule(AppModule); \ No newline at end of file
diff --git a/webapp/src/app/projects/projectAddModal.component.css b/webapp/src/app/projects/projectAddModal.component.css
deleted file mode 100644
index 77f73a5..0000000
--- a/webapp/src/app/projects/projectAddModal.component.css
+++ /dev/null
@@ -1,24 +0,0 @@
-.table-borderless>tbody>tr>td,
-.table-borderless>tbody>tr>th,
-.table-borderless>tfoot>tr>td,
-.table-borderless>tfoot>tr>th,
-.table-borderless>thead>tr>td,
-.table-borderless>thead>tr>th {
- border: none;
-}
-
-tr>th {
- vertical-align: middle;
-}
-
-tr>td {
- vertical-align: middle;
-}
-
-th label {
- margin-bottom: 0;
-}
-
-td input {
- width: 100%;
-}
diff --git a/webapp/src/app/projects/projectAddModal.component.html b/webapp/src/app/projects/projectAddModal.component.html
deleted file mode 100644
index dc84985..0000000
--- a/webapp/src/app/projects/projectAddModal.component.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<div bsModal #childProjectModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel"
- [config]="{backdrop: 'static'}" aria-hidden="true">
- <div class="modal-dialog modal-lg">
- <div class="modal-content">
- <div class="modal-header">
- <h4 class="modal-title pull-left">{{title}}</h4>
- <button type="button" class="close pull-right" aria-label="Close" (click)="hide()">
- <span aria-hidden="true">&times;</span>
- </button>
- </div>
-
- <form [formGroup]="addProjectForm" (ngSubmit)="onSubmit()">
- <div class="modal-body">
- <div class="row ">
- <div class="col-xs-12">
- <table class="table table-borderless">
- <tbody>
- <tr>
- <th><label>Sharing Type </label></th>
- <td><select class="form-control" formControlName="type">
- <option *ngFor="let t of projectTypes" [value]="t.value">{{t.display}}
- </option>
- </select>
- </td>
- </tr>
- <tr>
- <th><label for="select-local-path">Local Path </label></th>
- <td><input type="text" id="select-local-path" formControlName="pathCli" placeholder="/tmp/myProject" (change)="onChangeLocalProject($event)"></td>
- </tr>
- <tr>
- <th><label for="select-server-path">Server Path </label></th>
- <td><input type="text" id="select-server-path" formControlName="pathSvr"></td>
- </tr>
- <tr>
- <th><label for="select-label">Label </label></th>
- <td><input type="text" formControlName="label" id="select-label" (keyup)="onKeyLabel($event)"></td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- </div>
- <div class="modal-footer">
- <div class="pull-left">
- <button class="btn btn-default" (click)="cancelAction=true; hide()"> Cancel </button>
- </div>
- <div class="">
- <button class="btn btn-primary" type="submit" [disabled]="!addProjectForm.valid">Add Folder</button>
- </div>
- </div>
- </form>
- </div>
- </div>
-</div>
diff --git a/webapp/src/app/projects/projectAddModal.component.ts b/webapp/src/app/projects/projectAddModal.component.ts
deleted file mode 100644
index 7ef5b5e..0000000
--- a/webapp/src/app/projects/projectAddModal.component.ts
+++ /dev/null
@@ -1,152 +0,0 @@
-import { Component, Input, ViewChild, OnInit } from '@angular/core';
-import { Observable } from 'rxjs/Observable';
-import { ModalDirective } from 'ngx-bootstrap/modal';
-import { FormControl, FormGroup, Validators, FormBuilder, ValidatorFn, AbstractControl } from '@angular/forms';
-
-// Import RxJs required methods
-import 'rxjs/add/operator/map';
-import 'rxjs/add/operator/filter';
-import 'rxjs/add/operator/debounceTime';
-
-import { AlertService, IAlert } from "../services/alert.service";
-import {
- ConfigService, IConfig, IProject, ProjectType, ProjectTypes,
- IxdsAgentPackage
-} from "../services/config.service";
-
-
-@Component({
- selector: 'project-add-modal',
- templateUrl: './app/projects/projectAddModal.component.html',
- styleUrls: ['./app/projects/projectAddModal.component.css']
-})
-export class ProjectAddModalComponent {
- @ViewChild('childProjectModal') public childProjectModal: ModalDirective;
- @Input() title?: string;
-
- config$: Observable<IConfig>;
-
- cancelAction: boolean = false;
- userEditedLabel: boolean = false;
- projectTypes = ProjectTypes;
-
- addProjectForm: FormGroup;
- typeCtrl: FormControl;
- pathCliCtrl: FormControl;
- pathSvrCtrl: FormControl;
-
- constructor(
- private alert: AlertService,
- private configSvr: ConfigService,
- private fb: FormBuilder
- ) {
- // Define types (first one is special/placeholder)
- this.projectTypes.unshift({ value: -1, display: "--Select a type--" });
-
- this.typeCtrl = new FormControl(this.projectTypes[0].value, Validators.pattern("[0-9]+"));
- this.pathCliCtrl = new FormControl("", Validators.required);
- this.pathSvrCtrl = new FormControl({ value: "", disabled: true }, [Validators.required, Validators.minLength(1)]);
-
- this.addProjectForm = fb.group({
- type: this.typeCtrl,
- pathCli: this.pathCliCtrl,
- pathSvr: this.pathSvrCtrl,
- label: ["", Validators.nullValidator],
- });
- }
-
- ngOnInit() {
- this.config$ = this.configSvr.conf;
-
- // Auto create label name
- this.pathCliCtrl.valueChanges
- .debounceTime(100)
- .filter(n => n)
- .map(n => {
- let last = n.split('/');
- let nm = n;
- if (last.length > 0) {
- nm = last.pop();
- if (nm === "" && last.length > 0) {
- nm = last.pop();
- }
- }
- return "Project_" + nm;
- })
- .subscribe(value => {
- if (value && !this.userEditedLabel) {
- this.addProjectForm.patchValue({ label: value });
- }
- });
-
- // Handle disabling of Server path
- this.typeCtrl.valueChanges
- .debounceTime(500)
- .subscribe(valType => {
- let dis = (valType === String(ProjectType.SYNCTHING));
- this.pathSvrCtrl.reset({ value: "", disabled: dis });
- });
- }
-
- show() {
- this.cancelAction = false;
- this.childProjectModal.show();
- }
-
- hide() {
- this.childProjectModal.hide();
- }
-
- onKeyLabel(event: any) {
- this.userEditedLabel = (this.addProjectForm.value.label !== "");
- }
-
- /* FIXME: change input to file type
- <td><input type="file" id="select-local-path" webkitdirectory
- formControlName="pathCli" placeholder="myProject" (change)="onChangeLocalProject($event)"></td>
-
- onChangeLocalProject(e) {
- if e.target.files.length < 1 {
- console.log('NO files');
- }
- let dir = e.target.files[0].webkitRelativePath;
- console.log("files: " + dir);
- let u = URL.createObjectURL(e.target.files[0]);
- }
- */
- onChangeLocalProject(e) {
- }
-
- onSubmit() {
- if (this.cancelAction) {
- return;
- }
-
- let formVal = this.addProjectForm.value;
-
- let type = formVal['type'].value;
- let numType = Number(formVal['type']);
- this.configSvr.addProject({
- label: formVal['label'],
- pathClient: formVal['pathCli'],
- pathServer: formVal['pathSvr'],
- type: numType,
- // FIXME: allow to set defaultSdkID from New Project config panel
- })
- .subscribe(prj => {
- this.alert.info("Project " + prj.label + " successfully created.");
- this.hide();
-
- // Reset Value for the next creation
- this.addProjectForm.reset();
- let selectedType = this.projectTypes[0].value;
- this.addProjectForm.patchValue({ type: selectedType });
-
- },
- err => {
- this.alert.error("Configuration ERROR: " + err, 60);
- this.hide();
- });
- }
-
-}
diff --git a/webapp/src/app/projects/projectCard.component.ts b/webapp/src/app/projects/projectCard.component.ts
deleted file mode 100644
index a7ca9a3..0000000
--- a/webapp/src/app/projects/projectCard.component.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import { Component, Input, Pipe, PipeTransform } from '@angular/core';
-import { ConfigService, IProject, ProjectType } from "../services/config.service";
-import { AlertService } from "../services/alert.service";
-
-@Component({
- selector: 'project-card',
- template: `
- <div class="row">
- <div class="col-xs-12">
- <div class="text-right" role="group">
- <button class="btn btn-link" (click)="delete(project)">
- <span class="fa fa-trash fa-size-x2"></span>
- </button>
- </div>
- </div>
- </div>
-
- <table class="table table-striped">
- <tbody>
- <tr>
- <th><span class="fa fa-fw fa-id-badge"></span>&nbsp;<span>Project ID</span></th>
- <td>{{ project.id }}</td>
- </tr>
- <tr>
- <th><span class="fa fa-fw fa-exchange"></span>&nbsp;<span>Sharing type</span></th>
- <td>{{ project.type | readableType }}</td>
- </tr>
- <tr>
- <th><span class="fa fa-fw fa-folder-open-o"></span>&nbsp;<span>Local path</span></th>
- <td>{{ project.pathClient }}</td>
- </tr>
- <tr *ngIf="project.pathServer && project.pathServer != ''">
- <th><span class="fa fa-fw fa-folder-open-o"></span>&nbsp;<span>Server path</span></th>
- <td>{{ project.pathServer }}</td>
- </tr>
- <tr>
- <th><span class="fa fa-fw fa-flag"></span>&nbsp;<span>Status</span></th>
- <td>{{ project.status }} - {{ project.isInSync ? "Up to Date" : "Out of Sync"}}
- <button *ngIf="!project.isInSync" class="btn btn-link" (click)="sync(project)">
- <span class="fa fa-refresh fa-size-x2"></span>
- </button>
- </td>
- </tr>
- </tbody>
- </table >
- `,
- styleUrls: ['./app/config/config.component.css']
-})
-
-export class ProjectCardComponent {
-
- @Input() project: IProject;
-
- constructor(
- private alert: AlertService,
- private configSvr: ConfigService
- ) {
- }
-
- delete(prj: IProject) {
- this.configSvr.deleteProject(prj)
- .subscribe(res => {
- }, err => {
- this.alert.error("Delete local ERROR: " + err);
- });
- }
-
- sync(prj: IProject) {
- this.configSvr.syncProject(prj)
- .subscribe(res => {
- }, err => {
- this.alert.error("ERROR: " + err);
- });
- }
-
-}
-
-// Remove APPS. prefix if translate has failed
-@Pipe({
- name: 'readableType'
-})
-
-export class ProjectReadableTypePipe implements PipeTransform {
- transform(type: ProjectType): string {
- switch (type) {
- case ProjectType.NATIVE_PATHMAP: return "Native (path mapping)";
- case ProjectType.SYNCTHING: return "Cloud (Syncthing)";
- default: return String(type);
- }
- }
-}
diff --git a/webapp/src/app/projects/projectsListAccordion.component.ts b/webapp/src/app/projects/projectsListAccordion.component.ts
deleted file mode 100644
index 6e697f4..0000000
--- a/webapp/src/app/projects/projectsListAccordion.component.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { Component, Input } from "@angular/core";
-
-import { IProject } from "../services/config.service";
-
-@Component({
- selector: 'projects-list-accordion',
- template: `
- <style>
- .fa.fa-exclamation-triangle {
- margin-right: 2em;
- color: red;
- }
- .fa.fa-refresh {
- margin-right: 10px;
- color: darkviolet;
- }
- </style>
- <accordion>
- <accordion-group #group *ngFor="let prj of projects">
- <div accordion-heading>
- {{ prj.label }}
- <div class="pull-right">
- <i *ngIf="prj.status == 'Syncing'" class="fa fa-refresh faa-spin animated"></i>
- <i *ngIf="!prj.isInSync && prj.status != 'Syncing'" class="fa fa-exclamation-triangle"></i>
- <i class="fa" [ngClass]="{'fa-chevron-down': group.isOpen, 'fa-chevron-right': !group.isOpen}"></i>
- </div>
- </div>
- <project-card [project]="prj"></project-card>
- </accordion-group>
- </accordion>
- `
-})
-export class ProjectsListAccordionComponent {
-
- @Input() projects: IProject[];
-
-}
-
-
diff --git a/webapp/src/app/sdks/sdkAddModal.component.html b/webapp/src/app/sdks/sdkAddModal.component.html
deleted file mode 100644
index 2c07fca..0000000
--- a/webapp/src/app/sdks/sdkAddModal.component.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<div bsModal #sdkChildModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel"
- aria-hidden="true">
- <div class="modal-dialog modal-lg">
- <div class="modal-content">
- <div class="modal-header">
- <h4 class="modal-title pull-left">{{title}}</h4>
- <button type="button" class="close pull-right" aria-label="Close" (click)="hideChildModal()">
- <span aria-hidden="true">&times;</span>
- </button>
- </div>
- <div class="modal-body">
- <ng-content select=".modal-body"> </ng-content>
- <i>Not available for now.</i>
- </div>
-
- <div class="modal-footer">
- <div class="pull-left">
- <button class="btn btn-default" (click)="hide()"> Cancel </button>
- </div>
- </div>
- </div>
- </div>
-</div>
diff --git a/webapp/src/app/sdks/sdkAddModal.component.ts b/webapp/src/app/sdks/sdkAddModal.component.ts
deleted file mode 100644
index b6c8eb2..0000000
--- a/webapp/src/app/sdks/sdkAddModal.component.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Component, Input, ViewChild } from '@angular/core';
-import { ModalDirective } from 'ngx-bootstrap/modal';
-
-@Component({
- selector: 'sdk-add-modal',
- templateUrl: './app/sdks/sdkAddModal.component.html',
-})
-export class SdkAddModalComponent {
- @ViewChild('sdkChildModal') public sdkChildModal: ModalDirective;
-
- @Input() title?: string;
-
- // TODO
- constructor() {
- }
-
- show() {
- this.sdkChildModal.show();
- }
-
- hide() {
- this.sdkChildModal.hide();
- }
-}
diff --git a/webapp/src/app/sdks/sdkCard.component.ts b/webapp/src/app/sdks/sdkCard.component.ts
deleted file mode 100644
index 579d224..0000000
--- a/webapp/src/app/sdks/sdkCard.component.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { Component, Input } from '@angular/core';
-import { ISdk } from "../services/sdk.service";
-
-@Component({
- selector: 'sdk-card',
- template: `
- <div class="row">
- <div class="col-xs-12">
- <div class="text-right" role="group">
- <button disabled class="btn btn-link" (click)="delete(sdk)"><span class="fa fa-trash fa-size-x2"></span></button>
- </div>
- </div>
- </div>
-
- <table class="table table-striped">
- <tbody>
- <tr>
- <th><span class="fa fa-fw fa-id-badge"></span>&nbsp;<span>Profile</span></th>
- <td>{{ sdk.profile }}</td>
- </tr>
- <tr>
- <th><span class="fa fa-fw fa-tasks"></span>&nbsp;<span>Architecture</span></th>
- <td>{{ sdk.arch }}</td>
- </tr>
- <tr>
- <th><span class="fa fa-fw fa-code-fork"></span>&nbsp;<span>Version</span></th>
- <td>{{ sdk.version }}</td>
- </tr>
- <tr>
- <th><span class="fa fa-fw fa-folder-open-o"></span>&nbsp;<span>Sdk path</span></th>
- <td>{{ sdk.path}}</td>
- </tr>
-
- </tbody>
- </table >
- `,
- styleUrls: ['./app/config/config.component.css']
-})
-
-export class SdkCardComponent {
-
- @Input() sdk: ISdk;
-
- constructor() { }
-
-
- delete(sdk: ISdk) {
- // Not supported for now
- }
-
-}
diff --git a/webapp/src/app/sdks/sdkSelectDropdown.component.ts b/webapp/src/app/sdks/sdkSelectDropdown.component.ts
deleted file mode 100644
index a2fe37a..0000000
--- a/webapp/src/app/sdks/sdkSelectDropdown.component.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { Component, Input } from "@angular/core";
-
-import { ISdk, SdkService } from "../services/sdk.service";
-
-@Component({
- selector: 'sdk-select-dropdown',
- template: `
- <div class="btn-group" dropdown *ngIf="curSdk" >
- <button dropdownToggle type="button" class="btn btn-primary dropdown-toggle" style="width: 20em;">
- {{curSdk.name}} <span class="caret" style="float: right; margin-top: 8px;"></span>
- </button>
- <ul *dropdownMenu class="dropdown-menu" role="menu">
- <li role="menuitem"><a class="dropdown-item" *ngFor="let sdk of sdks" (click)="select(sdk)">
- {{sdk.name}}</a>
- </li>
- </ul>
- </div>
- `
-})
-export class SdkSelectDropdownComponent {
-
- // FIXME investigate to understand why not working with sdks as input
- // <sdk-select-dropdown [sdks]="(sdks$ | async)"></sdk-select-dropdown>
- //@Input() sdks: ISdk[];
- sdks: ISdk[];
-
- curSdk: ISdk;
-
- constructor(private sdkSvr: SdkService) { }
-
- ngOnInit() {
- this.curSdk = this.sdkSvr.getCurrent();
- this.sdkSvr.Sdks$.subscribe((s) => {
- if (s) {
- this.sdks = s;
- if (this.curSdk === null || s.indexOf(this.curSdk) === -1) {
- this.sdkSvr.setCurrent(this.curSdk = s.length ? s[0] : null);
- }
- }
- });
- }
-
- select(s) {
- this.sdkSvr.setCurrent(this.curSdk = s);
- }
-}
-
-
diff --git a/webapp/src/app/sdks/sdksListAccordion.component.ts b/webapp/src/app/sdks/sdksListAccordion.component.ts
deleted file mode 100644
index 9d5f7e9..0000000
--- a/webapp/src/app/sdks/sdksListAccordion.component.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Component, Input } from "@angular/core";
-
-import { ISdk } from "../services/sdk.service";
-
-@Component({
- selector: 'sdks-list-accordion',
- template: `
- <accordion>
- <accordion-group #group *ngFor="let sdk of sdks">
- <div accordion-heading>
- {{ sdk.name }}
- <i class="pull-right float-xs-right fa"
- [ngClass]="{'fa-chevron-down': group.isOpen, 'fa-chevron-right': !group.isOpen}"></i>
- </div>
- <sdk-card [sdk]="sdk"></sdk-card>
- </accordion-group>
- </accordion>
- `
-})
-export class SdksListAccordionComponent {
-
- @Input() sdks: ISdk[];
-
-}
-
-
diff --git a/webapp/src/app/services/alert.service.ts b/webapp/src/app/services/alert.service.ts
deleted file mode 100644
index c3cae7a..0000000
--- a/webapp/src/app/services/alert.service.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import { Injectable, SecurityContext } from '@angular/core';
-import { DomSanitizer } from '@angular/platform-browser';
-import { Observable } from 'rxjs/Observable';
-import { Subject } from 'rxjs/Subject';
-
-
-export type AlertType = "danger" | "warning" | "info" | "success";
-
-export interface IAlert {
- type: AlertType;
- msg: string;
- show?: boolean;
- dismissible?: boolean;
- dismissTimeout?: number; // close alert after this time (in seconds)
- id?: number;
-}
-
-@Injectable()
-export class AlertService {
- public alerts: Observable<IAlert[]>;
-
- private _alerts: IAlert[];
- private alertsSubject = <Subject<IAlert[]>>new Subject();
- private uid = 0;
- private defaultDissmissTmo = 5; // in seconds
-
- constructor(private sanitizer: DomSanitizer) {
- this.alerts = this.alertsSubject.asObservable();
- this._alerts = [];
- this.uid = 0;
- }
-
- public error(msg: string, dismissTime?: number) {
- this.add({
- type: "danger", msg: msg, dismissible: true, dismissTimeout: dismissTime
- });
- }
-
- public warning(msg: string, dismissible?: boolean) {
- this.add({ type: "warning", msg: msg, dismissible: true, dismissTimeout: (dismissible ? this.defaultDissmissTmo : 0) });
- }
-
- public info(msg: string) {
- this.add({ type: "info", msg: msg, dismissible: true, dismissTimeout: this.defaultDissmissTmo });
- }
-
- public add(al: IAlert) {
- this._alerts.push({
- show: true,
- type: al.type,
- msg: this.sanitizer.sanitize(SecurityContext.HTML, al.msg),
- dismissible: al.dismissible || true,
- dismissTimeout: (al.dismissTimeout * 1000) || 0,
- id: this.uid,
- });
- this.uid += 1;
- this.alertsSubject.next(this._alerts);
- }
-
- public del(al: IAlert) {
- let idx = this._alerts.findIndex((a) => a.id === al.id);
- if (idx > -1) {
- this._alerts.splice(idx, 1);
- }
- }
-}
diff --git a/webapp/src/app/services/config.service.ts b/webapp/src/app/services/config.service.ts
deleted file mode 100644
index 6cab73c..0000000
--- a/webapp/src/app/services/config.service.ts
+++ /dev/null
@@ -1,422 +0,0 @@
-import { Injectable, OnInit } from '@angular/core';
-import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http';
-import { Location } from '@angular/common';
-import { CookieService } from 'ngx-cookie';
-import { Observable } from 'rxjs/Observable';
-import { Subscriber } from 'rxjs/Subscriber';
-import { BehaviorSubject } from 'rxjs/BehaviorSubject';
-
-// Import RxJs required methods
-import 'rxjs/add/operator/map';
-import 'rxjs/add/operator/catch';
-import 'rxjs/add/observable/throw';
-import 'rxjs/add/operator/mergeMap';
-
-
-import { XDSServerService, IXDSFolderConfig } from "../services/xdsserver.service";
-import { XDSAgentService } from "../services/xdsagent.service";
-import { SyncthingService, ISyncThingProject, ISyncThingStatus } from "../services/syncthing.service";
-import { AlertService, IAlert } from "../services/alert.service";
-import { UtilsService } from "../services/utils.service";
-
-export enum ProjectType {
- NATIVE_PATHMAP = 1,
- SYNCTHING = 2
-}
-
-export var ProjectTypes = [
- { value: ProjectType.NATIVE_PATHMAP, display: "Path mapping" },
- { value: ProjectType.SYNCTHING, display: "Cloud Sync" }
-];
-
-export var ProjectStatus = {
- ErrorConfig: "ErrorConfig",
- Disable: "Disable",
- Enable: "Enable",
- Pause: "Pause",
- Syncing: "Syncing"
-};
-
-export interface IProject {
- id?: string;
- label: string;
- pathClient: string;
- pathServer?: string;
- type: ProjectType;
- status?: string;
- isInSync?: boolean;
- isUsable?: boolean;
- serverPrjDef?: IXDSFolderConfig;
- isExpanded?: boolean;
- visible?: boolean;
- defaultSdkID?: string;
-}
-
-export interface IXDSAgentConfig {
- URL: string;
- retry: number;
-}
-
-export interface ILocalSTConfig {
- ID: string;
- URL: string;
- retry: number;
- tilde: string;
-}
-
-export interface IxdsAgentPackage {
- os: string;
- arch: string;
- version: string;
- url: string;
-}
-
-export interface IConfig {
- xdsServerURL: string;
- xdsAgent: IXDSAgentConfig;
- xdsAgentPackages: IxdsAgentPackage[];
- projectsRootDir: string;
- projects: IProject[];
- localSThg: ILocalSTConfig;
-}
-
-@Injectable()
-export class ConfigService {
-
- public conf: Observable<IConfig>;
-
- private confSubject: BehaviorSubject<IConfig>;
- private confStore: IConfig;
- private AgentConnectObs = null;
- private stConnectObs = null;
-
- constructor(private _window: Window,
- private cookie: CookieService,
- private xdsServerSvr: XDSServerService,
- private xdsAgentSvr: XDSAgentService,
- private stSvr: SyncthingService,
- private alert: AlertService,
- private utils: UtilsService,
- ) {
- this.load();
- this.confSubject = <BehaviorSubject<IConfig>>new BehaviorSubject(this.confStore);
- this.conf = this.confSubject.asObservable();
-
- // force to load projects
- this.loadProjects();
- }
-
- // Load config
- load() {
- // Try to retrieve previous config from cookie
- let cookConf = this.cookie.getObject("xds-config");
- if (cookConf != null) {
- this.confStore = <IConfig>cookConf;
- } else {
- // Set default config
- this.confStore = {
- xdsServerURL: this._window.location.origin + '/api/v1',
- xdsAgent: {
- URL: 'http://localhost:8010',
- retry: 10,
- },
- xdsAgentPackages: [],
- projectsRootDir: "",
- projects: [],
- localSThg: {
- ID: null,
- URL: "http://localhost:8386",
- retry: 10, // 10 seconds
- tilde: "",
- }
- };
- }
-
- // Update XDS Agent tarball url
- this.xdsServerSvr.getXdsAgentInfo().subscribe(nfo => {
- this.confStore.xdsAgentPackages = [];
- nfo.tarballs && nfo.tarballs.forEach(el =>
- this.confStore.xdsAgentPackages.push({
- os: el.os,
- arch: el.arch,
- version: el.version,
- url: el.fileUrl
- })
- );
- this.confSubject.next(Object.assign({}, this.confStore));
- });
-
- // Update Project data
- this.xdsServerSvr.FolderStateChange$.subscribe(prj => {
- let i = this._getProjectIdx(prj.id);
- if (i >= 0) {
- // XXX for now, only isInSync and status may change
- this.confStore.projects[i].isInSync = prj.isInSync;
- this.confStore.projects[i].status = prj.status;
- this.confStore.projects[i].isUsable = this._isUsableProject(prj);
- this.confSubject.next(Object.assign({}, this.confStore));
- }
- });
- }
-
- // Save config into cookie
- save() {
- // Notify subscribers
- this.confSubject.next(Object.assign({}, this.confStore));
-
- // Don't save projects in cookies (too big!)
- let cfg = Object.assign({}, this.confStore);
- delete (cfg.projects);
- this.cookie.putObject("xds-config", cfg);
- }
-
- loadProjects() {
- // Setup connection with local XDS agent
- if (this.AgentConnectObs) {
- try {
- this.AgentConnectObs.unsubscribe();
- } catch (err) { }
- this.AgentConnectObs = null;
- }
-
- let cfg = this.confStore.xdsAgent;
- this.AgentConnectObs = this.xdsAgentSvr.connect(cfg.retry, cfg.URL)
- .subscribe((sts) => {
- //console.log("Agent sts", sts);
- // FIXME: load projects from local XDS Agent and
- // not directly from local syncthing
- this._loadProjectFromLocalST();
-
- }, error => {
- if (error.indexOf("XDS local Agent not responding") !== -1) {
- let rootUrl = "http://docs.automotivelinux.org/docs/devguides/en/dev/reference/";
- let url_OS_Linux = rootUrl + "xds/part-1/1_install-client.html#install-packages-for-debian-distro-type";
- let url_OS_Other = rootUrl + "xds/part-1/1_install-client.html#install-for-other-platforms-windows--macos";
- let msg = `<span><strong>` + error + `<br></strong>
- You may need to install and execute XDS-Agent: <br>
- On Linux machine <a href="` + url_OS_Linux + `" target="_blank"><span
- class="fa fa-external-link"></span></a>
- <br>
- On Windows machine <a href="` + url_OS_Other + `" target="_blank"><span
- class="fa fa-external-link"></span></a>
- <br>
- On MacOS machine <a href="` + url_OS_Other + `" target="_blank"><span
- class="fa fa-external-link"></span></a>
- `;
- this.alert.error(msg);
- } else {
- this.alert.error(error);
- }
- });
- }
-
- private _loadProjectFromLocalST() {
- // Remove previous subscriber if existing
- if (this.stConnectObs) {
- try {
- this.stConnectObs.unsubscribe();
- } catch (err) { }
- this.stConnectObs = null;
- }
-
- // FIXME: move this code and all logic about syncthing inside XDS Agent
- // Setup connection with local SyncThing
- let retry = this.confStore.localSThg.retry;
- let url = this.confStore.localSThg.URL;
- this.stConnectObs = this.stSvr.connect(retry, url).subscribe((sts) => {
- this.confStore.localSThg.ID = sts.ID;
- this.confStore.localSThg.tilde = sts.tilde;
- if (this.confStore.projectsRootDir === "") {
- this.confStore.projectsRootDir = sts.tilde;
- }
-
- // Rebuild projects definition from local and remote syncthing
- this.confStore.projects = [];
-
- this.xdsServerSvr.getProjects().subscribe(remotePrj => {
- this.stSvr.getProjects().subscribe(localPrj => {
- remotePrj.forEach(rPrj => {
- let lPrj = localPrj.filter(item => item.id === rPrj.id);
- if (lPrj.length > 0 || rPrj.type === ProjectType.NATIVE_PATHMAP) {
- this._addProject(rPrj, true);
- }
- });
- this.confSubject.next(Object.assign({}, this.confStore));
- }), error => this.alert.error('Could not load initial state of local projects.');
- }), error => this.alert.error('Could not load initial state of remote projects.');
-
- }, error => {
- if (error.indexOf("Syncthing local daemon not responding") !== -1) {
- let msg = "<span><strong>" + error + "<br></strong>";
- msg += "Please check that local XDS-Agent is running.<br>";
- msg += "</span>";
- this.alert.error(msg);
- } else {
- this.alert.error(error);
- }
- });
- }
-
- set syncToolURL(url: string) {
- this.confStore.localSThg.URL = url;
- this.save();
- }
-
- set xdsAgentRetry(r: number) {
- this.confStore.localSThg.retry = r;
- this.confStore.xdsAgent.retry = r;
- this.save();
- }
-
- set xdsAgentUrl(url: string) {
- this.confStore.xdsAgent.URL = url;
- this.save();
- }
-
-
- set projectsRootDir(p: string) {
- if (p.charAt(0) === '~') {
- p = this.confStore.localSThg.tilde + p.substring(1);
- }
- this.confStore.projectsRootDir = p;
- this.save();
- }
-
- getLabelRootName(): string {
- let id = this.confStore.localSThg.ID;
- if (!id || id === "") {
- return null;
- }
- return id.slice(0, 15);
- }
-
- addProject(prj: IProject): Observable<IProject> {
- // Substitute tilde with to user home path
- let pathCli = prj.pathClient.trim();
- if (pathCli.charAt(0) === '~') {
- pathCli = this.confStore.localSThg.tilde + pathCli.substring(1);
-
- // Must be a full path (on Linux or Windows)
- } else if (!((pathCli.charAt(0) === '/') ||
- (pathCli.charAt(1) === ':' && (pathCli.charAt(2) === '\\' || pathCli.charAt(2) === '/')))) {
- pathCli = this.confStore.projectsRootDir + '/' + pathCli;
- }
-
- let xdsPrj: IXDSFolderConfig = {
- id: "",
- label: prj.label || "",
- path: pathCli,
- type: prj.type,
- defaultSdkID: prj.defaultSdkID,
- dataPathMap: {
- serverPath: prj.pathServer,
- },
- dataCloudSync: {
- syncThingID: this.confStore.localSThg.ID,
- }
- };
- // Send config to XDS server
- let newPrj = prj;
- return this.xdsServerSvr.addProject(xdsPrj)
- .flatMap(resStRemotePrj => {
- xdsPrj = resStRemotePrj;
- if (xdsPrj.type === ProjectType.SYNCTHING) {
- // FIXME REWORK local ST config
- // move logic to server side tunneling-back by WS
- let stData = xdsPrj.dataCloudSync;
-
- // Now setup local config
- let stLocPrj: ISyncThingProject = {
- id: xdsPrj.id,
- label: xdsPrj.label,
- path: xdsPrj.path,
- serverSyncThingID: stData.builderSThgID
- };
-
- // Set local Syncthing config
- return this.stSvr.addProject(stLocPrj);
-
- } else {
- return Observable.of(null);
- }
- })
- .map(resStLocalPrj => {
- this._addProject(xdsPrj);
- return newPrj;
- });
- }
-
- deleteProject(prj: IProject): Observable<IProject> {
- let idx = this._getProjectIdx(prj.id);
- let delPrj = prj;
- if (idx === -1) {
- throw new Error("Invalid project id (id=" + prj.id + ")");
- }
- return this.xdsServerSvr.deleteProject(prj.id)
- .flatMap(res => {
- if (prj.type === ProjectType.SYNCTHING) {
- return this.stSvr.deleteProject(prj.id);
- }
- return Observable.of(null);
- })
- .map(res => {
- this.confStore.projects.splice(idx, 1);
- return delPrj;
- });
- }
-
- syncProject(prj: IProject): Observable<string> {
- let idx = this._getProjectIdx(prj.id);
- if (idx === -1) {
- throw new Error("Invalid project id (id=" + prj.id + ")");
- }
- return this.xdsServerSvr.syncProject(prj.id);
- }
-
- private _isUsableProject(p) {
- return p && p.isInSync &&
- (p.status === ProjectStatus.Enable) &&
- (p.status !== ProjectStatus.Syncing);
- }
-
- private _getProjectIdx(id: string): number {
- return this.confStore.projects.findIndex((item) => item.id === id);
- }
-
- private _addProject(rPrj: IXDSFolderConfig, noNext?: boolean) {
-
- // Convert XDSFolderConfig to IProject
- let pp: IProject = {
- id: rPrj.id,
- label: rPrj.label,
- pathClient: rPrj.path,
- pathServer: rPrj.dataPathMap.serverPath,
- type: rPrj.type,
- status: rPrj.status,
- isInSync: rPrj.isInSync,
- isUsable: this._isUsableProject(rPrj),
- defaultSdkID: rPrj.defaultSdkID,
- serverPrjDef: Object.assign({}, rPrj), // do a copy
- };
-
- // add new project
- this.confStore.projects.push(pp);
-
- // sort project array
- this.confStore.projects.sort((a, b) => {
- if (a.label < b.label) {
- return -1;
- }
- if (a.label > b.label) {
- return 1;
- }
- return 0;
- });
-
- // FIXME: maybe reduce subject to only .project
- //this.confSubject.next(Object.assign({}, this.confStore).project);
- if (!noNext) {
- this.confSubject.next(Object.assign({}, this.confStore));
- }
- }
-}
diff --git a/webapp/src/app/services/sdk.service.ts b/webapp/src/app/services/sdk.service.ts
deleted file mode 100644
index fa4cd55..0000000
--- a/webapp/src/app/services/sdk.service.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { Injectable, SecurityContext } from '@angular/core';
-import { Observable } from 'rxjs/Observable';
-import { BehaviorSubject } from 'rxjs/BehaviorSubject';
-
-import { XDSServerService } from "../services/xdsserver.service";
-
-export interface ISdk {
- id: string;
- profile: string;
- version: string;
- arch: number;
- path: string;
-}
-
-@Injectable()
-export class SdkService {
- public Sdks$: Observable<ISdk[]>;
-
- private _sdksList = [];
- private current: ISdk;
- private sdksSubject = <BehaviorSubject<ISdk[]>>new BehaviorSubject(this._sdksList);
-
- constructor(private xdsSvr: XDSServerService) {
- this.current = null;
- this.Sdks$ = this.sdksSubject.asObservable();
-
- this.xdsSvr.getSdks().subscribe((s) => {
- this._sdksList = s;
- this.sdksSubject.next(s);
- });
- }
-
- public setCurrent(s: ISdk) {
- this.current = s;
- }
-
- public getCurrent(): ISdk {
- return this.current;
- }
-
- public getCurrentId(): string {
- if (this.current && this.current.id) {
- return this.current.id;
- }
- return "";
- }
-} \ No newline at end of file
diff --git a/webapp/src/app/services/syncthing.service.ts b/webapp/src/app/services/syncthing.service.ts
deleted file mode 100644
index 2e6da1c..0000000
--- a/webapp/src/app/services/syncthing.service.ts
+++ /dev/null
@@ -1,348 +0,0 @@
-import { Injectable } from '@angular/core';
-import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http';
-import { CookieService } from 'ngx-cookie';
-import { Location } from '@angular/common';
-import { Observable } from 'rxjs/Observable';
-import { BehaviorSubject } from 'rxjs/BehaviorSubject';
-
-// Import RxJs required methods
-import 'rxjs/add/operator/map';
-import 'rxjs/add/operator/catch';
-import 'rxjs/add/observable/throw';
-import 'rxjs/add/observable/of';
-import 'rxjs/add/observable/timer';
-import 'rxjs/add/operator/retryWhen';
-
-export interface ISyncThingProject {
- id: string;
- path: string;
- serverSyncThingID: string;
- label?: string;
-}
-
-export interface ISyncThingStatus {
- ID: string;
- baseURL: string;
- connected: boolean;
- connectionRetry: number;
- tilde: string;
- rawStatus: any;
-}
-
-// Private interfaces of Syncthing
-const ISTCONFIG_VERSION = 20;
-
-interface ISTFolderDeviceConfiguration {
- deviceID: string;
- introducedBy: string;
-}
-interface ISTFolderConfiguration {
- id: string;
- label: string;
- path: string;
- type?: number;
- devices?: ISTFolderDeviceConfiguration[];
- rescanIntervalS?: number;
- ignorePerms?: boolean;
- autoNormalize?: boolean;
- minDiskFreePct?: number;
- versioning?: { type: string; params: string[] };
- copiers?: number;
- pullers?: number;
- hashers?: number;
- order?: number;
- ignoreDelete?: boolean;
- scanProgressIntervalS?: number;
- pullerSleepS?: number;
- pullerPauseS?: number;
- maxConflicts?: number;
- disableSparseFiles?: boolean;
- disableTempIndexes?: boolean;
- fsync?: boolean;
- paused?: boolean;
-}
-
-interface ISTDeviceConfiguration {
- deviceID: string;
- name?: string;
- address?: string[];
- compression?: string;
- certName?: string;
- introducer?: boolean;
- skipIntroductionRemovals?: boolean;
- introducedBy?: string;
- paused?: boolean;
- allowedNetwork?: string[];
-}
-
-interface ISTGuiConfiguration {
- enabled: boolean;
- address: string;
- user?: string;
- password?: string;
- useTLS: boolean;
- apiKey?: string;
- insecureAdminAccess?: boolean;
- theme: string;
- debugging: boolean;
- insecureSkipHostcheck?: boolean;
-}
-
-interface ISTOptionsConfiguration {
- listenAddresses: string[];
- globalAnnounceServer: string[];
- // To be completed ...
-}
-
-interface ISTConfiguration {
- version: number;
- folders: ISTFolderConfiguration[];
- devices: ISTDeviceConfiguration[];
- gui: ISTGuiConfiguration;
- options: ISTOptionsConfiguration;
- ignoredDevices: string[];
-}
-
-// Default settings
-const DEFAULT_GUI_PORT = 8386;
-const DEFAULT_GUI_API_KEY = "1234abcezam";
-const DEFAULT_RESCAN_INTERV = 0; // 0: use syncthing-inotify to detect changes
-
-
-@Injectable()
-export class SyncthingService {
-
- public Status$: Observable<ISyncThingStatus>;
-
- private baseRestUrl: string;
- private apikey: string;
- private localSTID: string;
- private stCurVersion: number;
- private connectionMaxRetry: number;
- private _status: ISyncThingStatus = {
- ID: null,
- baseURL: "",
- connected: false,
- connectionRetry: 0,
- tilde: "",
- rawStatus: null,
- };
- private statusSubject = <BehaviorSubject<ISyncThingStatus>>new BehaviorSubject(this._status);
-
- constructor(private http: Http, private _window: Window, private cookie: CookieService) {
- this._status.baseURL = 'http://localhost:' + DEFAULT_GUI_PORT;
- this.baseRestUrl = this._status.baseURL + '/rest';
- this.apikey = DEFAULT_GUI_API_KEY;
- this.stCurVersion = -1;
- this.connectionMaxRetry = 10; // 10 seconds
-
- this.Status$ = this.statusSubject.asObservable();
- }
-
- connect(retry: number, url?: string): Observable<ISyncThingStatus> {
- if (url) {
- this._status.baseURL = url;
- this.baseRestUrl = this._status.baseURL + '/rest';
- }
- this._status.connected = false;
- this._status.ID = null;
- this._status.connectionRetry = 0;
- this.connectionMaxRetry = retry || 3600; // 1 hour
- return this.getStatus();
- }
-
- getID(): Observable<string> {
- if (this._status.ID != null) {
- return Observable.of(this._status.ID);
- }
- return this.getStatus().map(sts => sts.ID);
- }
-
- getStatus(): Observable<ISyncThingStatus> {
- return this._get('/system/status')
- .map((status) => {
- this._status.ID = status["myID"];
- this._status.tilde = status["tilde"];
- console.debug('ST local ID', this._status.ID);
-
- this._status.rawStatus = status;
-
- return this._status;
- });
- }
-
- getProjects(): Observable<ISTFolderConfiguration[]> {
- return this._getConfig()
- .map((conf) => conf.folders);
- }
-
- addProject(prj: ISyncThingProject): Observable<ISTFolderConfiguration> {
- return this.getID()
- .flatMap(() => this._getConfig())
- .flatMap((stCfg) => {
- let newDevID = prj.serverSyncThingID;
-
- // Add new Device if needed
- let dev = stCfg.devices.filter(item => item.deviceID === newDevID);
- if (dev.length <= 0) {
- stCfg.devices.push(
- {
- deviceID: newDevID,
- name: "Builder_" + newDevID.slice(0, 15),
- address: ["dynamic"],
- }
- );
- }
-
- // Add or update Folder settings
- let label = prj.label || "";
- let scanInterval = parseInt(this.cookie.get("st-rescanInterval"), 10) || DEFAULT_RESCAN_INTERV;
- let folder: ISTFolderConfiguration = {
- id: prj.id,
- label: label,
- path: prj.path,
- devices: [{ deviceID: newDevID, introducedBy: "" }],
- autoNormalize: true,
- rescanIntervalS: scanInterval,
- };
-
- let idx = stCfg.folders.findIndex(item => item.id === prj.id);
- if (idx === -1) {
- stCfg.folders.push(folder);
- } else {
- let newFld = Object.assign({}, stCfg.folders[idx], folder);
- stCfg.folders[idx] = newFld;
- }
-
- // Set new config
- return this._setConfig(stCfg);
- })
- .flatMap(() => this._getConfig())
- .map((newConf) => {
- let idx = newConf.folders.findIndex(item => item.id === prj.id);
- return newConf.folders[idx];
- });
- }
-
- deleteProject(id: string): Observable<ISTFolderConfiguration> {
- let delPrj: ISTFolderConfiguration;
- return this._getConfig()
- .flatMap((conf: ISTConfiguration) => {
- let idx = conf.folders.findIndex(item => item.id === id);
- if (idx === -1) {
- throw new Error("Cannot delete project: not found");
- }
- delPrj = Object.assign({}, conf.folders[idx]);
- conf.folders.splice(idx, 1);
- return this._setConfig(conf);
- })
- .map(() => delPrj);
- }
-
- /*
- * --- Private functions ---
- */
- private _getConfig(): Observable<ISTConfiguration> {
- return this._get('/system/config');
- }
-
- private _setConfig(cfg: ISTConfiguration): Observable<any> {
- return this._post('/system/config', cfg);
- }
-
- private _attachAuthHeaders(options?: any) {
- options = options || {};
- let headers = options.headers || new Headers();
- // headers.append('Authorization', 'Basic ' + btoa('username:password'));
- headers.append('Accept', 'application/json');
- headers.append('Content-Type', 'application/json');
- if (this.apikey !== "") {
- headers.append('X-API-Key', this.apikey);
-
- }
- options.headers = headers;
- return options;
- }
-
- private _checkAlive(): Observable<boolean> {
- if (this._status.connected) {
- return Observable.of(true);
- }
-
- return this.http.get(this.baseRestUrl + '/system/version', this._attachAuthHeaders())
- .map((r) => this._status.connected = true)
- .retryWhen((attempts) => {
- this._status.connectionRetry = 0;
- return attempts.flatMap(error => {
- this._status.connected = false;
- if (++this._status.connectionRetry >= this.connectionMaxRetry) {
- return Observable.throw("Syncthing local daemon not responding (url=" + this._status.baseURL + ")");
- } else {
- return Observable.timer(1000);
- }
- });
- });
- }
-
- private _getAPIVersion(): Observable<number> {
- if (this.stCurVersion !== -1) {
- return Observable.of(this.stCurVersion);
- }
-
- return this.http.get(this.baseRestUrl + '/system/config', this._attachAuthHeaders())
- .map((res: Response) => {
- let conf: ISTConfiguration = res.json();
- this.stCurVersion = (conf && conf.version) || -1;
- return this.stCurVersion;
- })
- .catch(this._handleError);
- }
-
- private _checkAPIVersion(): Observable<number> {
- return this._getAPIVersion().map(ver => {
- if (ver !== ISTCONFIG_VERSION) {
- throw new Error("Unsupported Syncthing version api (" + ver +
- " != " + ISTCONFIG_VERSION + ") !");
- }
- return ver;
- });
- }
-
- private _get(url: string): Observable<any> {
- return this._checkAlive()
- .flatMap(() => this._checkAPIVersion())
- .flatMap(() => this.http.get(this.baseRestUrl + url, this._attachAuthHeaders()))
- .map((res: Response) => res.json())
- .catch(this._handleError);
- }
-
- private _post(url: string, body: any): Observable<any> {
- return this._checkAlive()
- .flatMap(() => this._checkAPIVersion())
- .flatMap(() => this.http.post(this.baseRestUrl + url, JSON.stringify(body), this._attachAuthHeaders()))
- .map((res: Response) => {
- if (res && res.status && res.status === 200) {
- return res;
- }
- throw new Error(res.toString());
-
- })
- .catch(this._handleError);
- }
-
- private _handleError(error: Response | any) {
- // In a real world app, you might use a remote logging infrastructure
- let errMsg: string;
- if (this._status) {
- this._status.connected = false;
- }
- if (error instanceof Response) {
- const body = error.json() || 'Server error';
- const err = body.error || JSON.stringify(body);
- errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
- } else {
- errMsg = error.message ? error.message : error.toString();
- }
- return Observable.throw(errMsg);
- }
-}
diff --git a/webapp/src/app/services/utils.service.ts b/webapp/src/app/services/utils.service.ts
deleted file mode 100644
index 84b9ab6..0000000
--- a/webapp/src/app/services/utils.service.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Injectable } from '@angular/core';
-
-@Injectable()
-export class UtilsService {
- constructor() { }
-
- getOSName(lowerCase?: boolean): string {
- var checkField = function (ff) {
- if (ff.indexOf("Linux") !== -1) {
- return "Linux";
- } else if (ff.indexOf("Win") !== -1) {
- return "Windows";
- } else if (ff.indexOf("Mac") !== -1) {
- return "MacOS";
- } else if (ff.indexOf("X11") !== -1) {
- return "UNIX";
- }
- return "";
- };
-
- let OSName = checkField(navigator.platform);
- if (OSName === "") {
- OSName = checkField(navigator.appVersion);
- }
- if (OSName === "") {
- OSName = "Unknown OS";
- }
- if (lowerCase) {
- return OSName.toLowerCase();
- }
- return OSName;
- }
-} \ No newline at end of file
diff --git a/webapp/src/app/services/xdsagent.service.ts b/webapp/src/app/services/xdsagent.service.ts
deleted file mode 100644
index c6c52c8..0000000
--- a/webapp/src/app/services/xdsagent.service.ts
+++ /dev/null
@@ -1,216 +0,0 @@
-import { Injectable } from '@angular/core';
-import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http';
-import { Location } from '@angular/common';
-import { Observable } from 'rxjs/Observable';
-import { Subject } from 'rxjs/Subject';
-import { BehaviorSubject } from 'rxjs/BehaviorSubject';
-import * as io from 'socket.io-client';
-
-import { AlertService } from './alert.service';
-
-
-// Import RxJs required methods
-import 'rxjs/add/operator/map';
-import 'rxjs/add/operator/catch';
-import 'rxjs/add/observable/throw';
-
-export interface IXDSVersion {
- version: string;
- apiVersion: string;
- gitTag: string;
-
-}
-
-export interface IXDSDeploy {
- boardIP: string;
- file: string;
-}
-
-export interface IAgentStatus {
- baseURL: string;
- connected: boolean;
- WS_connected: boolean;
- connectionRetry: number;
- version: string;
-}
-
-// Default settings
-const DEFAULT_PORT = 8010;
-const DEFAULT_API_KEY = "1234abcezam";
-const API_VERSION = "v1";
-
-@Injectable()
-export class XDSAgentService {
- public Status$: Observable<IAgentStatus>;
-
- private baseRestUrl: string;
- private wsUrl: string;
- private connectionMaxRetry: number;
- private apikey: string;
- private _status: IAgentStatus = {
- baseURL: "",
- connected: false,
- WS_connected: false,
- connectionRetry: 0,
- version: "",
- };
- private statusSubject = <BehaviorSubject<IAgentStatus>>new BehaviorSubject(this._status);
-
-
- private socket: SocketIOClient.Socket;
-
- constructor(private http: Http, private _window: Window, private alert: AlertService) {
-
- this.Status$ = this.statusSubject.asObservable();
-
- this.apikey = DEFAULT_API_KEY; // FIXME Add dynamic allocated key
- this._initURLs('http://localhost:' + DEFAULT_PORT);
- }
-
- connect(retry: number, url?: string): Observable<IAgentStatus> {
- if (url) {
- this._initURLs(url);
- }
- this._status.connected = false;
- this._status.connectionRetry = 0;
- this.connectionMaxRetry = retry || 3600; // 1 hour
-
- // Init IO Socket connection
- this._handleIoSocket();
-
- // Get Version in order to check connection via a REST request
- return this.getVersion()
- .map((v) => {
- this._status.version = v.version;
- this.statusSubject.next(Object.assign({}, this._status));
- return this._status;
- });
- }
-
- public getVersion(): Observable<IXDSVersion> {
- return this._get('/version');
- }
-
- public deploy(dpy: IXDSDeploy) {
- return this._post('/deploy', dpy);
- }
-
- private _initURLs(url: string) {
- this._status.baseURL = url;
- this.baseRestUrl = this._status.baseURL + '/api/' + API_VERSION;
- let re = this._status.baseURL.match(/http[s]?:\/\/([^\/]*)[\/]?/);
- if (re === null || re.length < 2) {
- this.wsUrl = '';
- console.error('ERROR: cannot determine Websocket url');
- return;
- }
- this.wsUrl = 'ws://' + re[1];
- }
-
- private _WSState(sts: boolean) {
- this._status.WS_connected = sts;
- this.statusSubject.next(Object.assign({}, this._status));
- }
-
- private _handleIoSocket() {
- this.socket = io(this.wsUrl, { transports: ['websocket'] });
-
- this.socket.on('connect_error', (res) => {
- this._WSState(false);
- console.error('WS Connect_error ', res);
- });
-
- this.socket.on('connect', (res) => {
- this._WSState(true);
- });
-
- this.socket.on('disconnection', (res) => {
- this._WSState(false);
- this.alert.error('WS disconnection: ' + res);
- });
-
- this.socket.on('error', (err) => {
- console.error('WS error:', err);
- });
-
- }
-
- private _attachAuthHeaders(options?: any) {
- options = options || {};
- let headers = options.headers || new Headers();
- // headers.append('Authorization', 'Basic ' + btoa('username:password'));
- headers.append('Accept', 'application/json');
- headers.append('Content-Type', 'application/json');
- if (this.apikey !== "") {
- headers.append('X-API-Key', this.apikey);
-
- }
-
- options.headers = headers;
- return options;
- }
-
- private _checkAlive(): Observable<boolean> {
- if (this._status.connected) {
- return Observable.of(true);
- }
-
- return this.http.get(this.baseRestUrl + "/version", this._attachAuthHeaders())
- .map((r) => this._status.connected = true)
- .retryWhen((attempts) => {
- this._status.connectionRetry = 0;
- return attempts.flatMap(error => {
- this._status.connected = false;
- if (++this._status.connectionRetry >= this.connectionMaxRetry) {
- return Observable.throw("XDS local Agent not responding (url=" + this._status.baseURL + ")");
- } else {
- return Observable.timer(1000);
- }
- });
- });
- }
-
- private _get(url: string): Observable<any> {
- return this._checkAlive()
- .flatMap(() => this.http.get(this.baseRestUrl + url, this._attachAuthHeaders()))
- .map((res: Response) => res.json())
- .catch(this._decodeError);
- }
- private _post(url: string, body: any): Observable<any> {
- return this._checkAlive()
- .flatMap(() => this.http.post(this.baseRestUrl + url, JSON.stringify(body), this._attachAuthHeaders()))
- .map((res: Response) => res.json())
- .catch(this._decodeError);
- }
- private _delete(url: string): Observable<any> {
- return this._checkAlive()
- .flatMap(() => this.http.delete(this.baseRestUrl + url, this._attachAuthHeaders()))
- .map((res: Response) => res.json())
- .catch(this._decodeError);
- }
-
- private _decodeError(err: Response | any) {
- let e: string;
- if (this._status) {
- this._status.connected = false;
- }
- if (err instanceof Response) {
- const body = err.json() || 'Server error';
- e = body.error || JSON.stringify(body);
- if (!e || e === "") {
- e = `${err.status} - ${err.statusText || 'Unknown error'}`;
- }
- } else if (typeof err === "object") {
- if (err.statusText) {
- e = err.statusText;
- } else if (err.error) {
- e = String(err.error);
- } else {
- e = JSON.stringify(err);
- }
- } else {
- e = err.message ? err.message : err.toString();
- }
- return Observable.throw(e);
- }
-}
diff --git a/webapp/src/app/services/xdsserver.service.ts b/webapp/src/app/services/xdsserver.service.ts
deleted file mode 100644
index b69a196..0000000
--- a/webapp/src/app/services/xdsserver.service.ts
+++ /dev/null
@@ -1,296 +0,0 @@
-import { Injectable } from '@angular/core';
-import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http';
-import { Location } from '@angular/common';
-import { Observable } from 'rxjs/Observable';
-import { Subject } from 'rxjs/Subject';
-import { BehaviorSubject } from 'rxjs/BehaviorSubject';
-import * as io from 'socket.io-client';
-
-import { AlertService } from './alert.service';
-import { ISdk } from './sdk.service';
-
-
-// Import RxJs required methods
-import 'rxjs/add/operator/map';
-import 'rxjs/add/operator/catch';
-import 'rxjs/add/observable/throw';
-import 'rxjs/add/operator/mergeMap';
-
-
-export interface IXDSConfigProject {
- id: string;
- path: string;
- clientSyncThingID: string;
- type: number;
- label?: string;
- defaultSdkID?: string;
-}
-
-interface IXDSBuilderConfig {
- ip: string;
- port: string;
- syncThingID: string;
-}
-
-export interface IXDSFolderConfig {
- id: string;
- label: string;
- path: string;
- type: number;
- status?: string;
- isInSync?: boolean;
- defaultSdkID: string;
-
- // FIXME better with union but tech pb with go code
- //data?: IXDSPathMapConfig|IXDSCloudSyncConfig;
- dataPathMap?: IXDSPathMapConfig;
- dataCloudSync?: IXDSCloudSyncConfig;
-}
-
-export interface IXDSPathMapConfig {
- // TODO
- serverPath: string;
-}
-
-export interface IXDSCloudSyncConfig {
- syncThingID: string;
- builderSThgID?: string;
-}
-
-interface IXDSConfig {
- version: number;
- builder: IXDSBuilderConfig;
- folders: IXDSFolderConfig[];
-}
-
-export interface IXDSAgentTarball {
- os: string;
- arch: string;
- version: string;
- rawVersion: string;
- fileUrl: string;
-}
-
-export interface IXDSAgentInfo {
- tarballs: IXDSAgentTarball[];
-}
-
-export interface ISdkMessage {
- wsID: string;
- msgType: string;
- data: any;
-}
-
-export interface ICmdOutput {
- cmdID: string;
- timestamp: string;
- stdout: string;
- stderr: string;
-}
-
-export interface ICmdExit {
- cmdID: string;
- timestamp: string;
- code: number;
- error: string;
-}
-
-export interface IServerStatus {
- WS_connected: boolean;
-
-}
-
-const FOLDER_TYPE_CLOUDSYNC = 2;
-
-@Injectable()
-export class XDSServerService {
-
- public CmdOutput$ = <Subject<ICmdOutput>>new Subject();
- public CmdExit$ = <Subject<ICmdExit>>new Subject();
- public FolderStateChange$ = <Subject<IXDSFolderConfig>>new Subject();
- public Status$: Observable<IServerStatus>;
-
-
- private baseUrl: string;
- private wsUrl: string;
- private _status = { WS_connected: false };
- private statusSubject = <BehaviorSubject<IServerStatus>>new BehaviorSubject(this._status);
-
-
- private socket: SocketIOClient.Socket;
-
- constructor(private http: Http, private _window: Window, private alert: AlertService) {
-
- this.Status$ = this.statusSubject.asObservable();
-
- this.baseUrl = this._window.location.origin + '/api/v1';
- let re = this._window.location.origin.match(/http[s]?:\/\/([^\/]*)[\/]?/);
- if (re === null || re.length < 2) {
- console.error('ERROR: cannot determine Websocket url');
- } else {
- this.wsUrl = 'ws://' + re[1];
- this._handleIoSocket();
- this._RegisterEvents();
- }
- }
-
- private _WSState(sts: boolean) {
- this._status.WS_connected = sts;
- this.statusSubject.next(Object.assign({}, this._status));
- }
-
- private _handleIoSocket() {
- this.socket = io(this.wsUrl, { transports: ['websocket'] });
-
- this.socket.on('connect_error', (res) => {
- this._WSState(false);
- console.error('WS Connect_error ', res);
- });
-
- this.socket.on('connect', (res) => {
- this._WSState(true);
- });
-
- this.socket.on('disconnection', (res) => {
- this._WSState(false);
- this.alert.error('WS disconnection: ' + res);
- });
-
- this.socket.on('error', (err) => {
- console.error('WS error:', err);
- });
-
- this.socket.on('make:output', data => {
- this.CmdOutput$.next(Object.assign({}, <ICmdOutput>data));
- });
-
- this.socket.on('make:exit', data => {
- this.CmdExit$.next(Object.assign({}, <ICmdExit>data));
- });
-
- this.socket.on('exec:output', data => {
- this.CmdOutput$.next(Object.assign({}, <ICmdOutput>data));
- });
-
- this.socket.on('exec:exit', data => {
- this.CmdExit$.next(Object.assign({}, <ICmdExit>data));
- });
-
- this.socket.on('event:FolderStateChanged', ev => {
- if (ev && ev.folder) {
- this.FolderStateChange$.next(Object.assign({}, ev.folder));
- }
- });
- }
-
- private _RegisterEvents() {
- let ev = "FolderStateChanged";
- this._post('/events/register', { "name": ev })
- .subscribe(
- res => { },
- error => {
- this.alert.error("ERROR while registering events " + ev + ": ", error);
- }
- );
- }
-
- getSdks(): Observable<ISdk[]> {
- return this._get('/sdks');
- }
-
- getXdsAgentInfo(): Observable<IXDSAgentInfo> {
- return this._get('/xdsagent/info');
- }
-
- getProjects(): Observable<IXDSFolderConfig[]> {
- return this._get('/folders');
- }
-
- addProject(cfg: IXDSFolderConfig): Observable<IXDSFolderConfig> {
- return this._post('/folder', cfg);
- }
-
- deleteProject(id: string): Observable<IXDSFolderConfig> {
- return this._delete('/folder/' + id);
- }
-
- syncProject(id: string): Observable<string> {
- return this._post('/folder/sync/' + id, {});
- }
-
- exec(prjID: string, dir: string, cmd: string, sdkid?: string, args?: string[], env?: string[]): Observable<any> {
- return this._post('/exec',
- {
- id: prjID,
- rpath: dir,
- cmd: cmd,
- sdkid: sdkid || "",
- args: args || [],
- env: env || [],
- });
- }
-
- make(prjID: string, dir: string, sdkid?: string, args?: string[], env?: string[]): Observable<any> {
- return this._post('/make',
- {
- id: prjID,
- rpath: dir,
- sdkid: sdkid,
- args: args || [],
- env: env || [],
- });
- }
-
-
- private _attachAuthHeaders(options?: any) {
- options = options || {};
- let headers = options.headers || new Headers();
- // headers.append('Authorization', 'Basic ' + btoa('username:password'));
- headers.append('Accept', 'application/json');
- headers.append('Content-Type', 'application/json');
- // headers.append('Access-Control-Allow-Origin', '*');
-
- options.headers = headers;
- return options;
- }
-
- private _get(url: string): Observable<any> {
- return this.http.get(this.baseUrl + url, this._attachAuthHeaders())
- .map((res: Response) => res.json())
- .catch(this._decodeError);
- }
- private _post(url: string, body: any): Observable<any> {
- return this.http.post(this.baseUrl + url, JSON.stringify(body), this._attachAuthHeaders())
- .map((res: Response) => res.json())
- .catch((error) => {
- return this._decodeError(error);
- });
- }
- private _delete(url: string): Observable<any> {
- return this.http.delete(this.baseUrl + url, this._attachAuthHeaders())
- .map((res: Response) => res.json())
- .catch(this._decodeError);
- }
-
- private _decodeError(err: any) {
- let e: string;
- if (err instanceof Response) {
- const body = err.json() || 'Server error';
- e = body.error || JSON.stringify(body);
- if (!e || e === "") {
- e = `${err.status} - ${err.statusText || 'Unknown error'}`;
- }
- } else if (typeof err === "object") {
- if (err.statusText) {
- e = err.statusText;
- } else if (err.error) {
- e = String(err.error);
- } else {
- e = JSON.stringify(err);
- }
- } else {
- e = err.message ? err.message : err.toString();
- }
- return Observable.throw(e);
- }
-}
diff --git a/webapp/src/index.html b/webapp/src/index.html
index 290b4be..45ac90d 100644
--- a/webapp/src/index.html
+++ b/webapp/src/index.html
@@ -2,49 +2,97 @@
<head>
<title>
- XDS Dashboard
+ XDS Server
</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
-
<link rel="icon" type="image/x-icon" href="assets/favicon.ico">
- <!-- TODO cleanup
- <link rel="stylesheet" href="lib/foundation-sites/dist/css/foundation.min.css">
- -->
- <link <link href="lib/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
+ <link rel="stylesheet" href="font-awesome.min.css">
- <link rel="stylesheet" href="lib/font-awesome/css/font-awesome.min.css">
- <link rel="stylesheet" href="lib/font-awesome-animation/dist/font-awesome-animation.min.css">
+ <style>
+ body.page-content {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ position: relative;
+ height: 100%;
+ width: auto;
+ text-align: center;
+ background: url("assets/images/background_iot_bzh_light.png") 0 0 no-repeat;
+ background-color: lightgrey;
+ background-size: cover;
+ background-position: center;
+ color: #FFFFFF;
+ }
- <!-- 1. Load libraries -->
- <!-- Polyfill(s) for older browsers -->
- <script src="lib/core-js/client/shim.min.js"></script>
+ img {
+ width: 15em;
+ }
- <script src="lib/zone.js/dist/zone.js"></script>
- <script src="lib/reflect-metadata/Reflect.js"></script>
- <script src="lib/systemjs/dist/system.src.js"></script>
+ li {
+ list-style: none;
+ font-size: x-large;
+ padding-bottom: 10px;
+ }
- <!-- 2. Configure SystemJS -->
- <script src="systemjs.config.js"></script>
- <script>
- System.import('app')
- .then(null, console.error.bind(console));
- </script>
+ a {
+ color: royalblue;
+ }
- <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
+ i.fa {
+ font-size: smaller;
+ }
+ #dashbButton {
+ font-size: large;
+ font-weight: bold;
+ background: none;
+ color: royalblue;
+ }
+ </style>
</head>
-<!-- 3. Display the application -->
+<body class="page-content">
+
+ <img id="logo-iot" src="assets/images/iot-bzh-logo-small.png">
+
+ <h1 id="title">X(cross) Development System</h1>
+
+ <h2>Please start XDS agent on your machine<br> and
+ <br> connect to XDS Dashboard
+ </h2>
+
+ <button id="dashbButton">
+ Try to connect to dashboard<br>
+ http://localhost:8000
+ </button>
+ <script type="text/javascript">
+ document.getElementById("dashbButton").onclick = function () {
+ location.href = "http://localhost:8000";
+ };
+ </script>
+ <i style="font:xx-small;">(URL may depend on your configuration)</i>
+
+ <br><br><br>
-<body style="padding-top: 70px;"> <!-- padding needed due to fixed navbar -->
- <app>
- <div style="text-align:center; position:absolute; top:50%; width:100%; transform:translate(0,-50%);">
- <img id="logo-iot" src="assets/images/iot-bzh-logo-small.png">
- <br> Loading...
- <i class="fa fa-spinner fa-spin fa-fw"></i>
- </div>
- </app>
+ <h2>For more information, please refer to XDS User's Guide:</h2>
+ <ul>
+ <li>
+ <a href="http://docs.automotivelinux.org/docs/devguides/en/dev/reference/xds/part-1/1_install-client.html">
+ Install instructions <i class="fa fa-external-link" aria-hidden="true"></i>
+ </a>
+ </li>
+ <li>
+ <a href="http://docs.automotivelinux.org/docs/devguides/en/dev/#xcross-development-system-user's-guide">
+ Online User's guide <i class="fa fa-external-link" aria-hidden="true"></i>
+ </a>
+ </li>
+ <li>
+ <a href="http://iot.bzh/download/public/2017/XDS/docs/XDS_UsersGuide.pdf">
+ User's guide (PDF file) <i class="fa fa-external-link" aria-hidden="true"></i>
+ </a>
+ </li>
+ </ul>
</body>
</html>
diff --git a/webapp/src/systemjs.config.js b/webapp/src/systemjs.config.js
deleted file mode 100644
index 15c52ba..0000000
--- a/webapp/src/systemjs.config.js
+++ /dev/null
@@ -1,69 +0,0 @@
-(function (global) {
- System.config({
- paths: {
- // paths serve as alias
- 'npm:': 'lib/'
- },
- bundles: {
- "npm:rxjs-system-bundle/Rx.system.min.js": [
- "rxjs",
- "rxjs/*",
- "rxjs/operator/*",
- "rxjs/observable/*",
- "rxjs/scheduler/*",
- "rxjs/symbol/*",
- "rxjs/add/operator/*",
- "rxjs/add/observable/*",
- "rxjs/util/*"
- ]
- },
- // map tells the System loader where to look for things
- map: {
- // our app is within the app folder
- app: 'app',
- // angular bundles
- '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
- '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
- '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
- '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
- '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
- '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
- '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
- '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
- 'ngx-cookie': 'npm:ngx-cookie/bundles/ngx-cookie.umd.js',
- // ng2-bootstrap
- 'moment': 'npm:moment',
- 'ngx-bootstrap/alert': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
- 'ngx-bootstrap/modal': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
- 'ngx-bootstrap/accordion': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
- 'ngx-bootstrap/carousel': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
- 'ngx-bootstrap/popover': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
- 'ngx-bootstrap/dropdown': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
- 'ngx-bootstrap/collapse': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js',
- // other libraries
- 'socket.io-client': 'npm:socket.io-client/dist/socket.io.min.js'
- },
- // packages tells the System loader how to load when no filename and/or no extension
- packages: {
- 'app': {
- main: './main.js',
- defaultExtension: 'js'
- },
- 'rxjs': {
- defaultExtension: false
- },
- 'socket.io-client': {
- defaultExtension: 'js'
- },
- 'ngx-bootstrap': {
- format: 'cjs',
- main: 'bundles/ng2-bootstrap.umd.js',
- defaultExtension: 'js'
- },
- 'moment': {
- main: 'moment.js',
- defaultExtension: 'js'
- }
- }
- });
-})(this);
diff --git a/webapp/tsconfig.json b/webapp/tsconfig.json
deleted file mode 100644
index 9bad681..0000000
--- a/webapp/tsconfig.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "compilerOptions": {
- "outDir": "dist/app",
- "target": "es5",
- "module": "commonjs",
- "moduleResolution": "node",
- "sourceMap": true,
- "emitDecoratorMetadata": true,
- "experimentalDecorators": true,
- "removeComments": false,
- "noImplicitAny": false,
- "noStrictGenericChecks": true // better to switch to RxJS 5.4.2 ; workaround https://stackoverflow.com/questions/44810195/how-do-i-get-around-this-subject-incorrectly-extends-observable-error-in-types
- },
- "exclude": [
- "gulpfile.ts",
- "node_modules"
- ]
-}
diff --git a/webapp/tslint.json b/webapp/tslint.json
deleted file mode 100644
index 15969a4..0000000
--- a/webapp/tslint.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "rules": {
- "class-name": true,
- "curly": true,
- "eofline": false,
- "forin": true,
- "indent": [
- true,
- 4
- ],
- "label-position": true,
- "max-line-length": [
- true,
- 140
- ],
- "no-arg": true,
- "no-bitwise": true,
- "no-console": [
- true,
- "info",
- "time",
- "timeEnd",
- "trace"
- ],
- "no-construct": true,
- "no-debugger": true,
- "no-duplicate-variable": true,
- "no-empty": false,
- "no-eval": true,
- "no-string-literal": false,
- "no-trailing-whitespace": true,
- "no-use-before-declare": true,
- "one-line": [
- true,
- "check-open-brace",
- "check-catch",
- "check-else",
- "check-whitespace"
- ],
- "radix": true,
- "semicolon": true,
- "triple-equals": [
- true,
- "allow-null-check"
- ],
- "variable-name": false,
- "whitespace": [
- true,
- "check-branch",
- "check-decl",
- "check-operator",
- "check-separator"
- ]
- }
-}
diff --git a/webapp/tslint.prod.json b/webapp/tslint.prod.json
deleted file mode 100644
index aa64c7f..0000000
--- a/webapp/tslint.prod.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "rules": {
- "class-name": true,
- "curly": true,
- "eofline": false,
- "forin": true,
- "indent": [
- true,
- 4
- ],
- "label-position": true,
- "max-line-length": [
- true,
- 140
- ],
- "no-arg": true,
- "no-bitwise": true,
- "no-console": [
- true,
- "debug",
- "info",
- "time",
- "timeEnd",
- "trace"
- ],
- "no-construct": true,
- "no-debugger": true,
- "no-duplicate-variable": true,
- "no-empty": false,
- "no-eval": true,
- "no-string-literal": false,
- "no-trailing-whitespace": true,
- "no-use-before-declare": true,
- "one-line": [
- true,
- "check-open-brace",
- "check-catch",
- "check-else",
- "check-whitespace"
- ],
- "radix": true,
- "semicolon": true,
- "triple-equals": [
- true,
- "allow-null-check"
- ],
- "variable-name": false,
- "whitespace": [
- true,
- "check-branch",
- "check-decl",
- "check-operator",
- "check-separator"
- ]
- }
-}
diff --git a/webapp/typings.json b/webapp/typings.json
deleted file mode 100644
index 23c6a41..0000000
--- a/webapp/typings.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "dependencies": {},
- "devDependencies": {},
- "globalDependencies": {
- "es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654",
- "socket.io-client": "registry:dt/socket.io-client#1.4.4+20160317120654"
- },
- "globalDevDependencies": {
- "jasmine": "registry:dt/jasmine#2.2.0+20160505161446"
- }
-}