sleepy-serv 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -8
- package/dist/core/index.d.ts +31 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/middleware.d.ts +2 -2
- package/dist/core/middleware.d.ts.map +1 -1
- package/dist/core/socket.d.ts +44 -17
- package/dist/core/socket.d.ts.map +1 -1
- package/dist/core/utils.d.ts +40 -86
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/index.ts +105 -71
- package/src/core/middleware.ts +9 -7
- package/src/core/socket.ts +172 -71
- package/src/core/utils.ts +51 -103
- package/src/index.ts +4 -4
package/src/core/socket.ts
CHANGED
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
12
|
StatusCode,
|
|
13
|
-
|
|
13
|
+
SessionType,
|
|
14
|
+
SessionFilter,
|
|
14
15
|
toSegments,
|
|
15
16
|
formatError,
|
|
16
17
|
executeMiddlewareChain,
|
|
@@ -37,14 +38,9 @@ import type {
|
|
|
37
38
|
FilterFn,
|
|
38
39
|
MiddlewareChain,
|
|
39
40
|
SocketCommands,
|
|
41
|
+
SocketData,
|
|
40
42
|
SessionEntry,
|
|
41
43
|
WebSocketRequest,
|
|
42
|
-
SocketData,
|
|
43
|
-
SocketConnection,
|
|
44
|
-
ActiveSession,
|
|
45
|
-
InactiveSession,
|
|
46
|
-
Session,
|
|
47
|
-
SocketOptions,
|
|
48
44
|
} from './utils'
|
|
49
45
|
|
|
50
46
|
import type {
|
|
@@ -54,7 +50,10 @@ import type {
|
|
|
54
50
|
ResponseMessage,
|
|
55
51
|
} from './messages'
|
|
56
52
|
|
|
57
|
-
type SocketHandler =
|
|
53
|
+
type SocketHandler<T = void> = (
|
|
54
|
+
req: Request<T>,
|
|
55
|
+
res: unknown,
|
|
56
|
+
) => AsyncHandlerResult
|
|
58
57
|
|
|
59
58
|
type UpgradeData = {
|
|
60
59
|
clientId?: string
|
|
@@ -66,10 +65,10 @@ type UpgradeContext = {
|
|
|
66
65
|
[key: string]: unknown
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
type SocketEndpoint = {
|
|
68
|
+
type SocketEndpoint<T = void> = {
|
|
70
69
|
method: HttpMethod
|
|
71
70
|
path: string
|
|
72
|
-
handler: SocketHandler
|
|
71
|
+
handler: SocketHandler<T>
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
type CreateSocketRequest = {
|
|
@@ -91,30 +90,79 @@ type UpdateTicketRequest = {
|
|
|
91
90
|
}
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
export type
|
|
93
|
+
export type SocketConnection<T = void> = {
|
|
94
|
+
data: SocketData<T>
|
|
95
|
+
send: (data: string) => unknown
|
|
96
|
+
close: (code?: number, reason?: string) => void
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export type ActiveSession<T = void> = {
|
|
100
|
+
token: string
|
|
101
|
+
ws: SocketConnection<T>
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type InactiveSession<T = void> = {
|
|
105
|
+
token: string
|
|
106
|
+
expiresAt: number
|
|
107
|
+
data: T
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type ActiveSessions<T = void> = ReadonlyMap<string, ActiveSession<T>>
|
|
111
|
+
|
|
112
|
+
export const ServerCloseSignals: Record<string, CloseSignal> = {
|
|
113
|
+
Ok: {
|
|
114
|
+
code: 1000,
|
|
115
|
+
reason: 'ok',
|
|
116
|
+
},
|
|
117
|
+
Reaped: {
|
|
118
|
+
code: 4998,
|
|
119
|
+
reason: 'reaped',
|
|
120
|
+
},
|
|
121
|
+
Superseded: {
|
|
122
|
+
code: 4999,
|
|
123
|
+
reason: 'superseded',
|
|
124
|
+
},
|
|
125
|
+
} as const
|
|
126
|
+
|
|
127
|
+
export type ServerCloseSignals =
|
|
128
|
+
typeof ServerCloseSignals[keyof typeof ServerCloseSignals]
|
|
129
|
+
|
|
130
|
+
export type Session<T = void> = ActiveSession<T> | InactiveSession<T>
|
|
131
|
+
|
|
132
|
+
export type SocketOptions = {
|
|
133
|
+
dropThreshold?: number
|
|
134
|
+
heartbeatInterval?: number
|
|
135
|
+
maxTickets?: number
|
|
136
|
+
reclaimTtl?: number
|
|
137
|
+
ticketTtl?: number
|
|
138
|
+
onOpen?: (clientId: string) => void
|
|
139
|
+
onClose?: (clientId: string, signal: CloseSignal) => void
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export type Ticket<T = void> = {
|
|
95
143
|
clientId: string
|
|
96
144
|
expiresAt: number
|
|
97
|
-
data:
|
|
145
|
+
data: T
|
|
98
146
|
}
|
|
99
147
|
|
|
100
|
-
export type SocketState = {
|
|
148
|
+
export type SocketState<T = void> = {
|
|
101
149
|
dropThreshold: number
|
|
102
150
|
heartbeatInterval: number
|
|
103
151
|
maxTickets: number
|
|
104
152
|
reclaimTtl: number
|
|
105
153
|
ticketTtl: number
|
|
106
|
-
tickets: Map<string, Ticket
|
|
107
|
-
activeSessions: Map<string, ActiveSession
|
|
108
|
-
inactiveSessions: Map<string, InactiveSession
|
|
154
|
+
tickets: Map<string, Ticket<T>>
|
|
155
|
+
activeSessions: Map<string, ActiveSession<T>>
|
|
156
|
+
inactiveSessions: Map<string, InactiveSession<T>>
|
|
109
157
|
onOpen: ((clientId: string) => void) | null
|
|
110
158
|
onClose: ((clientId: string, signal: CloseSignal) => void) | null
|
|
111
159
|
}
|
|
112
160
|
|
|
113
|
-
export type SocketRoute = {
|
|
161
|
+
export type SocketRoute<T = void> = {
|
|
114
162
|
method: HttpMethod
|
|
115
163
|
path: string
|
|
116
164
|
segments: string[]
|
|
117
|
-
chain: MiddlewareChain
|
|
165
|
+
chain: MiddlewareChain<T>
|
|
118
166
|
}
|
|
119
167
|
|
|
120
168
|
const ajv = new Ajv({
|
|
@@ -218,7 +266,7 @@ const updateTicketValidator = ajv.compile<UpdateTicketRequest>({
|
|
|
218
266
|
},
|
|
219
267
|
})
|
|
220
268
|
|
|
221
|
-
function isSessionActive (session: InactiveSession): boolean {
|
|
269
|
+
function isSessionActive<T> (session: InactiveSession<T>): boolean {
|
|
222
270
|
return !session.expiresAt || session.expiresAt > Date.now()
|
|
223
271
|
}
|
|
224
272
|
|
|
@@ -240,7 +288,7 @@ function parseMessage (raw: string | Buffer): RawMessage | undefined {
|
|
|
240
288
|
}
|
|
241
289
|
}
|
|
242
290
|
|
|
243
|
-
function sweepInactiveSessions (state: SocketState): void {
|
|
291
|
+
function sweepInactiveSessions<T> (state: SocketState<T>): void {
|
|
244
292
|
for (const [key, session] of state.inactiveSessions) {
|
|
245
293
|
if (!isSessionActive(session)) {
|
|
246
294
|
state.inactiveSessions.delete(key)
|
|
@@ -290,10 +338,10 @@ function matchesSegments (
|
|
|
290
338
|
)
|
|
291
339
|
}
|
|
292
340
|
|
|
293
|
-
function matchRoute (
|
|
294
|
-
routes: SocketRoute[],
|
|
341
|
+
function matchRoute<T> (
|
|
342
|
+
routes: SocketRoute<T>[],
|
|
295
343
|
message: RequestMessage,
|
|
296
|
-
): SocketRoute {
|
|
344
|
+
): SocketRoute<T> {
|
|
297
345
|
const requestSegments = toSegments(message.route)
|
|
298
346
|
|
|
299
347
|
const matchingPaths = routes.filter(route =>
|
|
@@ -313,8 +361,8 @@ function matchRoute (
|
|
|
313
361
|
return route
|
|
314
362
|
}
|
|
315
363
|
|
|
316
|
-
function buildParams (
|
|
317
|
-
route: SocketRoute
|
|
364
|
+
function buildParams<T> (
|
|
365
|
+
route: SocketRoute<T>,
|
|
318
366
|
message: RequestMessage,
|
|
319
367
|
): Record<string, string> {
|
|
320
368
|
const requestSegments = toSegments(message.route)
|
|
@@ -327,11 +375,11 @@ function buildParams (
|
|
|
327
375
|
} : accum, {})
|
|
328
376
|
}
|
|
329
377
|
|
|
330
|
-
function buildRequest (
|
|
378
|
+
function buildRequest<T> (
|
|
331
379
|
params: Record<string, string>,
|
|
332
380
|
message: RequestMessage,
|
|
333
|
-
ws: SocketCommands
|
|
334
|
-
): WebSocketRequest {
|
|
381
|
+
ws: SocketCommands<T>,
|
|
382
|
+
): WebSocketRequest<T> {
|
|
335
383
|
const { id, clientId, method, route } = message
|
|
336
384
|
const headers = new Headers(message.headers ?? {})
|
|
337
385
|
const query = message.query ?? {}
|
|
@@ -386,7 +434,9 @@ function buildErrorMessage (
|
|
|
386
434
|
})
|
|
387
435
|
}
|
|
388
436
|
|
|
389
|
-
export function buildSocketState
|
|
437
|
+
export function buildSocketState<T = void> (
|
|
438
|
+
opts: SocketOptions = {},
|
|
439
|
+
): SocketState<T> {
|
|
390
440
|
return {
|
|
391
441
|
dropThreshold: opts.dropThreshold ?? 120_000,
|
|
392
442
|
heartbeatInterval: opts.heartbeatInterval ?? 30_000,
|
|
@@ -401,11 +451,11 @@ export function buildSocketState (opts: SocketOptions = {}): SocketState {
|
|
|
401
451
|
}
|
|
402
452
|
}
|
|
403
453
|
|
|
404
|
-
export function buildSocketServer (
|
|
405
|
-
routes: SocketRoute[],
|
|
406
|
-
state: SocketState
|
|
407
|
-
commands: SocketCommands
|
|
408
|
-
): WebSocketHandler<SocketData
|
|
454
|
+
export function buildSocketServer<T = void> (
|
|
455
|
+
routes: SocketRoute<T>[],
|
|
456
|
+
state: SocketState<T>,
|
|
457
|
+
commands: SocketCommands<T>,
|
|
458
|
+
): WebSocketHandler<SocketData<T>> {
|
|
409
459
|
const {
|
|
410
460
|
dropThreshold,
|
|
411
461
|
heartbeatInterval,
|
|
@@ -416,7 +466,7 @@ export function buildSocketServer (
|
|
|
416
466
|
onClose,
|
|
417
467
|
} = state
|
|
418
468
|
|
|
419
|
-
function armReaper (ws: SocketConnection) {
|
|
469
|
+
function armReaper (ws: SocketConnection<T>) {
|
|
420
470
|
if (ws.data.reaperHandle) {
|
|
421
471
|
clearTimeout(ws.data.reaperHandle)
|
|
422
472
|
}
|
|
@@ -425,13 +475,13 @@ export function buildSocketServer (
|
|
|
425
475
|
ws.data.reaped = true
|
|
426
476
|
|
|
427
477
|
ws.close(
|
|
428
|
-
|
|
429
|
-
|
|
478
|
+
ServerCloseSignals.Reaped.code,
|
|
479
|
+
ServerCloseSignals.Reaped.reason,
|
|
430
480
|
)
|
|
431
481
|
}, dropThreshold)
|
|
432
482
|
}
|
|
433
483
|
|
|
434
|
-
function invokeOpen (ws: SocketConnection) {
|
|
484
|
+
function invokeOpen (ws: SocketConnection<T>) {
|
|
435
485
|
if (onOpen) {
|
|
436
486
|
try {
|
|
437
487
|
onOpen(ws.data.clientId)
|
|
@@ -441,7 +491,7 @@ export function buildSocketServer (
|
|
|
441
491
|
}
|
|
442
492
|
}
|
|
443
493
|
|
|
444
|
-
function invokeClose (ws: SocketConnection
|
|
494
|
+
function invokeClose (ws: SocketConnection<T>, signal: CloseSignal) {
|
|
445
495
|
if (onClose) {
|
|
446
496
|
try {
|
|
447
497
|
onClose(ws.data.clientId, signal)
|
|
@@ -452,7 +502,7 @@ export function buildSocketServer (
|
|
|
452
502
|
}
|
|
453
503
|
|
|
454
504
|
return {
|
|
455
|
-
open (ws: SocketConnection): void {
|
|
505
|
+
open (ws: SocketConnection<T>): void {
|
|
456
506
|
sweepInactiveSessions(state)
|
|
457
507
|
|
|
458
508
|
const token = randomToken()
|
|
@@ -462,8 +512,8 @@ export function buildSocketServer (
|
|
|
462
512
|
existingSession.ws.data.superseded = true
|
|
463
513
|
|
|
464
514
|
existingSession.ws.close(
|
|
465
|
-
|
|
466
|
-
|
|
515
|
+
ServerCloseSignals.Superseded.code,
|
|
516
|
+
ServerCloseSignals.Superseded.reason,
|
|
467
517
|
)
|
|
468
518
|
}
|
|
469
519
|
|
|
@@ -491,7 +541,7 @@ export function buildSocketServer (
|
|
|
491
541
|
ws.send(JSON.stringify(welcomeMessage))
|
|
492
542
|
invokeOpen(ws)
|
|
493
543
|
},
|
|
494
|
-
close (ws: SocketConnection
|
|
544
|
+
close (ws: SocketConnection<T>, code: number, reason: string): void {
|
|
495
545
|
const signal: CloseSignal = {
|
|
496
546
|
code,
|
|
497
547
|
reason,
|
|
@@ -515,17 +565,20 @@ export function buildSocketServer (
|
|
|
515
565
|
|
|
516
566
|
activeSessions.delete(ws.data.clientId)
|
|
517
567
|
|
|
518
|
-
if (code !==
|
|
568
|
+
if (code !== ServerCloseSignals.Ok.code || ws.data.reaped) {
|
|
519
569
|
inactiveSessions.set(ws.data.clientId, {
|
|
520
570
|
token: exists.token,
|
|
521
571
|
expiresAt: Date.now() + reclaimTtl,
|
|
522
|
-
|
|
572
|
+
data: ws.data.data,
|
|
523
573
|
})
|
|
524
574
|
}
|
|
525
575
|
|
|
526
576
|
invokeClose(ws, signal)
|
|
527
577
|
},
|
|
528
|
-
async message (
|
|
578
|
+
async message (
|
|
579
|
+
ws: SocketConnection<T>,
|
|
580
|
+
raw: string | Buffer,
|
|
581
|
+
): Promise<void> {
|
|
529
582
|
const incomingMsg = parseMessage(raw)
|
|
530
583
|
|
|
531
584
|
if (incomingMsg === undefined) {
|
|
@@ -565,7 +618,9 @@ export function buildSocketServer (
|
|
|
565
618
|
}
|
|
566
619
|
}
|
|
567
620
|
|
|
568
|
-
export function buildSocketHandlers
|
|
621
|
+
export function buildSocketHandlers<T = void> (
|
|
622
|
+
state: SocketState<T>,
|
|
623
|
+
): SocketEndpoint<T>[] {
|
|
569
624
|
const {
|
|
570
625
|
maxTickets,
|
|
571
626
|
ticketTtl,
|
|
@@ -574,7 +629,7 @@ export function buildSocketHandlers (state: SocketState): SocketEndpoint[] {
|
|
|
574
629
|
inactiveSessions,
|
|
575
630
|
} = state
|
|
576
631
|
|
|
577
|
-
function issueTicket (clientId: string, data:
|
|
632
|
+
function issueTicket (clientId: string, data: T): string {
|
|
578
633
|
for (const [key, entry] of tickets) {
|
|
579
634
|
if (entry.expiresAt > Date.now()) {
|
|
580
635
|
break
|
|
@@ -599,7 +654,7 @@ export function buildSocketHandlers (state: SocketState): SocketEndpoint[] {
|
|
|
599
654
|
return hash
|
|
600
655
|
}
|
|
601
656
|
|
|
602
|
-
function redeemTicket (hash: string): Ticket | undefined {
|
|
657
|
+
function redeemTicket (hash: string): Ticket<T> | undefined {
|
|
603
658
|
const entry = hash ? tickets.get(hash) : undefined
|
|
604
659
|
|
|
605
660
|
if (!entry) {
|
|
@@ -616,7 +671,7 @@ export function buildSocketHandlers (state: SocketState): SocketEndpoint[] {
|
|
|
616
671
|
{
|
|
617
672
|
method: 'GET',
|
|
618
673
|
path: '/ws',
|
|
619
|
-
handler (req: Request
|
|
674
|
+
handler (req: Request<T>, res: unknown): AsyncHandlerResult {
|
|
620
675
|
const validReq = validateSchema(req, createSocketValidator)
|
|
621
676
|
|
|
622
677
|
if (typeof res !== 'object') {
|
|
@@ -635,7 +690,7 @@ export function buildSocketHandlers (state: SocketState): SocketEndpoint[] {
|
|
|
635
690
|
ctx.data.superseded = false
|
|
636
691
|
ctx.data.reaped = false
|
|
637
692
|
ctx.data.reaperHandle = null
|
|
638
|
-
ctx.data.
|
|
693
|
+
ctx.data.data = ticket.data
|
|
639
694
|
|
|
640
695
|
const useSocket = validReq.server.upgrade(validReq.raw, ctx)
|
|
641
696
|
|
|
@@ -649,11 +704,11 @@ export function buildSocketHandlers (state: SocketState): SocketEndpoint[] {
|
|
|
649
704
|
{
|
|
650
705
|
method: 'POST',
|
|
651
706
|
path: '/ws',
|
|
652
|
-
async handler (req: Request
|
|
707
|
+
async handler (req: Request<T>, res: unknown): AsyncHandlerResult {
|
|
653
708
|
validateSchema(req, createTicketValidator)
|
|
654
709
|
|
|
655
710
|
const clientId = crypto.randomUUID()
|
|
656
|
-
const ticket = issueTicket(clientId, res)
|
|
711
|
+
const ticket = issueTicket(clientId, res as T)
|
|
657
712
|
|
|
658
713
|
return Response.json({
|
|
659
714
|
clientId,
|
|
@@ -665,12 +720,12 @@ export function buildSocketHandlers (state: SocketState): SocketEndpoint[] {
|
|
|
665
720
|
{
|
|
666
721
|
method: 'PUT',
|
|
667
722
|
path: '/ws/:clientId',
|
|
668
|
-
async handler (req: Request
|
|
723
|
+
async handler (req: Request<T>, res: unknown): AsyncHandlerResult {
|
|
669
724
|
const validReq = validateSchema(req, updateTicketValidator)
|
|
670
725
|
const authHeader = validReq.headers.get('authorization')!
|
|
671
726
|
const token = authHeader.slice('Bearer '.length)
|
|
672
727
|
|
|
673
|
-
let session: Session | undefined =
|
|
728
|
+
let session: Session<T> | undefined =
|
|
674
729
|
activeSessions.get(validReq.params.clientId)
|
|
675
730
|
|
|
676
731
|
if (!session) {
|
|
@@ -691,7 +746,7 @@ export function buildSocketHandlers (state: SocketState): SocketEndpoint[] {
|
|
|
691
746
|
throw new UnauthorizedError('Invalid token')
|
|
692
747
|
}
|
|
693
748
|
|
|
694
|
-
const appData = 'ws' in session ? session.ws.data.
|
|
749
|
+
const appData = 'ws' in session ? session.ws.data.data : session.data
|
|
695
750
|
|
|
696
751
|
return Response.json({
|
|
697
752
|
clientId: validReq.params.clientId,
|
|
@@ -703,7 +758,7 @@ export function buildSocketHandlers (state: SocketState): SocketEndpoint[] {
|
|
|
703
758
|
]
|
|
704
759
|
}
|
|
705
760
|
|
|
706
|
-
export function buildDisabledSocketCommands (): SocketCommands {
|
|
761
|
+
export function buildDisabledSocketCommands<T = void> (): SocketCommands<T> {
|
|
707
762
|
const msg = 'WebSocket support is not enabled'
|
|
708
763
|
|
|
709
764
|
return {
|
|
@@ -714,7 +769,9 @@ export function buildDisabledSocketCommands (): SocketCommands {
|
|
|
714
769
|
}
|
|
715
770
|
}
|
|
716
771
|
|
|
717
|
-
export function buildSocketCommands
|
|
772
|
+
export function buildSocketCommands<T = void> (
|
|
773
|
+
state: SocketState<T>,
|
|
774
|
+
): SocketCommands<T> {
|
|
718
775
|
function sendToClient (clientId: string, event: string, body: unknown) {
|
|
719
776
|
const session = state.activeSessions.get(clientId)
|
|
720
777
|
|
|
@@ -737,19 +794,25 @@ export function buildSocketCommands (state: SocketState): SocketCommands {
|
|
|
737
794
|
sendToClient(clientId, event, body)
|
|
738
795
|
}
|
|
739
796
|
},
|
|
740
|
-
send (event: string, body: unknown, fn: FilterFn) {
|
|
797
|
+
send (event: string, body: unknown, fn: FilterFn<T>) {
|
|
741
798
|
let index = 0
|
|
742
799
|
|
|
743
800
|
/* TODO: look into concurrency at some point */
|
|
744
801
|
for (const [clientId, session] of state.activeSessions) {
|
|
745
|
-
|
|
802
|
+
const entry: SessionEntry<T> = {
|
|
803
|
+
clientId,
|
|
804
|
+
type: SessionType.Active,
|
|
805
|
+
data: session.ws.data.data,
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
if (fn(entry, index)) {
|
|
746
809
|
sendToClient(clientId, event, body)
|
|
747
810
|
}
|
|
748
811
|
|
|
749
812
|
index += 1
|
|
750
813
|
}
|
|
751
814
|
},
|
|
752
|
-
drop (signal: CloseSignal, fn: FilterFn) {
|
|
815
|
+
drop (signal: CloseSignal, fn: FilterFn<T>) {
|
|
753
816
|
const { code, reason } = signal
|
|
754
817
|
|
|
755
818
|
let index = 0
|
|
@@ -761,28 +824,66 @@ export function buildSocketCommands (state: SocketState): SocketCommands {
|
|
|
761
824
|
}
|
|
762
825
|
|
|
763
826
|
for (const [clientId, session] of state.activeSessions) {
|
|
764
|
-
|
|
827
|
+
const entry: SessionEntry<T> = {
|
|
828
|
+
clientId,
|
|
829
|
+
type: SessionType.Active,
|
|
830
|
+
data: session.ws.data.data,
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
if (fn(entry, index)) {
|
|
765
834
|
session.ws.close(code, reason)
|
|
766
835
|
}
|
|
767
836
|
|
|
768
837
|
index += 1
|
|
769
838
|
}
|
|
770
839
|
},
|
|
771
|
-
query (
|
|
772
|
-
|
|
773
|
-
|
|
840
|
+
query (
|
|
841
|
+
fn: FilterFn<T>,
|
|
842
|
+
filter: SessionFilter = SessionFilter.Active,
|
|
843
|
+
) {
|
|
844
|
+
const results: SessionEntry<T>[] = []
|
|
845
|
+
|
|
846
|
+
function processSessions (
|
|
847
|
+
type: SessionType,
|
|
848
|
+
filter: SessionFilter,
|
|
849
|
+
startIndex: number,
|
|
850
|
+
): number {
|
|
851
|
+
let index = startIndex
|
|
852
|
+
|
|
853
|
+
const sessions = type === SessionType.Active
|
|
854
|
+
? state.activeSessions
|
|
855
|
+
: state.inactiveSessions
|
|
856
|
+
|
|
857
|
+
if (type !== filter && filter !== SessionFilter.All) {
|
|
858
|
+
return index
|
|
859
|
+
}
|
|
774
860
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
861
|
+
for (const [clientId, session] of sessions) {
|
|
862
|
+
const data = 'ws' in session ? session.ws.data.data : session.data
|
|
863
|
+
|
|
864
|
+
const entry: SessionEntry<T> = {
|
|
778
865
|
clientId,
|
|
779
|
-
|
|
780
|
-
|
|
866
|
+
type,
|
|
867
|
+
data,
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
if (fn(entry, index)) {
|
|
871
|
+
results.push(entry)
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
index += 1
|
|
781
875
|
}
|
|
782
876
|
|
|
783
|
-
index
|
|
877
|
+
return index
|
|
784
878
|
}
|
|
785
879
|
|
|
880
|
+
let index = 0
|
|
881
|
+
|
|
882
|
+
sweepInactiveSessions(state)
|
|
883
|
+
|
|
884
|
+
index = processSessions(SessionType.Active, filter, index)
|
|
885
|
+
index = processSessions(SessionType.Inactive, filter, index)
|
|
886
|
+
|
|
786
887
|
return results
|
|
787
888
|
},
|
|
788
889
|
}
|