diff options
Diffstat (limited to 'src/features/settingsWS/store.js')
-rwxr-xr-x | src/features/settingsWS/store.js | 120 |
1 files changed, 120 insertions, 0 deletions
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 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | import WebSocket from 'ws'; | ||
3 | import ms from 'ms'; | ||
4 | |||
5 | import Store from '../../stores/lib/Store'; | ||
6 | import { WS_API } from '../../environment'; | ||
7 | |||
8 | const debug = require('debug')('Franz:feature:settingsWS:store'); | ||
9 | |||
10 | export 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 | |||
120 | export default SettingsWSStore; | ||