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';
11 // Import RxJs required methods
12 import 'rxjs/add/operator/map';
13 import 'rxjs/add/operator/catch';
14 import 'rxjs/add/observable/throw';
15 import 'rxjs/add/operator/mergeMap';
18 export interface IXDSConfigProject {
21 hostSyncThingID: string;
25 interface IXDSBuilderConfig {
31 interface IXDSFolderConfig {
37 builderSThgID?: string;
41 interface IXDSConfig {
43 builder: IXDSBuilderConfig;
44 folders: IXDSFolderConfig[];
47 export interface ISdkMessage {
53 export interface ICmdOutput {
60 export interface ICmdExit {
67 export interface IServerStatus {
68 WS_connected: boolean;
72 const FOLDER_TYPE_CLOUDSYNC = 2;
75 export class XDSServerService {
77 public CmdOutput$ = <Subject<ICmdOutput>>new Subject();
78 public CmdExit$ = <Subject<ICmdExit>>new Subject();
79 public Status$: Observable<IServerStatus>;
81 private baseUrl: string;
82 private wsUrl: string;
83 private _status = { WS_connected: false };
84 private statusSubject = <BehaviorSubject<IServerStatus>>new BehaviorSubject(this._status);
87 private socket: SocketIOClient.Socket;
89 constructor(private http: Http, private _window: Window, private alert: AlertService) {
91 this.Status$ = this.statusSubject.asObservable();
93 this.baseUrl = this._window.location.origin + '/api/v1';
94 let re = this._window.location.origin.match(/http[s]?:\/\/([^\/]*)[\/]?/);
95 if (re === null || re.length < 2) {
96 console.error('ERROR: cannot determine Websocket url');
98 this.wsUrl = 'ws://' + re[1];
99 this._handleIoSocket();
103 private _WSState(sts: boolean) {
104 this._status.WS_connected = sts;
105 this.statusSubject.next(Object.assign({}, this._status));
108 private _handleIoSocket() {
109 this.socket = io(this.wsUrl, { transports: ['websocket'] });
111 this.socket.on('connect_error', (res) => {
112 this._WSState(false);
113 console.error('WS Connect_error ', res);
116 this.socket.on('connect', (res) => {
120 this.socket.on('disconnection', (res) => {
121 this._WSState(false);
122 this.alert.error('WS disconnection: ' + res);
125 this.socket.on('error', (err) => {
126 console.error('WS error:', err);
129 this.socket.on('make:output', data => {
130 this.CmdOutput$.next(Object.assign({}, <ICmdOutput>data));
133 this.socket.on('make:exit', data => {
134 this.CmdExit$.next(Object.assign({}, <ICmdExit>data));
139 getProjects(): Observable<IXDSFolderConfig[]> {
140 return this._get('/folders');
143 addProject(cfg: IXDSConfigProject): Observable<IXDSFolderConfig> {
144 let folder: IXDSFolderConfig = {
146 label: cfg.label || "",
148 type: FOLDER_TYPE_CLOUDSYNC,
149 syncThingID: cfg.hostSyncThingID
151 return this._post('/folder', folder);
154 deleteProject(id: string): Observable<IXDSFolderConfig> {
155 return this._delete('/folder/' + id);
158 exec(cmd: string, args?: string[], options?: any): Observable<any> {
159 return this._post('/exec',
166 make(prjID: string, dir: string, args: string): Observable<any> {
167 return this._post('/make', { id: prjID, rpath: dir, args: args });
171 private _attachAuthHeaders(options?: any) {
172 options = options || {};
173 let headers = options.headers || new Headers();
174 // headers.append('Authorization', 'Basic ' + btoa('username:password'));
175 headers.append('Accept', 'application/json');
176 headers.append('Content-Type', 'application/json');
177 // headers.append('Access-Control-Allow-Origin', '*');
179 options.headers = headers;
183 private _get(url: string): Observable<any> {
184 return this.http.get(this.baseUrl + url, this._attachAuthHeaders())
185 .map((res: Response) => res.json())
186 .catch(this._decodeError);
188 private _post(url: string, body: any): Observable<any> {
189 return this.http.post(this.baseUrl + url, JSON.stringify(body), this._attachAuthHeaders())
190 .map((res: Response) => res.json())
192 return this._decodeError(error);
195 private _delete(url: string): Observable<any> {
196 return this.http.delete(this.baseUrl + url, this._attachAuthHeaders())
197 .map((res: Response) => res.json())
198 .catch(this._decodeError);
201 private _decodeError(err: any) {
203 if (typeof err === "object") {
204 if (err.statusText) {
206 } else if (err.error) {
207 e = String(err.error);
209 e = JSON.stringify(err);
212 e = err.json().error || 'Server error';
214 return Observable.throw(e);