-
-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathsocket.ts
More file actions
135 lines (100 loc) · 3.49 KB
/
socket.ts
File metadata and controls
135 lines (100 loc) · 3.49 KB
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
import { camelCase } from 'lodash'
import WebSocket from 'ws'
import IWSEvent from './event'
import WSMessage from './message'
import Room from '../../../models/room'
import User from '../../../models/user'
import client from '../../../config/redis.config'
import config from '../../../config/defaults'
import { verifyToken } from '../../../utils/generate.utils'
import { extractUserId, UNALLOCATED_PORTALS_KEYS } from '../../../utils/helpers.utils'
import log from '../../../utils/log.utils'
import { WSLogPrefix } from '../log'
type SocketConfigKey = 'id' | 'type' | 'user' | 'group' | 'authenticated' | 'last_heartbeat_at' | 'last_user_refresh'
const socketKeys: SocketConfigKey[] = ['id', 'type', 'user', 'group', 'authenticated', 'last_heartbeat_at', 'last_user_refresh']
export default class WSSocket {
public id: string
public user?: User
public room?: Room
public authenticated: boolean = false
public lastHeartbeatAt: number
public lastUserRefresh?: Date
private socket: WebSocket
constructor(socket: WebSocket) {
this.socket = socket
socketKeys.forEach(key => {
if (socket[key])
this[camelCase(key)] = socket[key]
})
}
public set(key: SocketConfigKey, value: any, save: boolean = true) {
this.socket[key] = value
this[camelCase(key)] = value
if (save) this.save()
}
public save() {
const { id, authenticated, lastHeartbeatAt } = this
if (!id)
return
client.hset('client_sessions', id, JSON.stringify({ id, authenticated, lastHeartbeatAt }))
}
public send = (message: WSMessage) => this.socket.send(JSON.stringify(message.serialize()))
public authenticate = async (_token: string) => {
const { id } = verifyToken(_token) as { id: string }
try {
const user = await new User().load(id)
if (!user)
return
// Set user
this.set('user', user)
this.set('last_user_refresh', new Date())
// Presence Update
if (user.room) {
const { room } = user as { room: Room }
const message = new WSMessage(0, { u: user.id, presence: 'online' }, 'PRESENCE_UPDATE')
message.broadcastRoom(room, [user.id])
if (room.portal.status !== 'open') {
room.fetchMembers().then(({ members }) => {
if (
members.length > (config.min_member_portal_creation_count - 1) &&
UNALLOCATED_PORTALS_KEYS.indexOf(room.portal.status) > -1
)
room.createPortal()
})
} else if (room.portal.id) {
const janusMessage = new WSMessage(0, { id: room.portal.janusId }, 'JANUS_CONFIG')
janusMessage.broadcast([ extractUserId(user) ])
}
}
// Log update
log(`Authenticated user ${user.name} (${user.id})`, [WSLogPrefix, { content: 'auth', color: 'GREEN' }], 'CYAN')
this.sendUndeliverableMessages()
} catch (error) {
return this.socket.close(1013)
}
const save = false
this.set('id', id, save)
this.set('last_heartbeat_at', Date.now(), save)
this.set('authenticated', true, save)
try {
await client.sadd('connected_clients', id)
} catch (error) {
console.error(error)
}
if (!save)
this.save()
}
public close = (code: number) => this.socket.close(code)
private sendUndeliverableMessages = async () => {
try {
const _undelivered = await client.hget('undelivered_events', this.id)
let undelivered: IWSEvent[] = []
if (_undelivered)
undelivered = JSON.parse(_undelivered)
undelivered.forEach((event, s) => this.socket.send(JSON.stringify({ ...event, s })))
client.hset('undelivered_events', this.id, JSON.stringify([]))
} catch (error) {
console.error(error)
}
}
}