This commit is contained in:
parent
7224de69b7
commit
9b15b4b4f3
@ -40,10 +40,11 @@ module.exports = convict({
|
|||||||
env: 'PORT',
|
env: 'PORT',
|
||||||
arg: 'port'
|
arg: 'port'
|
||||||
},
|
},
|
||||||
timeout: {
|
expire_timeout: {
|
||||||
doc: '',
|
doc: 'The timeout before EXPIRE message send',
|
||||||
format: 'duration',
|
format: 'duration',
|
||||||
default: 5000
|
default: 5000,
|
||||||
|
arg: 'expireTimeout'
|
||||||
},
|
},
|
||||||
key: {
|
key: {
|
||||||
doc: 'The key to check incoming clients',
|
doc: 'The key to check incoming clients',
|
||||||
@ -79,9 +80,9 @@ module.exports = convict({
|
|||||||
arg: 'proxied'
|
arg: 'proxied'
|
||||||
},
|
},
|
||||||
cleanup_out_msgs: {
|
cleanup_out_msgs: {
|
||||||
doc: '',
|
doc: 'The period in ms to check expired messages',
|
||||||
format: 'duration',
|
format: 'duration',
|
||||||
default: 5000
|
default: 1000
|
||||||
},
|
},
|
||||||
ssl: {
|
ssl: {
|
||||||
key_path: {
|
key_path: {
|
||||||
|
45
src/index.js
45
src/index.js
@ -6,10 +6,10 @@ const fs = require('fs');
|
|||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
const WebSocketServer = require('./services/webSocketServer');
|
const WebSocketServer = require('./services/webSocketServer');
|
||||||
const logger = require('./services/logger');
|
const logger = require('./services/logger');
|
||||||
|
const realm = require('./services/realm');
|
||||||
|
const { startMessagesExpiration } = require('./services/messagesExpire');
|
||||||
const api = require('./api');
|
const api = require('./api');
|
||||||
const messageHandler = require('./messageHandler');
|
const messageHandler = require('./messageHandler');
|
||||||
const realm = require('./services/realm');
|
|
||||||
const { MessageType } = require('./enums');
|
|
||||||
|
|
||||||
process.on('uncaughtException', (e) => {
|
process.on('uncaughtException', (e) => {
|
||||||
logger.error('Error: ' + e);
|
logger.error('Error: ' + e);
|
||||||
@ -53,10 +53,13 @@ app.use(path, api);
|
|||||||
const wss = new WebSocketServer(server, app.mountpath);
|
const wss = new WebSocketServer(server, app.mountpath);
|
||||||
|
|
||||||
wss.on('connection', client => {
|
wss.on('connection', client => {
|
||||||
const messages = realm.getMessageQueueById(client.getId());
|
const messageQueue = realm.getMessageQueueById(client.getId());
|
||||||
|
|
||||||
if (messages) {
|
if (messageQueue) {
|
||||||
messages.forEach(message => messageHandler(client, message));
|
let message;
|
||||||
|
while (message = messageQueue.readMessage()) {
|
||||||
|
messageHandler(client, message);
|
||||||
|
}
|
||||||
realm.clearMessageQueue(client.getId());
|
realm.clearMessageQueue(client.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,34 +89,6 @@ server.listen(port, host, () => {
|
|||||||
'Started PeerServer on %s, port: %s',
|
'Started PeerServer on %s, port: %s',
|
||||||
host, port
|
host, port
|
||||||
);
|
);
|
||||||
|
|
||||||
|
startMessagesExpiration();
|
||||||
});
|
});
|
||||||
|
|
||||||
const pruneOutstanding = () => {
|
|
||||||
const destinationClientsIds = realm.messageQueue.keys();
|
|
||||||
|
|
||||||
for (const destinationClientId of destinationClientsIds) {
|
|
||||||
const messages = realm.getMessageQueueById(destinationClientId);
|
|
||||||
|
|
||||||
const seen = {};
|
|
||||||
|
|
||||||
for (const message of messages) {
|
|
||||||
if (!seen[message.src]) {
|
|
||||||
messageHandler(null, {
|
|
||||||
type: MessageType.EXPIRE,
|
|
||||||
src: message.dst,
|
|
||||||
dst: message.src
|
|
||||||
});
|
|
||||||
seen[message.src] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
realm.messageQueue.clear();
|
|
||||||
|
|
||||||
logger.debug(`message queue was cleared`);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Clean up outstanding messages
|
|
||||||
setInterval(() => {
|
|
||||||
pruneOutstanding();
|
|
||||||
}, config.get('cleanup_out_msgs'));
|
|
||||||
|
@ -5,7 +5,7 @@ const transmissionHandler = require('./handlers/transmission');
|
|||||||
const handlers = {};
|
const handlers = {};
|
||||||
|
|
||||||
const registerHandler = (messageType, handler) => {
|
const registerHandler = (messageType, handler) => {
|
||||||
logger.info(`[MSGHANDLER] register handler for ${messageType}`);
|
logger.debug(`[MSGHANDLER] register handler for ${messageType}`);
|
||||||
handlers[messageType] = handler;
|
handlers[messageType] = handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
30
src/models/messageQueue.js
Normal file
30
src/models/messageQueue.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
class MessageQueue {
|
||||||
|
constructor (id) {
|
||||||
|
this._id = id;
|
||||||
|
this._lastReadAt = new Date().getTime();
|
||||||
|
this._messages = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastReadAt () {
|
||||||
|
return this._lastReadAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
addMessage (message) {
|
||||||
|
this._messages.push(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
readMessage () {
|
||||||
|
if (this._messages.length > 0) {
|
||||||
|
this._lastReadAt = new Date().getTime();
|
||||||
|
return this._messages.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMessages () {
|
||||||
|
return this._messages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MessageQueue;
|
@ -1,19 +1,21 @@
|
|||||||
|
const MessageQueue = require('./messageQueue');
|
||||||
|
|
||||||
class Realm {
|
class Realm {
|
||||||
constructor () {
|
constructor () {
|
||||||
this.clients = new Map();
|
this._clients = new Map();
|
||||||
this.messageQueue = new Map();
|
this._messageQueues = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
getClientsIds () {
|
getClientsIds () {
|
||||||
return [...this.clients.keys()];
|
return [...this._clients.keys()];
|
||||||
}
|
}
|
||||||
|
|
||||||
getClientById (clientId) {
|
getClientById (clientId) {
|
||||||
return this.clients.get(clientId);
|
return this._clients.get(clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
setClient (client, id) {
|
setClient (client, id) {
|
||||||
this.clients.set(id, client);
|
this._clients.set(id, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeClientById (id) {
|
removeClientById (id) {
|
||||||
@ -21,23 +23,23 @@ class Realm {
|
|||||||
|
|
||||||
if (!client) return false;
|
if (!client) return false;
|
||||||
|
|
||||||
this.clients.delete(id);
|
this._clients.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMessageQueueById (id) {
|
getMessageQueueById (id) {
|
||||||
return this.messageQueue.get(id);
|
return this._messageQueues.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
addMessageToQueue (id, message) {
|
addMessageToQueue (id, message) {
|
||||||
if (!this.getMessageQueueById(id)) {
|
if (!this.getMessageQueueById(id)) {
|
||||||
this.messageQueue.set(id, []);
|
this._messageQueues.set(id, new MessageQueue(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getMessageQueueById(id).push(message);
|
this.getMessageQueueById(id).addMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearMessageQueue (id) {
|
clearMessageQueue (id) {
|
||||||
this.messageQueue.delete(id);
|
this._messageQueues.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
generateClientId () {
|
generateClientId () {
|
||||||
|
67
src/services/messagesExpire/index.js
Normal file
67
src/services/messagesExpire/index.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
const config = require('../../../config');
|
||||||
|
const messageHandler = require('../../messageHandler');
|
||||||
|
const { MessageType } = require('../../enums');
|
||||||
|
const realm = require('../realm');
|
||||||
|
const logger = require('../logger');
|
||||||
|
|
||||||
|
const pruneOutstanding = () => {
|
||||||
|
const destinationClientsIds = realm._messageQueues.keys();
|
||||||
|
|
||||||
|
const now = new Date().getTime();
|
||||||
|
const maxDiff = config.get('expire_timeout');
|
||||||
|
|
||||||
|
const seen = {};
|
||||||
|
|
||||||
|
for (const destinationClientId of destinationClientsIds) {
|
||||||
|
const messageQueue = realm.getMessageQueueById(destinationClientId);
|
||||||
|
const lastReadDiff = now - messageQueue.getLastReadAt();
|
||||||
|
|
||||||
|
if (lastReadDiff < maxDiff) continue;
|
||||||
|
|
||||||
|
const messages = messageQueue.getMessages();
|
||||||
|
|
||||||
|
for (const message of messages) {
|
||||||
|
if (!seen[message.src]) {
|
||||||
|
messageHandler(null, {
|
||||||
|
type: MessageType.EXPIRE,
|
||||||
|
src: message.dst,
|
||||||
|
dst: message.src
|
||||||
|
});
|
||||||
|
seen[message.src] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
realm.clearMessageQueue(destinationClientId);
|
||||||
|
|
||||||
|
logger.trace(`[MSGSEXPIRE] mq ${destinationClientId} was cleared`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let timeoutId;
|
||||||
|
|
||||||
|
const startMessagesExpiration = () => {
|
||||||
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up outstanding messages
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
pruneOutstanding();
|
||||||
|
|
||||||
|
timeoutId = null;
|
||||||
|
|
||||||
|
startMessagesExpiration();
|
||||||
|
}, config.get('cleanup_out_msgs'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const stopMessagesExpiration = () => {
|
||||||
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
timeoutId = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
startMessagesExpiration,
|
||||||
|
stopMessagesExpiration
|
||||||
|
};
|
@ -24,8 +24,6 @@ class WebSocketServer extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onSocketConnection (socket, req) {
|
_onSocketConnection (socket, req) {
|
||||||
logger.debug(`[WSS] on new connection:${req}`);
|
|
||||||
|
|
||||||
const { query = {} } = url.parse(req.url, true);
|
const { query = {} } = url.parse(req.url, true);
|
||||||
|
|
||||||
const { id, token, key } = query;
|
const { id, token, key } = query;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user