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';
12 // Import RxJs required methods
13 import 'rxjs/add/operator/map';
14 import 'rxjs/add/operator/catch';
15 import 'rxjs/add/observable/throw';
17 export interface IXDSVersion {
24 export interface IAgentStatus {
27 WS_connected: boolean;
28 connectionRetry: number;
33 const DEFAULT_PORT = 8010;
34 const DEFAULT_API_KEY = "1234abcezam";
35 const API_VERSION = "v1";
38 export class XDSAgentService {
39 public Status$: Observable<IAgentStatus>;
41 private baseRestUrl: string;
42 private wsUrl: string;
43 private connectionMaxRetry: number;
44 private apikey: string;
45 private _status: IAgentStatus = {
52 private statusSubject = <BehaviorSubject<IAgentStatus>>new BehaviorSubject(this._status);
55 private socket: SocketIOClient.Socket;
57 constructor(private http: Http, private _window: Window, private alert: AlertService) {
59 this.Status$ = this.statusSubject.asObservable();
61 this.apikey = DEFAULT_API_KEY; // FIXME Add dynamic allocated key
62 this._status.baseURL = 'http://localhost:' + DEFAULT_PORT;
63 this.baseRestUrl = this._status.baseURL + '/api/' + API_VERSION;
64 let re = this._window.location.origin.match(/http[s]?:\/\/([^\/]*)[\/]?/);
65 if (re === null || re.length < 2) {
66 console.error('ERROR: cannot determine Websocket url');
68 this.wsUrl = 'ws://' + re[1];
72 connect(retry: number, url?: string): Observable<IAgentStatus> {
74 this._status.baseURL = url;
75 this.baseRestUrl = this._status.baseURL + '/api/' + API_VERSION;
77 //FIXME [XDS-Agent]: not implemented yet, set always as connected
78 //this._status.connected = false;
79 this._status.connected = true;
80 this._status.connectionRetry = 0;
81 this.connectionMaxRetry = retry || 3600; // 1 hour
83 // Init IO Socket connection
84 this._handleIoSocket();
86 // Get Version in order to check connection via a REST request
87 return this.getVersion()
89 this._status.version = v.version;
90 this.statusSubject.next(Object.assign({}, this._status));
95 public getVersion(): Observable<IXDSVersion> {
96 /*FIXME [XDS-Agent]: Not implemented for now
97 return this._get('/version');
99 return Observable.of({
100 version: "NOT_IMPLEMENTED",
101 apiVersion: "NOT_IMPLEMENTED",
102 gitTag: "NOT_IMPLEMENTED"
106 private _WSState(sts: boolean) {
107 this._status.WS_connected = sts;
108 this.statusSubject.next(Object.assign({}, this._status));
111 private _handleIoSocket() {
112 this.socket = io(this.wsUrl, { transports: ['websocket'] });
114 this.socket.on('connect_error', (res) => {
115 this._WSState(false);
116 console.error('WS Connect_error ', res);
119 this.socket.on('connect', (res) => {
123 this.socket.on('disconnection', (res) => {
124 this._WSState(false);
125 this.alert.error('WS disconnection: ' + res);
128 this.socket.on('error', (err) => {
129 console.error('WS error:', err);
134 private _attachAuthHeaders(options?: any) {
135 options = options || {};
136 let headers = options.headers || new Headers();
137 // headers.append('Authorization', 'Basic ' + btoa('username:password'));
138 headers.append('Access-Control-Allow-Origin', '*');
139 headers.append('Accept', 'application/json');
140 headers.append('Content-Type', 'application/json');
141 if (this.apikey !== "") {
142 headers.append('X-API-Key', this.apikey);
146 options.headers = headers;
150 private _checkAlive(): Observable<boolean> {
151 if (this._status.connected) {
152 return Observable.of(true);
155 return this.http.get(this._status.baseURL, this._attachAuthHeaders())
156 .map((r) => this._status.connected = true)
157 .retryWhen((attempts) => {
158 this._status.connectionRetry = 0;
159 return attempts.flatMap(error => {
160 this._status.connected = false;
161 if (++this._status.connectionRetry >= this.connectionMaxRetry) {
162 return Observable.throw("XDS local Agent not responding (url=" + this._status.baseURL + ")");
164 return Observable.timer(1000);
170 private _get(url: string): Observable<any> {
171 return this._checkAlive()
172 .flatMap(() => this.http.get(this.baseRestUrl + url, this._attachAuthHeaders()))
173 .map((res: Response) => res.json())
174 .catch(this._decodeError);
176 private _post(url: string, body: any): Observable<any> {
177 return this._checkAlive()
178 .flatMap(() => this.http.post(this.baseRestUrl + url, JSON.stringify(body), this._attachAuthHeaders()))
179 .map((res: Response) => res.json())
181 return this._decodeError(error);
184 private _delete(url: string): Observable<any> {
185 return this._checkAlive()
186 .flatMap(() => this.http.delete(this.baseRestUrl + url, this._attachAuthHeaders()))
187 .map((res: Response) => res.json())
188 .catch(this._decodeError);
191 private _decodeError(err: Response | any) {
194 this._status.connected = false;
196 if (typeof err === "object") {
197 if (err.statusText) {
199 } else if (err.error) {
200 e = String(err.error);
202 e = JSON.stringify(err);
204 } else if (err instanceof Response) {
205 const body = err.json() || 'Server error';
206 const error = body.error || JSON.stringify(body);
207 e = `${err.status} - ${err.statusText || ''} ${error}`;
209 e = err.message ? err.message : err.toString();
211 return Observable.throw(e);