blob: 372821c8f3e9d2908d72324196a75faae3611fc2 [file] [log] [blame]
Matteo Scandolofb46ae62017-08-08 09:10:50 -07001
2/*
3 * Copyright 2017-present Open Networking Foundation
4
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8
9 * http://www.apache.org/licenses/LICENSE-2.0
10
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
Matteo Scandolo035c5932016-12-14 09:55:15 -080019import * as io from 'socket.io-client';
Matteo Scandolo98b5f5d2017-03-17 17:09:05 -070020import * as _ from 'lodash';
Matteo Scandolo035c5932016-12-14 09:55:15 -080021import {Subject, Observable} from 'rxjs/Rx';
Matteo Scandolo828d1e82017-01-17 14:49:38 -080022import {IXosAppConfig} from '../../../index';
Matteo Scandolo035c5932016-12-14 09:55:15 -080023
24export interface IWSEvent {
25 model: string;
Matteo Scandolo31daa802017-09-01 12:19:56 -070026 skip_notification?: boolean;
Matteo Scandoloe9cdf9a2017-11-21 10:41:28 -080027 deleted?: boolean;
Matteo Scandolo035c5932016-12-14 09:55:15 -080028 msg: {
29 changed_fields: string[],
30 object?: any,
31 pk?: number
32 };
33}
34
35export interface IWSEventService {
36 list(): Observable<IWSEvent>;
37}
38
Matteo Scandolo06542252018-01-30 13:35:55 -080039export class WebSocketEvent implements IWSEventService {
Matteo Scandolo828d1e82017-01-17 14:49:38 -080040
Matteo Scandolo98b5f5d2017-03-17 17:09:05 -070041 static $inject = [
42 'AppConfig',
Matteo Scandolo06542252018-01-30 13:35:55 -080043 'SocketIo',
Matteo Scandolo98b5f5d2017-03-17 17:09:05 -070044 '$log'
45 ];
Matteo Scandolo828d1e82017-01-17 14:49:38 -080046
Matteo Scandoloe015fa92017-05-10 09:52:36 -070047
Matteo Scandolo035c5932016-12-14 09:55:15 -080048 private _events: Subject<IWSEvent> = new Subject<IWSEvent>();
Matteo Scandoloe015fa92017-05-10 09:52:36 -070049 private socket;
50 constructor(
51 private AppConfig: IXosAppConfig,
Matteo Scandolo06542252018-01-30 13:35:55 -080052 private SocketIo: any,
Matteo Scandoloe015fa92017-05-10 09:52:36 -070053 private $log: ng.ILogService
54 ) {
55 // NOTE list of field that are not useful to the UI
Matteo Scandolo06542252018-01-30 13:35:55 -080056 const ignoredFields: string[] = ['created', 'updated', 'backend_register', 'backend_status', 'policy_status'];
Matteo Scandolo98b5f5d2017-03-17 17:09:05 -070057
Matteo Scandolo06542252018-01-30 13:35:55 -080058 this.socket = this.SocketIo.socket;
Matteo Scandoloe9cdf9a2017-11-21 10:41:28 -080059
60 this.socket.on('remove', (data: IWSEvent): void => {
61 this.$log.info(`[WebSocket] Received Remove Event for: ${data.model} [${data.msg.pk}]`, data);
Matteo Scandolo06542252018-01-30 13:35:55 -080062
63 if (data.model.indexOf('_decl') > -1) {
64 // the GUI doesn't know about _decl models,
65 // send the event for the actual model
66 data.model = data.model.replace('_decl', '');
67 }
Matteo Scandoloe9cdf9a2017-11-21 10:41:28 -080068 this._events.next(data);
69
Matteo Scandolo06542252018-01-30 13:35:55 -080070 // NOTE update observers of parent classes
71 this.updateParentClasses(data);
Matteo Scandoloe9cdf9a2017-11-21 10:41:28 -080072 });
73
74 this.socket.on('update', (data: IWSEvent): void => {
Matteo Scandolo98b5f5d2017-03-17 17:09:05 -070075
Matteo Scandoloe015fa92017-05-10 09:52:36 -070076 if (data.msg.changed_fields.length === 0 || _.intersection(data.msg.changed_fields, ignoredFields).length === data.msg.changed_fields.length) {
77 // NOTE means that the only updated fields does not change anything in the UI, so don't send events around
Matteo Scandoloe015fa92017-05-10 09:52:36 -070078 return;
79 }
80
Matteo Scandolo31daa802017-09-01 12:19:56 -070081 this.$log.info(`[WebSocket] Received Event for: ${data.model} [${data.msg.pk}]`, data);
Matteo Scandoloc3804aa2017-08-09 16:00:43 -070082
Matteo Scandoloe015fa92017-05-10 09:52:36 -070083 this._events.next(data);
84
85 // NOTE update observers of parent classes
Matteo Scandolo06542252018-01-30 13:35:55 -080086 this.updateParentClasses(data);
Matteo Scandoloe015fa92017-05-10 09:52:36 -070087
88 });
Matteo Scandolo035c5932016-12-14 09:55:15 -080089 }
Matteo Scandolo06542252018-01-30 13:35:55 -080090
91 public list() {
Matteo Scandolob8d06372019-03-06 13:48:03 -080092 this.$log.debug(`[WebSocket] Active subscriptions: ${this._events.observers.length}`);
Matteo Scandolo035c5932016-12-14 09:55:15 -080093 return this._events.asObservable();
94 }
Matteo Scandolo06542252018-01-30 13:35:55 -080095
96 private updateParentClasses(data: IWSEvent) {
97 if (data.msg.object.class_names && angular.isString(data.msg.object.class_names)) {
98 const models = data.msg.object.class_names.split(',');
99 let event: IWSEvent = angular.copy(data);
100 _.forEach(models, (m: string) => {
101
102 switch (m) {
103 case 'object':
104 case 'XOSBase':
105 case 'Model':
106 case 'PlModelMixIn':
107 case 'AttributeMixin':
108 // do not send events for classes that we don't care about
109 break;
110 default:
111 if (m.indexOf('_decl') > -1 || event.model === m) {
112 // do not send events for _decl classes
113 // or if the parent class is the same as the model class
114 return;
115 }
116
117 event.model = m;
118 event.skip_notification = true;
119 this._events.next(event);
120 }
121 });
122 }
123 }
124}
125
126export class SocketIoService {
127
128 static $inject = [
129 'AppConfig'
130 ];
131
132 public socket;
133
134 constructor(
135 private AppConfig: IXosAppConfig,
136 private $log: ng.ILogService
137 ) {
138 this.socket = io(this.AppConfig.websocketClient);
139 }
Matteo Scandolo035c5932016-12-14 09:55:15 -0800140}