aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2019-04-16 11:53:30 +0200
committerLibravatar Stefan Malzner <stefan@adlk.io>2019-04-16 11:53:30 +0200
commit03950e3f8a43691bdb1371625b860b29f40a6e60 (patch)
tree4765ba98e1e3dade746a7d0216b6bde6c9d1cce6 /src/features
parentMerge branch 'feature/announcements' into develop (diff)
parentMerge pull request #1393 from meetfranz/chore/streamline-dashboard (diff)
downloadferdium-app-03950e3f8a43691bdb1371625b860b29f40a6e60.tar.gz
ferdium-app-03950e3f8a43691bdb1371625b860b29f40a6e60.tar.zst
ferdium-app-03950e3f8a43691bdb1371625b860b29f40a6e60.zip
Merge branch 'develop' of https://github.com/meetfranz/franz into develop
Diffstat (limited to 'src/features')
-rwxr-xr-xsrc/features/settingsWS/actions.js10
-rwxr-xr-xsrc/features/settingsWS/index.js35
-rwxr-xr-xsrc/features/settingsWS/state.js13
-rwxr-xr-xsrc/features/settingsWS/store.js120
4 files changed, 178 insertions, 0 deletions
diff --git a/src/features/settingsWS/actions.js b/src/features/settingsWS/actions.js
new file mode 100755
index 000000000..631670c8a
--- /dev/null
+++ b/src/features/settingsWS/actions.js
@@ -0,0 +1,10 @@
1import PropTypes from 'prop-types';
2import { createActionsFromDefinitions } from '../../actions/lib/actions';
3
4export const settingsWSActions = createActionsFromDefinitions({
5 greet: {
6 name: PropTypes.string.isRequired,
7 },
8}, PropTypes.checkPropTypes);
9
10export default settingsWSActions;
diff --git a/src/features/settingsWS/index.js b/src/features/settingsWS/index.js
new file mode 100755
index 000000000..4049ae814
--- /dev/null
+++ b/src/features/settingsWS/index.js
@@ -0,0 +1,35 @@
1import { reaction, runInAction } from 'mobx';
2import { SettingsWSStore } from './store';
3import state, { resetState } from './state';
4
5const debug = require('debug')('Franz:feature:settingsWS');
6
7let store = null;
8
9export default function initSettingsWebSocket(stores, actions) {
10 const { features } = stores;
11
12 // Toggle SettingsWebSocket feature
13 reaction(
14 () => (
15 features.features.isSettingsWSEnabled
16 ),
17 (isEnabled) => {
18 if (isEnabled) {
19 debug('Initializing `settingsWS` feature');
20 store = new SettingsWSStore(stores, null, actions, state);
21 store.initialize();
22 runInAction(() => { state.isFeatureActive = true; });
23 } else if (store) {
24 debug('Disabling `settingsWS` feature');
25 runInAction(() => { state.isFeatureActive = false; });
26 store.teardown();
27 store = null;
28 resetState(); // Reset state to default
29 }
30 },
31 {
32 fireImmediately: true,
33 },
34 );
35}
diff --git a/src/features/settingsWS/state.js b/src/features/settingsWS/state.js
new file mode 100755
index 000000000..7b16b2b6e
--- /dev/null
+++ b/src/features/settingsWS/state.js
@@ -0,0 +1,13 @@
1import { observable } from 'mobx';
2
3const defaultState = {
4 isFeatureActive: false,
5};
6
7export const settingsWSState = observable(defaultState);
8
9export function resetState() {
10 Object.assign(settingsWSState, defaultState);
11}
12
13export default settingsWSState;
diff --git a/src/features/settingsWS/store.js b/src/features/settingsWS/store.js
new file mode 100755
index 000000000..0f1feebb9
--- /dev/null
+++ b/src/features/settingsWS/store.js
@@ -0,0 +1,120 @@
1import { observable } from 'mobx';
2import WebSocket from 'ws';
3import ms from 'ms';
4
5import Store from '../../stores/lib/Store';
6import { WS_API } from '../../environment';
7
8const debug = require('debug')('Franz:feature:settingsWS:store');
9
10export class SettingsWSStore extends Store {
11 ws = null;
12
13 @observable connected = false;
14
15 pingTimeout = null;
16
17 reconnectTimeout = null;
18
19 constructor(stores, api, actions, state) {
20 super(stores, api, actions);
21 this.state = state;
22
23 this.registerReactions([
24 this._initialize.bind(this),
25 this._reconnect.bind(this),
26 this._close.bind(this),
27 ]);
28 }
29
30 connect() {
31 try {
32 const wsURL = `${WS_API}/ws/${this.stores.user.data.id}`;
33 debug('Setting up WebSocket to', wsURL);
34
35 this.ws = new WebSocket(wsURL);
36
37 this.ws.on('open', () => {
38 debug('Opened WebSocket');
39 this.send({
40 action: 'authorize',
41 token: this.stores.user.authToken,
42 });
43
44 this.connected = true;
45
46 this.heartbeat();
47 });
48
49 this.ws.on('message', (data) => {
50 const resp = JSON.parse(data);
51 debug('Received message', resp);
52
53 if (resp.id) {
54 this.stores.user.getUserInfoRequest.patch((result) => {
55 if (!result) return;
56
57 debug('Patching user object with new values');
58 Object.assign(result, resp);
59 });
60 }
61 });
62
63 this.ws.on('ping', this.heartbeat.bind(this));
64 } catch (err) {
65 console.err(err);
66 }
67 }
68
69 heartbeat() {
70 debug('Heartbeat');
71 clearTimeout(this.pingTimeout);
72
73 this.pingTimeout = setTimeout(() => {
74 debug('Terminating connection, reconnecting in 35');
75 this.ws.terminate();
76
77 this.connected = false;
78 }, ms('35s'));
79 }
80
81 send(data) {
82 if (this.ws) {
83 this.ws.send(JSON.stringify(data));
84 debug('Sending data', data);
85 } else {
86 debug('WebSocket is not initialized');
87 }
88 }
89
90 // Reactions
91
92 _initialize() {
93 if (this.stores.user.data.id) {
94 this.connect();
95 }
96 }
97
98 _reconnect() {
99 if (!this.connected) {
100 debug('Trying to reconnect in 30s');
101 this.reconnectTimeout = setInterval(() => {
102 debug('Trying to reconnect');
103 this.connect();
104 }, ms('30s'));
105 } else {
106 debug('Clearing reconnect interval');
107 clearInterval(this.reconnectTimeout);
108 }
109 }
110
111 _close() {
112 if (!this.stores.user.isLoggedIn && this.ws) {
113 debug('Terminating connection');
114 this.ws.terminate();
115 this.ws = null;
116 }
117 }
118}
119
120export default SettingsWSStore;