Used non default syncthing port to avoid confict.
[src/xds/xds-server.git] / webapp / src / app / services / config.service.ts
index c65332f..3f07a6a 100644 (file)
@@ -29,9 +29,13 @@ export var ProjectTypes = [
     { value: ProjectType.SYNCTHING, display: "Cloud Sync" }
 ];
 
-export interface INativeProject {
-    // TODO
-}
+export var ProjectStatus = {
+    ErrorConfig: "ErrorConfig",
+    Disable: "Disable",
+    Enable: "Enable",
+    Pause: "Pause",
+    Syncing: "Syncing"
+};
 
 export interface IProject {
     id?: string;
@@ -39,8 +43,10 @@ export interface IProject {
     pathClient: string;
     pathServer?: string;
     type: ProjectType;
-    remotePrjDef?: INativeProject | ISyncThingProject;
-    localPrjDef?: any;
+    status?: string;
+    isInSync?: boolean;
+    isUsable?: boolean;
+    serverPrjDef?: IXDSFolderConfig;
     isExpanded?: boolean;
     visible?: boolean;
     defaultSdkID?: string;
@@ -111,7 +117,7 @@ export class ConfigService {
             this.confStore = {
                 xdsServerURL: this._window.location.origin + '/api/v1',
                 xdsAgent: {
-                    URL: 'http://localhost:8000',
+                    URL: 'http://localhost:8010',
                     retry: 10,
                 },
                 xdsAgentPackages: [],
@@ -119,7 +125,7 @@ export class ConfigService {
                 projects: [],
                 localSThg: {
                     ID: null,
-                    URL: "http://localhost:8384",
+                    URL: "http://localhost:8385",
                     retry: 10,    // 10 seconds
                     tilde: "",
                 }
@@ -139,6 +145,18 @@ export class ConfigService {
             );
             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
@@ -171,16 +189,19 @@ export class ConfigService {
 
             }, error => {
                 if (error.indexOf("XDS local Agent not responding") !== -1) {
-                    let msg = "<span><strong>" + error + "<br></strong>";
-                    msg += "You may need to download and execute XDS-Agent.<br>";
-
-                    let os = this.utils.getOSName(true);
-                    let zurl = this.confStore.xdsAgentPackages && this.confStore.xdsAgentPackages.filter(elem => elem.os === os);
-                    if (zurl && zurl.length) {
-                        msg += " Download XDS-Agent tarball for " + zurl[0].os + " host OS ";
-                        msg += "<a class=\"fa fa-download\" href=\"" + zurl[0].url + "\" target=\"_blank\"></a>";
-                    }
-                    msg += "</span>";
+                    let url_OS_Linux = "https://en.opensuse.org/LinuxAutomotive#Installation_AGL_XDS";
+                    let url_OS_Other = "https://github.com/iotbzh/xds-agent#how-to-install-on-other-platform";
+                    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);
@@ -215,17 +236,8 @@ export class ConfigService {
                 this.stSvr.getProjects().subscribe(localPrj => {
                     remotePrj.forEach(rPrj => {
                         let lPrj = localPrj.filter(item => item.id === rPrj.id);
-                        if (lPrj.length > 0) {
-                            let pp: IProject = {
-                                id: rPrj.id,
-                                label: rPrj.label,
-                                pathClient: rPrj.path,
-                                pathServer: rPrj.dataPathMap.serverPath,
-                                type: rPrj.type,
-                                remotePrjDef: Object.assign({}, rPrj),
-                                localPrjDef: Object.assign({}, lPrj[0]),
-                            };
-                            this.confStore.projects.push(pp);
+                        if (lPrj.length > 0 || rPrj.type === ProjectType.NATIVE_PATHMAP) {
+                            this._addProject(rPrj, true);
                         }
                     });
                     this.confSubject.next(Object.assign({}, this.confStore));
@@ -277,7 +289,7 @@ export class ConfigService {
         return id.slice(0, 15);
     }
 
-    addProject(prj: IProject) {
+    addProject(prj: IProject): Observable<IProject> {
         // Substitute tilde with to user home path
         let pathCli = prj.pathClient.trim();
         if (pathCli.charAt(0) === '~') {
@@ -304,62 +316,106 @@ export class ConfigService {
         };
         // Send config to XDS server
         let newPrj = prj;
-        this.xdsServerSvr.addProject(xdsPrj)
-            .subscribe(resStRemotePrj => {
-                newPrj.remotePrjDef = resStRemotePrj;
-                newPrj.id = resStRemotePrj.id;
-
-                // FIXME REWORK local ST config
-                //  move logic to server side tunneling-back by WS
-                let stData = resStRemotePrj.dataCloudSync;
-
-                // Now setup local config
-                let stLocPrj: ISyncThingProject = {
-                    id: resStRemotePrj.id,
-                    label: xdsPrj.label,
-                    path: xdsPrj.path,
-                    serverSyncThingID: stData.builderSThgID
-                };
-
-                // Set local Syncthing config
-                this.stSvr.addProject(stLocPrj)
-                    .subscribe(resStLocalPrj => {
-                        newPrj.localPrjDef = resStLocalPrj;
-
-                        // FIXME: maybe reduce subject to only .project
-                        //this.confSubject.next(Object.assign({}, this.confStore).project);
-                        this.confStore.projects.push(Object.assign({}, newPrj));
-                        this.confSubject.next(Object.assign({}, this.confStore));
-                    },
-                    err => {
-                        this.alert.error("Configuration local ERROR: " + err);
-                    });
-            },
-            err => {
-                this.alert.error("Configuration remote ERROR: " + err);
+        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) {
+    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 + ")");
         }
-        this.xdsServerSvr.deleteProject(prj.id)
-            .subscribe(res => {
-                this.stSvr.deleteProject(prj.id)
-                    .subscribe(res => {
-                        this.confStore.projects.splice(idx, 1);
-                    }, err => {
-                        this.alert.error("Delete local ERROR: " + err);
-                    });
-            }, err => {
-                this.alert.error("Delete remote ERROR: " + err);
+        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));
+        }
+    }
 }