update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[osm/UI.git] / skyquake / framework / widgets / skyquake_container / skyquakeContainerStore.js
1 /*
2 *
3 * Copyright 2016 RIFT.IO Inc
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 //This will reach out to the global routes endpoint
19
20 import Alt from './skyquakeAltInstance.js';
21 import SkyquakeContainerSource from './skyquakeContainerSource.js';
22 import SkyquakeContainerActions from './skyquakeContainerActions';
23 let Utils = require('utils/utils.js');
24 import _indexOf from 'lodash/indexOf';
25 import _isEqual from 'lodash/isEqual';
26 //Temporary, until api server is on same port as webserver
27 import rw from 'utils/rw.js';
28
29 var API_SERVER = rw.getSearchParams(window.location).api_server;
30 const MAX_STORED_EVENTS = 20;
31
32 class SkyquakeContainerStore {
33 constructor() {
34 this.currentPlugin = getCurrentPlugin();
35 this.nav = {};
36 let notificationList = null;
37 try {notificationList = JSON.parse(sessionStorage.getItem('notifications'));} catch (e) {}
38 this.notifications = notificationList || [];
39 this.socket = null;
40 this.projects = null;
41 this.user = {};
42 //Notification defaults
43 this.notificationMessage = '';
44 this.displayNotification = false;
45 this.notificationType = 'error';
46 //Screen Loader default
47 this.displayScreenLoader = false;
48 this.bindActions(SkyquakeContainerActions);
49 this.exportAsync(SkyquakeContainerSource);
50
51
52 this.exportPublicMethods({
53 // getNav: this.getNav
54 });
55
56 }
57 getSkyquakeNavSuccess = (data) => {
58 var self = this;
59 this.setState({
60 nav: decorateAndTransformNav(data, self.currentPlugin)
61 })
62 }
63
64 closeSocket = () => {
65 if (this.socket) {
66 window.multiplexer.channel(this.channelId).close();
67 }
68 this.setState({
69 socket: null
70 });
71 }
72 //Remove once logging plugin is implemented
73 getSysLogViewerURLSuccess(data){
74 window.open(data.url);
75 }
76 getSysLogViewerURLError(data){
77 console.log('failed', data)
78 }
79
80 openNotificationsSocketLoading = () => {
81 this.setState({
82 isLoading: true
83 })
84 }
85
86 openNotificationsSocketSuccess = (data) => {
87 var self = this;
88
89 let connection = data.connection;
90 let streamSource = data.streamSource;
91 console.log('Success opening notification socket for stream ', streamSource);
92
93 let ws = window.multiplexer.channel(connection);
94
95 if (!connection) return;
96 self.setState({
97 socket: ws.ws,
98 isLoading: false,
99 channelId: connection
100 });
101
102 ws.onmessage = (socket) => {
103 try {
104 var data = JSON.parse(socket.data);
105 if(data.hasOwnProperty('map')) {
106 data = [];
107 }
108 if (!data.notification) {
109 console.warn('No notification in the received payload: ', data);
110 } else {
111 // Temp to test before adding multi-sources
112 data.notification.source = streamSource;
113 if (_indexOf(self.notifications, data.notification) == -1) {
114 // newly appreared event.
115 // Add to the notifications list and setState
116 self.notifications.unshift(data.notification);
117 (self.notifications.length > MAX_STORED_EVENTS) && self.notifications.pop();
118 self.setState({
119 newNotificationEvent: true,
120 newNotificationMsg: data.notification,
121 notifications: self.notifications,
122 isLoading: false
123 });
124 sessionStorage.setItem('notifications', JSON.stringify(self.notifications));
125 }
126 }
127 } catch(e) {
128 console.log('Error in parsing data on notification socket');
129 }
130 };
131
132 ws.onclose = () => {
133 self.closeSocket();
134 };
135 }
136
137 openNotificationsSocketError = (data) => {
138 console.log('Error opening notification socket', data);
139 }
140
141 getEventStreamsLoading = () => {
142 this.setState({
143 isLoading: true
144 });
145 }
146
147 getEventStreamsSuccess = (streams) => {
148 console.log('Found streams: ', streams);
149 let self = this;
150
151 streams &&
152 streams['ietf-restconf-monitoring:streams'] &&
153 streams['ietf-restconf-monitoring:streams']['stream'] &&
154 streams['ietf-restconf-monitoring:streams']['stream'].map((stream) => {
155 stream['access'] && stream['access'].map((streamLocation) => {
156 if (streamLocation['encoding'] == 'ws_json') {
157 setTimeout(() => {
158 self.getInstance().openNotificationsSocket(streamLocation['location'], stream['name']);
159 }, 0);
160 }
161 })
162 })
163
164 this.setState({
165 isLoading: true,
166 streams: streams
167 })
168 }
169
170 getEventStreamsError = (error) => {
171 console.log('Failed to get streams object');
172 this.setState({
173 isLoading: false
174 })
175 }
176
177 openProjectSocketSuccess = (connection) => {
178 var self = this;
179 var ws = window.multiplexer.channel(connection);
180 if (!connection) return;
181 self.setState({
182 socket: ws.ws,
183 channelId: connection
184 });
185 ws.onmessage = function(socket) {
186 try {
187 var data = JSON.parse(socket.data);
188 Utils.checkAuthentication(data.statusCode, function() {
189 self.closeSocket();
190 });
191 if (!data.project || !_isEqual(data.project, self.projects)) {
192 let user = self.user;
193 user.projects = data.project;
194 self.setState({
195 user: user,
196 projects: data.project || {}
197 });
198 }
199 } catch(e) {
200 console.log('HIT an exception in openProjectSocketSuccess', e);
201 }
202 };
203 }
204 getUserProfileSuccess = (user) => {
205 this.alt.actions.global.hideScreenLoader.defer();
206 this.setState({user})
207 }
208 selectActiveProjectSuccess = (projectId) => {
209 let user = this.user;
210 user.projectId = projectId;
211 this.setState({user});
212 window.location.href = window.location.origin;
213 }
214 //Notifications
215 handleServerReportedError = (result) => {
216 this.hideScreenLoader();
217 this.alt.actions.global.showNotification.defer(result);
218 }
219 showNotification = (notificationData) => {
220 this.setState({
221 notificationData,
222 displayNotification: true
223 })
224 }
225 hideNotification = () => {
226 this.setState({
227 displayNotification: false
228 })
229 }
230 //ScreenLoader
231 showScreenLoader = () => {
232 this.setState({
233 displayScreenLoader: true
234 });
235 }
236 hideScreenLoader = () => {
237 this.setState({
238 displayScreenLoader: false
239 })
240 }
241
242 }
243
244 /**
245 * Receives nav data from routes rest endpoint and decorates the data with internal/external linking information
246 * @param {object} nav Nav item from /nav endoingpoint
247 * @param {string} currentPlugin Current plugin name taken from url path.
248 * @return {array} Returns list of constructed nav items.
249 */
250 function decorateAndTransformNav(nav, currentPlugin) {
251 for ( let k in nav) {
252 nav[k].pluginName = k;
253 if (k != currentPlugin) {
254 nav[k].routes.map(function(route, i) {
255 if (API_SERVER) {
256 route.route = '/' + k + '/index.html?api_server=' + API_SERVER + '#' + route.route;
257 } else {
258 route.route = '/' + k + '/#' + route.route;
259 }
260 route.isExternal = true;
261 })
262 }
263 }
264 return nav;
265 }
266
267 function getCurrentPlugin() {
268 var paths = window.location.pathname.split('/');
269 var currentPath = null;
270 if (paths[0] != "") {
271 currentPath = paths[0]
272 } else {
273 currentPath = paths[1];
274 }
275 if (currentPath != null) {
276 return currentPath;
277 } else {
278 console.error('Well, something went horribly wrong with discovering the current plugin name - perhaps you should consider moving this logic to the server?')
279 }
280 }
281
282 export default Alt.createStore(SkyquakeContainerStore, 'SkyquakeContainerStore');