Skip to content
This repository was archived by the owner on Dec 15, 2019. It is now read-only.

Commit 09ca11c

Browse files
committed
Session broadcasting; Remove active sessions from status
1 parent 0aeac2a commit 09ca11c

File tree

2 files changed

+127
-104
lines changed

2 files changed

+127
-104
lines changed

src/api/endpoints/user/status.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
const authViaApiKey = require('../../tools/authViaApiKey');
2-
const websocket = require('../../../websocket');
32

43
module.exports = async req => {
54
const {apikey} = req.body;
@@ -10,7 +9,6 @@ module.exports = async req => {
109
return {
1110
availableSpace: _config.server.totalStorageLimitPerUser,
1211
uploadSizeLimitPerFile: _config.server.uploadSizeLimitPerFile,
13-
activeSessions: websocket.getSessionsBy(user.id),
1412
user: {
1513
id: user.id,
1614
username: user.username,

src/websocket.js

Lines changed: 127 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -6,128 +6,153 @@ const WebSocket = require('ws');
66
const lookup = maxmind.openSync(geolite2.paths.city);
77

88
const userMap = {};
9+
const websocket = {
910

10-
/**
11-
* Launches the websocket broadcast server
12-
* @param server
13-
*/
14-
module.exports.launch = server => {
15-
const wss = new WebSocket.Server({server: server});
16-
17-
wss.on('connection', (ws, req) => {
18-
let user;
19-
20-
ws.on('message', async message => {
21-
22-
// Answer ping request
23-
if (message === '__ping__') {
24-
return ws.send('__pong__');
25-
}
26-
27-
// Try to parse message
28-
try {
29-
message = JSON.parse(message);
30-
} catch (ignored) {
31-
return;
32-
}
33-
34-
const {type, value} = message;
35-
switch (type) {
36-
case 'register': {
37-
if (typeof value === 'string' && value) {
38-
user = await userModel.findOne({apikeys: {$elemMatch: {key: value}}});
39-
40-
if (!user) {
41-
return;
42-
}
11+
/**
12+
* Launches the websocket broadcast server
13+
* @param server
14+
*/
15+
launch(server) {
16+
const wss = new WebSocket.Server({server: server});
4317

44-
const userid = user.id;
45-
if (!(userid in userMap)) {
46-
userMap[userid] = {
47-
websockets: [],
48-
lastBroadcast: 0
49-
};
50-
} else if (userMap[userid].websockets.includes(ws)) {
51-
return;
52-
}
18+
wss.on('connection', (ws, req) => {
19+
let user;
5320

54-
// Lookup ip info
55-
const lu = lookup.get(req.connection.remoteAddress);
56-
57-
ws._sessionInfo = {
58-
city: lu.city.names.en,
59-
continent: lu.continent.names.en,
60-
country: lu.country.names.en,
61-
location: lu.location,
62-
registeredCountry: lu.registered_country.names.en,
63-
registerTimestamp: Date.now()
64-
};
65-
66-
userMap[userid].websockets.push(ws);
67-
68-
// Approve registration
69-
ws.send(JSON.stringify({
70-
type: 'registration-approval',
71-
value: {
72-
lastBroadcast: userMap[userid].lastBroadcast
73-
}
74-
}));
75-
}
21+
ws.on('message', async message => {
7622

77-
break;
23+
// Answer ping request
24+
if (message === '__ping__') {
25+
return ws.send('__pong__');
7826
}
79-
case 'broadcast': {
80-
if (user) {
81-
const container = userMap[user.id];
82-
const {websockets} = container;
83-
84-
// Broadcast message
85-
for (let i = 0, l = websockets.length; i < l; i++) {
86-
const socket = websockets[i];
87-
88-
if (socket !== ws) {
89-
socket.send(JSON.stringify({
90-
type: 'broadcast',
91-
value
92-
}));
27+
28+
// Try to parse message
29+
try {
30+
message = JSON.parse(message);
31+
} catch (ignored) {
32+
return;
33+
}
34+
35+
const {type, value} = message;
36+
switch (type) {
37+
case 'register': {
38+
if (typeof value === 'string' && value) {
39+
user = await userModel.findOne({apikeys: {$elemMatch: {key: value}}});
40+
41+
if (!user) {
42+
return;
9343
}
44+
45+
const userid = user.id;
46+
if (!(userid in userMap)) {
47+
userMap[userid] = {
48+
websockets: [],
49+
lastBroadcast: 0
50+
};
51+
} else if (userMap[userid].websockets.includes(ws)) {
52+
return;
53+
}
54+
55+
// Lookup ip info
56+
const lu = lookup.get(req.connection.remoteAddress);
57+
58+
ws._sessionInfo = {
59+
id: Math.floor(Math.random() * 1e15).toString(16) + Date.now().toString(16),
60+
city: lu.city.names.en,
61+
continent: lu.continent.names.en,
62+
country: lu.country.names.en,
63+
location: lu.location,
64+
registeredCountry: lu.registered_country.names.en,
65+
registerTimestamp: Date.now()
66+
};
67+
68+
userMap[userid].websockets.forEach(s => s.send(JSON.stringify({
69+
type: 'open-session',
70+
value: ws._sessionInfo
71+
})));
72+
73+
// Append websocket
74+
userMap[userid].websockets.push(ws);
75+
76+
// Approve registration
77+
ws.send(JSON.stringify({
78+
type: 'registration-approval',
79+
value: {
80+
lastBroadcast: userMap[userid].lastBroadcast,
81+
sessions: websocket.getSessionsBy(userid)
82+
}
83+
}));
9484
}
9585

96-
// Update last broadcast timestamp
97-
container.lastBroadcast = Date.now();
86+
break;
87+
}
88+
case 'broadcast': {
89+
if (user) {
90+
const container = userMap[user.id];
91+
const {websockets} = container;
92+
93+
// Broadcast message
94+
for (let i = 0, l = websockets.length; i < l; i++) {
95+
const socket = websockets[i];
96+
97+
if (socket !== ws) {
98+
socket.send(JSON.stringify({
99+
type: 'broadcast',
100+
value
101+
}));
102+
}
103+
}
104+
105+
// Update last broadcast timestamp
106+
container.lastBroadcast = Date.now();
107+
}
108+
break;
98109
}
99-
break;
100110
}
101-
}
102-
});
111+
});
103112

104-
ws.on('close', () => {
113+
ws.on('close', () => {
105114

106-
// Check if socket was registered
107-
if (user) {
108-
const {websockets} = userMap[user.id];
109-
const idx = websockets.indexOf(ws);
115+
// Check if socket was registered
116+
if (user) {
117+
const {websockets} = userMap[user.id];
118+
const idx = websockets.indexOf(ws);
110119

111-
// Remove socket
112-
if (~idx) {
113-
websockets.splice(idx, 1);
114-
}
120+
// Remove socket
121+
if (~idx) {
122+
const [socket] = websockets.splice(idx, 1);
123+
124+
if (socket) {
125+
websockets.forEach(ws => ws.send(JSON.stringify({
126+
type: 'close-session',
127+
value: socket._sessionInfo
128+
})));
129+
}
130+
}
115131

116-
// Clean up if no connection is open anymore
117-
if (!websockets.length) {
118-
delete userMap[user.id];
132+
// Clean up if no connection is open anymore
133+
if (!websockets.length) {
134+
delete userMap[user.id];
135+
}
119136
}
120-
}
137+
});
121138
});
122-
});
139+
},
140+
141+
/**
142+
* Returns the amount of currenty connected user
143+
* @param userid
144+
* @returns {number}
145+
*/
146+
getSessionsBy(userid) {
147+
const user = userMap[userid];
148+
return ((user && user.websockets) || []).map(v => v._sessionInfo);
149+
}
150+
123151
};
124152

125153
/**
126154
* Returns the amount of currenty connected user
127155
* @param userid
128156
* @returns {number}
129157
*/
130-
module.exports.getSessionsBy = userid => {
131-
const user = userMap[userid];
132-
return ((user && user.websockets) || []).map(v => v._sessionInfo);
133-
};
158+
module.exports = websocket;

0 commit comments

Comments
 (0)