1 import { Injectable, OnInit } from '@angular/core';
2 import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http';
3 import { Location } from '@angular/common';
4 import { CookieService } from 'ngx-cookie';
5 import { Observable } from 'rxjs/Observable';
6 import { Subscriber } from 'rxjs/Subscriber';
7 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
9 // Import RxJs required methods
10 import 'rxjs/add/operator/map';
11 import 'rxjs/add/operator/catch';
12 import 'rxjs/add/observable/throw';
13 import 'rxjs/add/operator/mergeMap';
16 import { XDSServerService, IXDSFolderConfig } from "../services/xdsserver.service";
17 import { XDSAgentService } from "../services/xdsagent.service";
18 import { SyncthingService, ISyncThingProject, ISyncThingStatus } from "../services/syncthing.service";
19 import { AlertService, IAlert } from "../services/alert.service";
20 import { UtilsService } from "../services/utils.service";
22 export enum ProjectType {
27 export var ProjectTypes = [
28 { value: ProjectType.NATIVE_PATHMAP, display: "Path mapping" },
29 { value: ProjectType.SYNCTHING, display: "Cloud Sync" }
32 export interface INativeProject {
36 export interface IProject {
42 remotePrjDef?: INativeProject | ISyncThingProject;
46 defaultSdkID?: string;
49 export interface IXDSAgentConfig {
54 export interface ILocalSTConfig {
61 export interface IxdsAgentPackage {
68 export interface IConfig {
70 xdsAgent: IXDSAgentConfig;
71 xdsAgentPackages: IxdsAgentPackage[];
72 projectsRootDir: string;
74 localSThg: ILocalSTConfig;
78 export class ConfigService {
80 public conf: Observable<IConfig>;
82 private confSubject: BehaviorSubject<IConfig>;
83 private confStore: IConfig;
84 private AgentConnectObs = null;
85 private stConnectObs = null;
87 constructor(private _window: Window,
88 private cookie: CookieService,
89 private xdsServerSvr: XDSServerService,
90 private xdsAgentSvr: XDSAgentService,
91 private stSvr: SyncthingService,
92 private alert: AlertService,
93 private utils: UtilsService,
96 this.confSubject = <BehaviorSubject<IConfig>>new BehaviorSubject(this.confStore);
97 this.conf = this.confSubject.asObservable();
99 // force to load projects
105 // Try to retrieve previous config from cookie
106 let cookConf = this.cookie.getObject("xds-config");
107 if (cookConf != null) {
108 this.confStore = <IConfig>cookConf;
110 // Set default config
112 xdsServerURL: this._window.location.origin + '/api/v1',
114 URL: 'http://localhost:8000',
117 xdsAgentPackages: [],
122 URL: "http://localhost:8384",
123 retry: 10, // 10 seconds
129 // Update XDS Agent tarball url
130 this.xdsServerSvr.getXdsAgentInfo().subscribe(nfo => {
131 this.confStore.xdsAgentPackages = [];
132 nfo.tarballs && nfo.tarballs.forEach(el =>
133 this.confStore.xdsAgentPackages.push({
140 this.confSubject.next(Object.assign({}, this.confStore));
144 // Save config into cookie
146 // Notify subscribers
147 this.confSubject.next(Object.assign({}, this.confStore));
149 // Don't save projects in cookies (too big!)
150 let cfg = Object.assign({}, this.confStore);
151 delete (cfg.projects);
152 this.cookie.putObject("xds-config", cfg);
156 // Setup connection with local XDS agent
157 if (this.AgentConnectObs) {
159 this.AgentConnectObs.unsubscribe();
161 this.AgentConnectObs = null;
164 let cfg = this.confStore.xdsAgent;
165 this.AgentConnectObs = this.xdsAgentSvr.connect(cfg.retry, cfg.URL)
166 .subscribe((sts) => {
167 //console.log("Agent sts", sts);
168 // FIXME: load projects from local XDS Agent and
169 // not directly from local syncthing
170 this._loadProjectFromLocalST();
173 if (error.indexOf("XDS local Agent not responding") !== -1) {
174 let msg = "<span><strong>" + error + "<br></strong>";
175 msg += "You may need to download and execute XDS-Agent.<br>";
177 let os = this.utils.getOSName(true);
178 let zurl = this.confStore.xdsAgentPackages && this.confStore.xdsAgentPackages.filter(elem => elem.os === os);
179 if (zurl && zurl.length) {
180 msg += " Download XDS-Agent tarball for " + zurl[0].os + " host OS ";
181 msg += "<a class=\"fa fa-download\" href=\"" + zurl[0].url + "\" target=\"_blank\"></a>";
184 this.alert.error(msg);
186 this.alert.error(error);
191 private _loadProjectFromLocalST() {
192 // Remove previous subscriber if existing
193 if (this.stConnectObs) {
195 this.stConnectObs.unsubscribe();
197 this.stConnectObs = null;
200 // FIXME: move this code and all logic about syncthing inside XDS Agent
201 // Setup connection with local SyncThing
202 let retry = this.confStore.localSThg.retry;
203 let url = this.confStore.localSThg.URL;
204 this.stConnectObs = this.stSvr.connect(retry, url).subscribe((sts) => {
205 this.confStore.localSThg.ID = sts.ID;
206 this.confStore.localSThg.tilde = sts.tilde;
207 if (this.confStore.projectsRootDir === "") {
208 this.confStore.projectsRootDir = sts.tilde;
211 // Rebuild projects definition from local and remote syncthing
212 this.confStore.projects = [];
214 this.xdsServerSvr.getProjects().subscribe(remotePrj => {
215 this.stSvr.getProjects().subscribe(localPrj => {
216 remotePrj.forEach(rPrj => {
217 let lPrj = localPrj.filter(item => item.id === rPrj.id);
218 if (lPrj.length > 0) {
222 pathClient: rPrj.path,
223 pathServer: rPrj.dataPathMap.serverPath,
225 remotePrjDef: Object.assign({}, rPrj),
226 localPrjDef: Object.assign({}, lPrj[0]),
228 this.confStore.projects.push(pp);
231 this.confSubject.next(Object.assign({}, this.confStore));
232 }), error => this.alert.error('Could not load initial state of local projects.');
233 }), error => this.alert.error('Could not load initial state of remote projects.');
236 if (error.indexOf("Syncthing local daemon not responding") !== -1) {
237 let msg = "<span><strong>" + error + "<br></strong>";
238 msg += "Please check that local XDS-Agent is running.<br>";
240 this.alert.error(msg);
242 this.alert.error(error);
247 set syncToolURL(url: string) {
248 this.confStore.localSThg.URL = url;
252 set xdsAgentRetry(r: number) {
253 this.confStore.localSThg.retry = r;
254 this.confStore.xdsAgent.retry = r;
258 set xdsAgentUrl(url: string) {
259 this.confStore.xdsAgent.URL = url;
264 set projectsRootDir(p: string) {
265 if (p.charAt(0) === '~') {
266 p = this.confStore.localSThg.tilde + p.substring(1);
268 this.confStore.projectsRootDir = p;
272 getLabelRootName(): string {
273 let id = this.confStore.localSThg.ID;
274 if (!id || id === "") {
277 return id.slice(0, 15);
280 addProject(prj: IProject) {
281 // Substitute tilde with to user home path
282 let pathCli = prj.pathClient.trim();
283 if (pathCli.charAt(0) === '~') {
284 pathCli = this.confStore.localSThg.tilde + pathCli.substring(1);
286 // Must be a full path (on Linux or Windows)
287 } else if (!((pathCli.charAt(0) === '/') ||
288 (pathCli.charAt(1) === ':' && (pathCli.charAt(2) === '\\' || pathCli.charAt(2) === '/')))) {
289 pathCli = this.confStore.projectsRootDir + '/' + pathCli;
292 let xdsPrj: IXDSFolderConfig = {
294 label: prj.label || "",
297 defaultSdkID: prj.defaultSdkID,
299 serverPath: prj.pathServer,
302 syncThingID: this.confStore.localSThg.ID,
305 // Send config to XDS server
307 this.xdsServerSvr.addProject(xdsPrj)
308 .subscribe(resStRemotePrj => {
309 newPrj.remotePrjDef = resStRemotePrj;
310 newPrj.id = resStRemotePrj.id;
312 // FIXME REWORK local ST config
313 // move logic to server side tunneling-back by WS
314 let stData = resStRemotePrj.dataCloudSync;
316 // Now setup local config
317 let stLocPrj: ISyncThingProject = {
318 id: resStRemotePrj.id,
321 serverSyncThingID: stData.builderSThgID
324 // Set local Syncthing config
325 this.stSvr.addProject(stLocPrj)
326 .subscribe(resStLocalPrj => {
327 newPrj.localPrjDef = resStLocalPrj;
329 // FIXME: maybe reduce subject to only .project
330 //this.confSubject.next(Object.assign({}, this.confStore).project);
331 this.confStore.projects.push(Object.assign({}, newPrj));
332 this.confSubject.next(Object.assign({}, this.confStore));
335 this.alert.error("Configuration local ERROR: " + err);
339 this.alert.error("Configuration remote ERROR: " + err);
343 deleteProject(prj: IProject) {
344 let idx = this._getProjectIdx(prj.id);
346 throw new Error("Invalid project id (id=" + prj.id + ")");
348 this.xdsServerSvr.deleteProject(prj.id)
350 this.stSvr.deleteProject(prj.id)
352 this.confStore.projects.splice(idx, 1);
354 this.alert.error("Delete local ERROR: " + err);
357 this.alert.error("Delete remote ERROR: " + err);
361 private _getProjectIdx(id: string): number {
362 return this.confStore.projects.findIndex((item) => item.id === id);