1 import { Injectable } from '@angular/core';
2 import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http';
3 import { Location } from '@angular/common';
4 import { Observable } from 'rxjs/Observable';
5 import { Subject } from 'rxjs/Subject';
6 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
7 import * as io from 'socket.io-client';
9 import { AlertService } from './alert.service';
10 import { ISdk } from './sdk.service';
13 // Import RxJs required methods
14 import 'rxjs/add/operator/map';
15 import 'rxjs/add/operator/catch';
16 import 'rxjs/add/observable/throw';
17 import 'rxjs/add/operator/mergeMap';
20 export interface IXDSConfigProject {
23 clientSyncThingID: string;
26 defaultSdkID?: string;
29 interface IXDSBuilderConfig {
35 export interface IXDSFolderConfig {
44 // FIXME better with union but tech pb with go code
45 //data?: IXDSPathMapConfig|IXDSCloudSyncConfig;
46 dataPathMap?: IXDSPathMapConfig;
47 dataCloudSync?: IXDSCloudSyncConfig;
50 export interface IXDSPathMapConfig {
55 export interface IXDSCloudSyncConfig {
57 builderSThgID?: string;
60 interface IXDSConfig {
62 builder: IXDSBuilderConfig;
63 folders: IXDSFolderConfig[];
66 export interface IXDSAgentTarball {
74 export interface IXDSAgentInfo {
75 tarballs: IXDSAgentTarball[];
78 export interface ISdkMessage {
84 export interface ICmdOutput {
91 export interface ICmdExit {
98 export interface IServerStatus {
99 WS_connected: boolean;
103 const FOLDER_TYPE_CLOUDSYNC = 2;
106 export class XDSServerService {
108 public CmdOutput$ = <Subject<ICmdOutput>>new Subject();
109 public CmdExit$ = <Subject<ICmdExit>>new Subject();
110 public FolderStateChange$ = <Subject<IXDSFolderConfig>>new Subject();
111 public Status$: Observable<IServerStatus>;
114 private baseUrl: string;
115 private wsUrl: string;
116 private _status = { WS_connected: false };
117 private statusSubject = <BehaviorSubject<IServerStatus>>new BehaviorSubject(this._status);
120 private socket: SocketIOClient.Socket;
122 constructor(private http: Http, private _window: Window, private alert: AlertService) {
124 this.Status$ = this.statusSubject.asObservable();
126 this.baseUrl = this._window.location.origin + '/api/v1';
127 let re = this._window.location.origin.match(/http[s]?:\/\/([^\/]*)[\/]?/);
128 if (re === null || re.length < 2) {
129 console.error('ERROR: cannot determine Websocket url');
131 this.wsUrl = 'ws://' + re[1];
132 this._handleIoSocket();
133 this._RegisterEvents();
137 private _WSState(sts: boolean) {
138 this._status.WS_connected = sts;
139 this.statusSubject.next(Object.assign({}, this._status));
142 private _handleIoSocket() {
143 this.socket = io(this.wsUrl, { transports: ['websocket'] });
145 this.socket.on('connect_error', (res) => {
146 this._WSState(false);
147 console.error('WS Connect_error ', res);
150 this.socket.on('connect', (res) => {
154 this.socket.on('disconnection', (res) => {
155 this._WSState(false);
156 this.alert.error('WS disconnection: ' + res);
159 this.socket.on('error', (err) => {
160 console.error('WS error:', err);
163 this.socket.on('make:output', data => {
164 this.CmdOutput$.next(Object.assign({}, <ICmdOutput>data));
167 this.socket.on('make:exit', data => {
168 this.CmdExit$.next(Object.assign({}, <ICmdExit>data));
171 this.socket.on('exec:output', data => {
172 this.CmdOutput$.next(Object.assign({}, <ICmdOutput>data));
175 this.socket.on('exec:exit', data => {
176 this.CmdExit$.next(Object.assign({}, <ICmdExit>data));
179 this.socket.on('event:FolderStateChanged', ev => {
180 if (ev && ev.folder) {
181 this.FolderStateChange$.next(Object.assign({}, ev.folder));
186 private _RegisterEvents() {
187 let ev = "FolderStateChanged";
188 this._post('/events/register', { "name": ev })
192 this.alert.error("ERROR while registering events " + ev + ": ", error);
197 getSdks(): Observable<ISdk[]> {
198 return this._get('/sdks');
201 getXdsAgentInfo(): Observable<IXDSAgentInfo> {
202 return this._get('/xdsagent/info');
205 getProjects(): Observable<IXDSFolderConfig[]> {
206 return this._get('/folders');
209 addProject(cfg: IXDSFolderConfig): Observable<IXDSFolderConfig> {
210 return this._post('/folder', cfg);
213 deleteProject(id: string): Observable<IXDSFolderConfig> {
214 return this._delete('/folder/' + id);
217 syncProject(id: string): Observable<string> {
218 return this._post('/folder/sync/' + id, {});
221 exec(prjID: string, dir: string, cmd: string, sdkid?: string, args?: string[], env?: string[]): Observable<any> {
222 return this._post('/exec',
233 make(prjID: string, dir: string, sdkid?: string, args?: string[], env?: string[]): Observable<any> {
234 return this._post('/make',
245 private _attachAuthHeaders(options?: any) {
246 options = options || {};
247 let headers = options.headers || new Headers();
248 // headers.append('Authorization', 'Basic ' + btoa('username:password'));
249 headers.append('Accept', 'application/json');
250 headers.append('Content-Type', 'application/json');
251 // headers.append('Access-Control-Allow-Origin', '*');
253 options.headers = headers;
257 private _get(url: string): Observable<any> {
258 return this.http.get(this.baseUrl + url, this._attachAuthHeaders())
259 .map((res: Response) => res.json())
260 .catch(this._decodeError);
262 private _post(url: string, body: any): Observable<any> {
263 return this.http.post(this.baseUrl + url, JSON.stringify(body), this._attachAuthHeaders())
264 .map((res: Response) => res.json())
266 return this._decodeError(error);
269 private _delete(url: string): Observable<any> {
270 return this.http.delete(this.baseUrl + url, this._attachAuthHeaders())
271 .map((res: Response) => res.json())
272 .catch(this._decodeError);
275 private _decodeError(err: any) {
277 if (err instanceof Response) {
278 const body = err.json() || 'Server error';
279 e = body.error || JSON.stringify(body);
280 if (!e || e === "") {
281 e = `${err.status} - ${err.statusText || 'Unknown error'}`;
283 } else if (typeof err === "object") {
284 if (err.statusText) {
286 } else if (err.error) {
287 e = String(err.error);
289 e = JSON.stringify(err);
292 e = err.message ? err.message : err.toString();
294 return Observable.throw(e);