forked from brainfoolong/web-ftp-client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebsocketuser.js
182 lines (168 loc) · 4.54 KB
/
websocketuser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
'use strict'
const path = require('path')
const fs = require('fs')
/**
* A single websocket user
* @constructor
*/
function WebSocketUser (socket) {
/** @type {WebSocketUser} */
const self = this
/** @type {number|null} */
this.id = null
/** @type {WebSocket} */
this.socket = socket
/** @type {object} */
this.bulkList = {}
/** @type {object} */
this.bulkTimeouts = {}
/**
* The current stored userdata
* Updated with each websocket incoming message
* @type {null}
*/
this.userData = null
self.id = WebSocketUser.instances.length
WebSocketUser.instances.push(self)
/**
* Send message to client
* @param {string} action
* @param {object=} message
* @param {number=} callbackId
*/
this.send = function (action, message, callbackId) {
if (self.socket) {
if (typeof message === 'undefined') {
message = null
}
const data = {
'action': action,
'message': message
}
if (typeof callbackId === 'number') {
data.callbackId = callbackId
}
try {
self.socket.send(JSON.stringify(data))
} catch (err) {
}
}
}
/**
* Do a bulk send, collect all bulkSends and send them out only each 500ms
* This prevent mass spam of socket and frontend and give everything time to breath
* All bulk sends of last 500ms will simply be collected to an array
* @param {string} action
* @param {object=} message
*/
this.bulkSend = function (action, message) {
const time = new Date().getTime()
if (typeof this.bulkList[action] === 'undefined') {
this.bulkList[action] = {'lastSent': time, 'collection': []}
}
const bulkColl = this.bulkList[action]
bulkColl.collection.push(message)
const send = function () {
bulkColl.lastSent = time
const arr = bulkColl.collection
bulkColl.collection = []
self.send(action, {'bulk': true, 'messages': arr})
}
const wait = (bulkColl.lastSent + 1000) - time
// if wait time is over, send bulk
if (wait <= 0) {
send()
} else {
// timeout for the next send
if (this.bulkTimeouts[action]) clearTimeout(this.bulkTimeouts[action])
this.bulkTimeouts[action] = setTimeout(send, wait)
}
}
/**
* If the socket got closed
*/
this.closed = function () {
WebSocketUser.instances.splice(self.id, 1)
self.socket = null
self.userData = null
}
/**
* On receive message from socket
* @param {object} frontendMessage
*/
this.onMessage = function (frontendMessage) {
// just send a message to the user for the callback in the frontend
const sendCallback = function (message) {
self.send(frontendMessage.action, message, frontendMessage.callbackId)
}
const actionPath = path.join(__dirname, 'actions/' + frontendMessage.action.replace(/[^a-z0-9_-]/ig, '') + '.js')
if (fs.existsSync(actionPath)) {
const action = require(actionPath)
if (action.requireAdmin && (!self.userData || !self.userData.admin)) {
sendCallback({
'error': {
'message': 'Require an administrator for: ' + frontendMessage.action
}
})
return
}
if (action.requireUser && !self.userData) {
sendCallback({
'error': {
'message': 'Require a valid user for: ' + frontendMessage.action
}
})
return
}
try {
action.execute(self, frontendMessage.message, sendCallback)
} catch (e) {
sendCallback({
'error': {
'message': e.message,
'stack': e.stack
}
})
}
} else {
sendCallback({
'error': {
'message': 'Action ' + frontendMessage.action + ' not exist in ' + actionPath
}
})
}
}
/**
* Convert to json
* @returns {object}
*/
this.toJSON = function () {
return {'username': this.userData.username}
}
}
/**
* All user instances
* @type WebSocketUser[]
*/
WebSocketUser.instances = []
/**
* Bulk send a message to all users
* @param {string} action
* @param {*} message
*/
WebSocketUser.bulkSendToAll = function (action, message) {
for (let i = 0; i < WebSocketUser.instances.length; i++) {
WebSocketUser.instances[i].bulkSend(action, message)
}
}
/**
* Send a message to all users
* @param {string} action
* @param {*} message
*/
WebSocketUser.sendToAll = function (action, message) {
for (let i = 0; i < WebSocketUser.instances.length; i++) {
WebSocketUser.instances[i].send(action, message)
}
}
module.exports = WebSocketUser