-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
315 lines (293 loc) · 10.3 KB
/
index.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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
const generate = require('meaningful-string')
const EventEmitter = require('events');
const generation_options = {
"min": 20,
"max": 30,
"capsWithNumbers": true
}
const m_options = {
"numberUpto": 60,
"joinBy": '-'
}
/**
* SessionManager is a class that manages the sessions of the users.
* @extends EventEmitter
*/
class SessionManager extends EventEmitter {
constructor() {
super()
// Singleton declaration
if (SessionManager._instance) {
return SessionManager._instance
}
SessionManager._instance = this;
/** @const {Object} sessions - The sessions of the users. */
/** @const {SocketIO.Server} - The socket reference. */
/** @const {number} MIN_SESSION_TIMEOUT - The minimum session timeout. */
/** @const {Object} settings - The settings of the session manager. */
// Initialize the settings
this.sessions = []
this.skIo = null
this.MIN_SESSION_TIMEOUT = 2
this.settings = {
SESSION_TIMEOUT: 3000 // Seconds of session elapsing time
}
}
/**
* @param {string} msg
* @returns {void}
*
* @description Logs a message to the console if the debug flag is set to true in the config.
*
*/
log(msg) {
if (process.env.DEBUG) {
console.log(msg)
}
}
/**
* This function is used to set the session timeout
* @param {number} sessionTimeout The session timeout in seconds
* @return {boolean} true or false: true if ok
*
* @example setSessionTimeOut(3000) // Returns true or false
**/
setSessionTimeOut(sessionTimeout) {
if (typeof sessionTimeout === 'number' && sessionTimeout >= this.MIN_SESSION_TIMEOUT) {
this.settings.SESSION_TIMEOUT = sessionTimeout
return true
}
return false
}
/**
* This function is used to get the session timeout
* @return {number} The session timeout in seconds
*
* @example getSessionTimeOut() // Returns 3000
**/
getSessionTimeout() {
return this.settings.SESSION_TIMEOUT
}
/**
* This function is used to get the list of logged users
* @return {array} The list of logged users
*
* @example getLoggedUsers() // Returns ['Gino', 'Gino2']
**/
getLoggedUsers() {
return Object.keys(this.sessions).map((k, i) => this.sessions[Object.keys(this.sessions)[i]].username)
}
/**
* Function to copy the Socket IO http server reference
* @param {*} ioRef
* @return {boolean} true or false, true if ok
*/
initSocketReference(ioRef) {
this.skIo = ioRef
}
/**
* Function to get the socket reference
* @return {SocketIO.Server} The socket reference
*/
getSocketReference() {
return this.skIo
}
/**
* Function to add users sessions in this module. Use it at login
* @param {string} username The username provided on successful login
* @return {string} user unique key
*
* @example addSession('Gino') // Returns 'session_key'
*/
loadNewSession(username) { // Generate new session
this.log('[Session Manager]: New session saved! 😉')
const newSessionKey = `${generate.meaningful(m_options)}_${generate.random(generation_options)}`
this.sessions[newSessionKey] = {
username,
key: newSessionKey,
createdAt: Date.now(),
timer: this.createNewSessionTimer(newSessionKey, username)
}
this.emit('sessionCreated', newSessionKey)
//this.log("[Session Manager]: Active sessions:", sessions)
return newSessionKey
}
/**
* Function to set the property 'data' of a session. Use it for example to store something in the session, like the user actions history, etc.
*
* @param {string} key The session_key provided on successful login
* @param {object} data The data to be stored in the session
* @return {boolean} true or false, true if ok
* @throws {Error} If the session_key is not found
*
* @example setSessionData('session_key', {'actions': ["logged in", ...]}) // Returns true or false
*
*/
setSessionData(key, data) {
if (this.checkSessionStatus(key)) {
this.sessions[key].data = data // Set the data
return true
}
return false
}
/**
* Function to get the property 'data' of a session. Use it for example to get the user actions history, etc.
*
* @param {string} key The session_key provided on successful login
* @return {object} The data stored in the session
* @throws {Error} If the session_key is not found
*
* @example getSessionData('session_key') // Returns {'actions': ["logged in", ...]}
*/
getSessionData(key) {
if (this.checkSessionStatus(key)) {
return this.sessions[key].data
}
return false
}
/** Function that restart the session timer. Use it after an API call to keep the session alive.
*
* @param {string} key The session_key
* @return {boolean} true or false, true if ok
* @throws {Error} If the session key is not found
*
* @example restartSessionTimer('session_key') // Returns true or false
*/
restartSessionTimer(key) {
if (this.checkSessionStatus(key)) {
clearTimeout(this.sessions[key].timer)
this.sessions[key].timer = this.createNewSessionTimer(key, this.sessions[key].username)
return true
}
return false
}
/**
* Function to get details of a session. Use it to get the username, the creation date and the data.
*
* @param {string} key The session_key
* @return {object|boolean} The session details or false if not found
* @throws {Error} If the session key is not found
*
* @example getSessionDetails('session_key') // Returns {'username': 'Gino', 'createdAt': 1523456789, 'data': {'actions': ["logged in", ...]}}
*/
getSessionDetails(key) {
if (this.checkSessionStatus(key)) {
if (this.sessions[key].data) {
return {
username: this.sessions[key].username,
createdAt: this.sessions[key].createdAt,
data: this.sessions[key].data
}
} else {
return {
username: this.sessions[key].username,
createdAt: this.sessions[key].createdAt,
}
}
}
return false
}
/**
* Function to delete users sessions in this module. Use it at client logout
* @param {string} key The session_key provided on successful login
* @return {boolean} true or false, true if ok
* @throws {Error} If the session_key is not found
*
* @example deleteSession('session_key') // Returns true or false
*/
deleteSession(key) { // Generate new session
this.log('[Session Manager]: Deleting session! 😉')
let ret = false
if (this.checkSessionStatus(key)) {
clearTimeout(this.sessions[key].timer)
delete this.sessions[key]
ret = true
this.emit('sessionDeleted', key)
} else {
this.log(`[Session Manager]: Deleting session`)
ret = false
this.emit('error', new Error(`[Session Manager]: Deleting session`), {
// or anything that you can like an user id
key
})
}
return ret
}
/**
* Function to delete all sessions
* @return {boolean} true or false, true if ok
*/
deleteAllSessions() {
for (let key in this.sessions) {
this.deleteSession(key)
this.sendLogoutMessage(key)
}
return this.sessions.length === 0
}
/**
* Use this to notify the client to logout with WebSocket
* @param {string} key The session_key
* @return {boolean} true or false, true if ok
*
* @example sendLogoutMessage('session_key') // Returns true or false
*/
sendLogoutMessage(key) {
if (this.skIo !== null) {
this.emit('notifyClientToLogout', this.skIo, key)
}
}
/**
* Function to return a new setTimeout object and start it.
* @param {string} key The session_key
* @param {string} username The username, only for logging features
* @return {NodeJS.Timeout}
*
* @example createNewSessionTimer('session_key', 'username') // Returns a new setTimeout object
*/
createNewSessionTimer(key, username) {
return setTimeout((_key, _username) => {
this.sendLogoutMessage(_key) // Session is expired... logging out
delete this.sessions[_key]
this.emit('sessionDeleted', key)
this.log('[Session Manager]: Removed user', _username)
}, this.settings.SESSION_TIMEOUT * 1000, key, username)
}
/**
* Function to check if a key is valid and exists in the stored collection
* Use this before every API.js function execution.
* @param {string} key the user key generated at login
* @return {boolean} true or false: true if session is active
* @throws {Error} if the session is not valid
* @throws {Error} if the session is expired
*
* @example checkSessionStatus('my_session_key') // true or false
*
*/
checkSessionStatus(key) {
if (this.sessions[key]) {
this.log('[Session Manager]: Session accepted! 👍')
return true
}
this.log('[Session Manager]: ⚠ !Session rejected! ⚠')
this.emit('error', new Error(`[Session Manager]: ⚠ !Session rejected! ⚠`), {
// or anything that you can like an user id
key
})
return false
}
/**
* Function to get the username from a session key
* @param {string} key The session key
* @return {string} The username or false if not found
*
* @example getUsernameFromSessionKey('123456789_123456789') // 'username'
*/
getUsernameFromSessionKey(key) {
if (this.sessions[key]) {
return this.sessions[key].username
}
this.log('[Session Manager]: Session not found...')
return false
}
}
module.exports = SessionManager