/**
* @license
-* Copyright (C) 2017 "IoT.bzh"
+* Copyright (C) 2017-2018 "IoT.bzh"
* Author Sebastien Douheret <sebastien@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
import * as io from 'socket.io-client';
import { AlertService } from './alert.service';
-import { ISdk } from './sdk.service';
+import { ISdk, ISdkManagementMsg } from './sdk.service';
import { ProjectType, ProjectTypeEnum } from './project.service';
+import { TargetType, TargetTypeEnum } from './target.service';
// Import RxJs required methods
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/observable/of';
-import 'rxjs/add/operator/retryWhen';
+import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
export interface IXDSConfigProject {
clientData?: string;
}
+/** Targets **/
+export interface IXDSTargetConfig {
+ id?: string;
+ name: string;
+ type: TargetTypeEnum;
+ ip: string;
+ status?: string;
+ terms?: IXDSTargetTerminal[];
+}
+
+export interface IXDSTargetTerminal {
+ id?: string;
+ type: string;
+ name: string;
+ status?: string;
+ cols?: number;
+ rows?: number;
+}
+
export interface IXDSVer {
id: string;
version: string;
@Injectable()
export class XDSAgentService {
+ public Socket: SocketIOClient.Socket;
public XdsConfig$: Observable<IXDSConfig>;
public Status$: Observable<IAgentStatus>;
public CmdOutput$ = <Subject<ICmdOutput>>new Subject();
public CmdExit$ = <Subject<ICmdExit>>new Subject();
+ protected sockConnect$ = new Subject<SocketIOClient.Socket>();
+ protected sockDisconnect$ = new Subject<SocketIOClient.Socket>();
+
protected projectAdd$ = new Subject<IXDSProjectConfig>();
protected projectDel$ = new Subject<IXDSProjectConfig>();
protected projectChange$ = new Subject<IXDSProjectConfig>();
+ protected sdkAdd$ = new Subject<ISdk>();
+ protected sdkRemove$ = new Subject<ISdk>();
+ protected sdkChange$ = new Subject<ISdk>();
+ protected sdkManagement$ = new Subject<ISdkManagementMsg>();
+
+ protected targetAdd$ = new Subject<IXDSTargetConfig>();
+ protected targetDel$ = new Subject<IXDSTargetConfig>();
+ protected targetChange$ = new Subject<IXDSTargetConfig>();
+
+ protected targetTerminalAdd$ = new Subject<IXDSTargetTerminal>();
+ protected targetTerminalDel$ = new Subject<IXDSTargetTerminal>();
+ protected targetTerminalChange$ = new Subject<IXDSTargetTerminal>();
+
+ private _socket: SocketIOClient.Socket;
private baseUrl: string;
private wsUrl: string;
private httpSessionID: string;
private configSubject = <BehaviorSubject<IXDSConfig>>new BehaviorSubject(this._config);
private statusSubject = <BehaviorSubject<IAgentStatus>>new BehaviorSubject(this._status);
- private socket: SocketIOClient.Socket;
- constructor( @Inject(DOCUMENT) private document: Document,
+
+ constructor(@Inject(DOCUMENT) private document: Document,
private http: HttpClient, private alert: AlertService) {
this.XdsConfig$ = this.configSubject.asObservable();
// Retrieve Session ID / token
this.http.get(this.baseUrl + '/version', { observe: 'response' })
.subscribe(
- resp => {
- this.httpSessionID = resp.headers.get('xds-agent-sid');
-
- const re = originUrl.match(/http[s]?:\/\/([^\/]*)[\/]?/);
- if (re === null || re.length < 2) {
- console.error('ERROR: cannot determine Websocket url');
- } else {
- this.wsUrl = 'ws://' + re[1];
- this._handleIoSocket();
- this._RegisterEvents();
- }
- },
- err => {
- /* tslint:disable:no-console */
- console.error('ERROR while retrieving session id:', err);
- });
+ resp => {
+ this.httpSessionID = resp.headers.get('xds-agent-sid');
+
+ const re = originUrl.match(/http[s]?:\/\/([^\/]*)[\/]?/);
+ if (re === null || re.length < 2) {
+ console.error('ERROR: cannot determine Websocket url');
+ } else {
+ this.wsUrl = 'ws://' + re[1];
+ this._handleIoSocket();
+ this._RegisterEvents();
+ }
+ },
+ err => {
+ /* tslint:disable:no-console */
+ console.error('ERROR while retrieving session id:', err);
+ });
}
private _NotifyXdsAgentState(sts: boolean) {
}
private _handleIoSocket() {
- this.socket = io(this.wsUrl, { transports: ['websocket'] });
+ this.Socket = this._socket = io(this.wsUrl, { transports: ['websocket'] });
- this.socket.on('connect_error', (res) => {
+ this._socket.on('connect_error', (res) => {
this._NotifyXdsAgentState(false);
console.error('XDS Agent WebSocket Connection error !');
});
- this.socket.on('connect', (res) => {
+ this._socket.on('connect', (res) => {
this._NotifyXdsAgentState(true);
+ this.sockConnect$.next(this._socket);
});
- this.socket.on('disconnection', (res) => {
+ this._socket.on('disconnection', (res) => {
this._NotifyXdsAgentState(false);
this.alert.error('WS disconnection: ' + res);
+ this.sockDisconnect$.next(this._socket);
});
- this.socket.on('error', (err) => {
+ this._socket.on('error', (err) => {
console.error('WS error:', err);
});
// XDS Events decoding
- this.socket.on('make:output', data => {
+ this._socket.on('exec:output', data => {
this.CmdOutput$.next(Object.assign({}, <ICmdOutput>data));
});
- this.socket.on('make:exit', data => {
+ this._socket.on('exec:exit', data => {
this.CmdExit$.next(Object.assign({}, <ICmdExit>data));
});
- this.socket.on('exec:output', data => {
- this.CmdOutput$.next(Object.assign({}, <ICmdOutput>data));
- });
-
- this.socket.on('exec:exit', data => {
- this.CmdExit$.next(Object.assign({}, <ICmdExit>data));
- });
-
- this.socket.on('event:server-config', ev => {
+ this._socket.on('event:server-config', ev => {
if (ev && ev.data) {
const cfg: IXDServerCfg = ev.data;
const idx = this._config.servers.findIndex(el => el.id === cfg.id);
}
});
- this.socket.on('event:project-add', (ev) => {
+ /*** Project events ****/
+
+ this._socket.on('event:project-add', (ev) => {
if (ev && ev.data && ev.data.id) {
this.projectAdd$.next(Object.assign({}, ev.data));
- if (ev.sessionID !== this.httpSessionID && ev.data.label) {
+ if (ev.sessionID !== '' && ev.sessionID !== this.httpSessionID && ev.data.label) {
this.alert.info('Project "' + ev.data.label + '" has been added by another tool.');
}
} else if (isDevMode) {
}
});
- this.socket.on('event:project-delete', (ev) => {
+ this._socket.on('event:project-delete', (ev) => {
if (ev && ev.data && ev.data.id) {
this.projectDel$.next(Object.assign({}, ev.data));
- if (ev.sessionID !== this.httpSessionID && ev.data.label) {
+ if (ev.sessionID !== '' && ev.sessionID !== this.httpSessionID && ev.data.label) {
this.alert.info('Project "' + ev.data.label + '" has been deleted by another tool.');
}
} else if (isDevMode) {
}
});
- this.socket.on('event:project-state-change', ev => {
+ this._socket.on('event:project-state-change', ev => {
if (ev && ev.data) {
this.projectChange$.next(Object.assign({}, ev.data));
} else if (isDevMode) {
}
});
+ /*** SDK Events ***/
+
+ this._socket.on('event:sdk-add', (ev) => {
+ if (ev && ev.data && ev.data.id) {
+ const evt = <ISdk>ev.data;
+ this.sdkAdd$.next(Object.assign({}, evt));
+
+ if (ev.sessionID !== '' && ev.sessionID !== this.httpSessionID && evt.name) {
+ this.alert.info('SDK "' + evt.name + '" has been added by another tool.');
+ }
+ } else if (isDevMode) {
+ console.log('Warning: received event:sdk-add with unknown data: ev=', ev);
+ }
+ });
+
+ this._socket.on('event:sdk-remove', (ev) => {
+ if (ev && ev.data && ev.data.id) {
+ const evt = <ISdk>ev.data;
+ this.sdkRemove$.next(Object.assign({}, evt));
+
+ if (ev.sessionID !== '' && ev.sessionID !== this.httpSessionID && evt.name) {
+ this.alert.info('SDK "' + evt.name + '" has been removed by another tool.');
+ }
+ } else if (isDevMode) {
+ console.log('Warning: received event:sdk-remove with unknown data: ev=', ev);
+ }
+ });
+
+ this._socket.on('event:sdk-state-change', (ev) => {
+ if (ev && ev.data && ev.data.id) {
+ const evt = <ISdk>ev.data;
+ this.sdkChange$.next(Object.assign({}, evt));
+
+ } else if (isDevMode) {
+ console.log('Warning: received event:sdk-state-change with unknown data: ev=', ev);
+ }
+ });
+
+ this._socket.on('event:sdk-management', (ev) => {
+ if (ev && ev.data && ev.data.sdk) {
+ const evt = <ISdkManagementMsg>ev.data;
+ this.sdkManagement$.next(Object.assign({}, evt));
+
+ if (ev.sessionID !== '' && ev.sessionID !== this.httpSessionID && evt.sdk.name) {
+ this.alert.info('SDK "' + evt.sdk.name + '" has been installed by another tool.');
+ }
+ } else if (isDevMode) {
+ /* tslint:disable:no-console */
+ console.log('Warning: received event:sdk-install with unknown data: ev=', ev);
+ }
+ });
+
+ /*** Target events ****/
+
+ this._socket.on('event:target-add', (ev) => {
+ if (ev && ev.data && ev.data.id) {
+ this.targetAdd$.next(Object.assign({}, ev.data));
+ if (ev.sessionID !== '' && ev.sessionID !== this.httpSessionID && ev.data.label) {
+ this.alert.info('Target "' + ev.data.label + '" has been added by another tool.');
+ }
+ } else if (isDevMode) {
+ /* tslint:disable:no-console */
+ console.log('Warning: received event:target-add with unknown data: ev=', ev);
+ }
+ });
+
+ this._socket.on('event:target-remove', (ev) => {
+ if (ev && ev.data && ev.data.id) {
+ this.targetDel$.next(Object.assign({}, ev.data));
+ if (ev.sessionID !== '' && ev.sessionID !== this.httpSessionID && ev.data.label) {
+ this.alert.info('Target "' + ev.data.label + '" has been deleted by another tool.');
+ }
+ } else if (isDevMode) {
+ console.log('Warning: received event:target-remove with unknown data: ev=', ev);
+ }
+ });
+
+ this._socket.on('event:target-state-change', ev => {
+ if (ev && ev.data) {
+ this.targetChange$.next(Object.assign({}, ev.data));
+ } else if (isDevMode) {
+ console.log('Warning: received event:target-state-change with unknown data: ev=', ev);
+ }
+ });
+
+ /*** Target Terminal events ****/
+
+ this._socket.on('event:target-terminal-add', (ev) => {
+ if (ev && ev.data && ev.data.id) {
+ this.targetTerminalAdd$.next(Object.assign({}, ev.data));
+ if (ev.sessionID !== '' && ev.sessionID !== this.httpSessionID && ev.data.label) {
+ this.alert.info('Target terminal "' + ev.data.label + '" has been added by another tool.');
+ }
+ } else if (isDevMode) {
+ /* tslint:disable:no-console */
+ console.log('Warning: received event:target-terminal-add with unknown data: ev=', ev);
+ }
+ });
+
+ this._socket.on('event:target-terminal-delete', (ev) => {
+ if (ev && ev.data && ev.data.id) {
+ this.targetTerminalDel$.next(Object.assign({}, ev.data));
+ if (ev.sessionID !== '' && ev.sessionID !== this.httpSessionID && ev.data.label) {
+ this.alert.info('Target terminal "' + ev.data.label + '" has been deleted by another tool.');
+ }
+ } else if (isDevMode) {
+ console.log('Warning: received event:target-terminal-delete with unknown data: ev=', ev);
+ }
+ });
+
+ this._socket.on('event:target-terminal-state-change', ev => {
+ if (ev && ev.data) {
+ this.targetTerminalChange$.next(Object.assign({}, ev.data));
+ } else if (isDevMode) {
+ console.log('Warning: received event:target-terminal-state-change with unknown data: ev=', ev);
+ }
+ });
+
}
/**
** Events registration
***/
+
+ onSocketConnect(): Observable<any> {
+ return this.sockConnect$.asObservable();
+ }
+
+ onSocketDisconnect(): Observable<any> {
+ return this.sockDisconnect$.asObservable();
+ }
+
onProjectAdd(): Observable<IXDSProjectConfig> {
return this.projectAdd$.asObservable();
}
return this.projectChange$.asObservable();
}
+ onSdkAdd(): Observable<ISdk> {
+ return this.sdkAdd$.asObservable();
+ }
+
+ onSdkRemove(): Observable<ISdk> {
+ return this.sdkRemove$.asObservable();
+ }
+
+ onSdkChange(): Observable<ISdk> {
+ return this.sdkChange$.asObservable();
+ }
+
+ onSdkManagement(): Observable<ISdkManagementMsg> {
+ return this.sdkManagement$.asObservable();
+ }
+
+ onTargetAdd(): Observable<IXDSTargetConfig> {
+ return this.targetAdd$.asObservable();
+ }
+
+ onTargetDelete(): Observable<IXDSTargetConfig> {
+ return this.targetDel$.asObservable();
+ }
+
+ onTargetChange(): Observable<IXDSTargetConfig> {
+ return this.targetChange$.asObservable();
+ }
+
+ onTargetTerminalAdd(): Observable<IXDSTargetTerminal> {
+ return this.targetTerminalAdd$.asObservable();
+ }
+
+ onTargetTerminalDelete(): Observable<IXDSTargetTerminal> {
+ return this.targetTerminalDel$.asObservable();
+ }
+
+ onTargetTerminalChange(): Observable<IXDSTargetTerminal> {
+ return this.targetTerminalChange$.asObservable();
+ }
+
/**
** Misc / Version
***/
if (!svr || !svr.connected) {
return Observable.of([]);
}
-
return this._get(svr.partialUrl + '/sdks');
}
+ installSdk(serverID: string, id: string, filename?: string, force?: boolean): Observable<ISdk> {
+ return this._post(this._getServerUrl(serverID) + '/sdks', { id: id, filename: filename, force: force });
+ }
+
+ abortInstall(serverID: string, id: string): Observable<ISdk> {
+ return this._post(this._getServerUrl(serverID) + '/sdks/abortinstall', { id: id });
+ }
+
+ removeSdk(serverID: string, id: string): Observable<ISdk> {
+ return this._delete(this._getServerUrl(serverID) + '/sdks/' + id);
+ }
+
+
/***
** Projects
***/
});
}
+
+ /***
+ ** Targets
+ ***/
+ getTargets(serverID: string): Observable<IXDSTargetConfig[]> {
+ return this._get(this._getServerUrl(serverID) + '/targets');
+ }
+
+ addTarget(serverID: string, cfg: IXDSTargetConfig): Observable<IXDSTargetConfig> {
+ return this._post(this._getServerUrl(serverID) + '/targets', cfg);
+ }
+
+ deleteTarget(serverID: string, id: string): Observable<IXDSTargetConfig> {
+ return this._delete(this._getServerUrl(serverID) + '/targets/' + id);
+ }
+
+ updateTarget(serverID: string, cfg: IXDSTargetConfig): Observable<IXDSTargetConfig> {
+ return this._put(this._getServerUrl(serverID) + '/targets/' + cfg.id, cfg);
+ }
+
+ /***
+ ** Terminals
+ ***/
+ getTerminalsTarget(serverID, targetID: string): Observable<IXDSTargetTerminal[]> {
+ return this._get(this._getServerUrl(serverID) + '/targets/' + targetID + '/terminals');
+ }
+
+ getTerminalTarget(serverID, targetID, termID: string): Observable<IXDSTargetTerminal> {
+ return this._get(this._getServerUrl(serverID) + '/targets/' + targetID + '/terminals/' + termID);
+ }
+
+ createTerminalTarget(serverID, targetID: string, cfg: IXDSTargetTerminal): Observable<IXDSTargetTerminal> {
+ return this._post(this._getServerUrl(serverID) + '/targets/' + targetID + '/terminals', cfg);
+ }
+
+ updateTerminalTarget(serverID, targetID: string, cfg: IXDSTargetTerminal): Observable<IXDSTargetTerminal> {
+ if (cfg && (cfg.id !== '' || cfg.id !== undefined)) {
+ return this._put(this._getServerUrl(serverID) + '/targets/' + targetID + '/terminals/' + cfg.id, cfg);
+ }
+ return Observable.throw('Undefined terminal id');
+ }
+
+ openTerminalTarget(serverID, targetID, termID: string): Observable<IXDSTargetTerminal> {
+ return this._post(this._getServerUrl(serverID) + '/targets/' + targetID + '/terminals/' + termID + '/open', {});
+ }
+
+ closeTerminalTarget(serverID, targetID, termID: string): Observable<IXDSTargetTerminal> {
+ return this._post(this._getServerUrl(serverID) + '/targets/' + targetID + '/terminals/' + termID + '/close', {});
+ }
+
+ resizeTerminalTarget(serverID, targetID, termID: string, cols, rows: number): Observable<IXDSTargetTerminal> {
+ return this._post(this._getServerUrl(serverID) + '/targets/' + targetID + '/terminals/' + termID + '/resize',
+ { cols: cols, rows: rows });
+ }
+
/**
** Private functions
***/
// Register to all existing events
this._post('/events/register', { 'name': 'event:all' })
.subscribe(
- res => { },
- error => {
- this.alert.error('ERROR while registering to all events: ' + error);
- },
+ res => { },
+ error => {
+ this.alert.error('ERROR while registering to all events: ' + error);
+ },
);
}
return svr[0];
}
+ private _getServerUrl(serverID: string): string | ErrorObservable {
+ const svr = this._getServer(serverID);
+ if (!svr || !svr.connected) {
+ if (isDevMode) {
+ console.log('ERROR: XDS Server unknown: serverID=' + serverID);
+ }
+ return Observable.throw('Cannot identify XDS Server');
+ }
+ return svr.partialUrl;
+ }
+
private _attachAuthHeaders(options?: any) {
options = options || {};
const headers = options.headers || new HttpHeaders();