blob: d784958f2f5db7a185d3cc7112b845c22e038d81 [file] [log] [blame]
Matteo Scandolo72181592017-07-25 14:49:40 -07001import * as _ from 'lodash';
2import {Observable, BehaviorSubject, Subscription} from 'rxjs';
3import {IXosModelStoreService} from '../../datasources/stores/model.store';
4import {
5 IXosServiceGraph, IXosServiceModel, IXosTenantModel, IXosCoarseGraphData,
6 IXosServiceGraphNode, IXosServiceGraphLink, IXosFineGrainedGraphData
7} from '../interfaces';
8import {IXosDebouncer} from '../../core/services/helpers/debounce.helper';
9export interface IXosServiceGraphStore {
10 // TODO remove, moved in a new service
11 get(): Observable<IXosServiceGraph>;
12 // TODO rename in get()
13 getCoarse(): Observable<IXosServiceGraph>;
14}
15
16export class XosServiceGraphStore implements IXosServiceGraphStore {
17 static $inject = [
18 '$log',
19 'XosModelStore',
20 'XosDebouncer'
21 ];
22
23 // graph data store
24 private graphData: BehaviorSubject<IXosFineGrainedGraphData> = new BehaviorSubject({
25 services: [],
26 tenants: [],
27 networks: [],
28 subscribers: [],
29 servicedependencies: []
30 });
31
32 private emptyGraph: IXosServiceGraph = {
33 nodes: [],
34 links: []
35 };
36
37 // representation of the graph as D3 requires
38 private d3CoarseGraph = new BehaviorSubject(this.emptyGraph);
39 private d3FineGrainedGraph = new BehaviorSubject(this.emptyGraph);
40
41 // storing locally reference to the data model
42 private services;
43 private tenants;
44 private subscribers;
45 private networks;
46 private servicedependencys;
47
48 // debounced functions
49 private handleData;
50
51 // datastore
52 private ServiceSubscription: Subscription;
53 private TenantSubscription: Subscription;
54 private SubscriberSubscription: Subscription;
55 private NetworkSubscription: Subscription;
56 private ServiceDependencySubscription: Subscription;
57
58 constructor (
59 private $log: ng.ILogService,
60 private XosModelStore: IXosModelStoreService,
61 private XosDebouncer: IXosDebouncer
62 ) {
63
64 this.$log.info(`[XosServiceGraphStore] Setup`);
65
66 // we want to have a quiet period of 500ms from the last event before doing anything
67 this.handleData = this.XosDebouncer.debounce(this._handleData, 500, this, false);
68
69 // observe models and populate graphData
70 this.ServiceSubscription = this.XosModelStore.query('Service', '/core/services')
71 .subscribe(
72 (res) => {
73 this.combineData(res, 'services');
74 },
75 (err) => {
76 this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
77 }
78 );
79
80 this.ServiceDependencySubscription = this.XosModelStore.query('ServiceDependency', '/core/servicedependencys')
81 .subscribe(
82 (res) => {
83 this.combineData(res, 'servicedependencies');
84 },
85 (err) => {
86 this.$log.error(`[XosServiceGraphStore] Service Observable: `, err);
87 }
88 );
89
90 this.TenantSubscription = this.XosModelStore.query('Tenant', '/core/tenants')
91 .subscribe(
92 (res) => {
93 this.combineData(res, 'tenants');
94 },
95 (err) => {
96 this.$log.error(`[XosServiceGraphStore] Tenant Observable: `, err);
97 }
98 );
99
100 this.SubscriberSubscription = this.XosModelStore.query('Tenantroot', '/core/tenantroots')
101 .subscribe(
102 (res) => {
103 this.combineData(res, 'subscribers');
104 },
105 (err) => {
106 this.$log.error(`[XosServiceGraphStore] Subscriber Observable: `, err);
107 }
108 );
109
110 this.NetworkSubscription = this.XosModelStore.query('Network', '/core/networks')
111 .subscribe(
112 (res) => {
113 this.combineData(res, 'networks');
114 },
115 (err) => {
116 this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
117 }
118 );
119
120 // observe graphData and build Coarse and FineGrained graphs
121 this.graphData
122 .subscribe(
123 (res: IXosFineGrainedGraphData) => {
124 this.$log.debug(`[XosServiceGraphStore] New graph data received`, res);
125 this.graphDataToCoarseGraph(res);
126 // this.graphDataToFineGrainedGraph(res);
127 },
128 (err) => {
129 this.$log.error(`[XosServiceGraphStore] graphData Observable: `, err);
130 }
131 );
132 }
133
134 public get() {
135 return this.d3FineGrainedGraph.asObservable();
136 }
137
138 public getCoarse() {
139 return this.d3CoarseGraph.asObservable();
140 }
141
142 private combineData(data: any, type: 'services'|'tenants'|'subscribers'|'networks'|'servicedependencies') {
143 switch (type) {
144 case 'services':
145 this.services = data;
146 break;
147 case 'tenants':
148 this.tenants = data;
149 break;
150 case 'subscribers':
151 this.subscribers = data;
152 break;
153 case 'networks':
154 this.networks = data;
155 break;
156 case 'servicedependencies':
157 this.servicedependencys = data;
158 break;
159 }
160 this.handleData(this.services, this.tenants);
161 }
162
163 private _handleData(services: IXosServiceModel[], tenants: IXosTenantModel[]) {
164 this.graphData.next({
165 services: this.services,
166 tenants: this.tenants,
167 subscribers: this.subscribers,
168 networks: this.networks,
169 servicedependencies: this.servicedependencys
170 });
171 }
172
173 private getNodeIndexById(id: number | string, nodes: IXosServiceModel[]) {
174 return _.findIndex(nodes, {id: id});
175 }
176
177 private graphDataToCoarseGraph(data: IXosCoarseGraphData) {
178
179 try {
180 const links: IXosServiceGraphLink[] = _.chain(data.servicedependencies)
181 .map((t: IXosTenantModel) => {
182 return {
183 id: t.id,
184 source: this.getNodeIndexById(t.provider_service_id, data.services),
185 target: this.getNodeIndexById(t.subscriber_service_id, data.services),
186 model: t
187 };
188 })
189 .value();
190
191 const nodes: IXosServiceGraphNode[] = _.map(data.services, (s: IXosServiceModel) => {
192 return {
193 id: s.id,
194 label: s.name,
195 model: s
196 };
197 });
198
199 let graph: IXosServiceGraph = {
200 nodes,
201 links
202 };
203
204 this.d3CoarseGraph.next(graph);
205 } catch (e) {
206 this.d3CoarseGraph.error(e);
207 }
208 }
209}