@pelican.ts/sdk 0.4.12 → 0.4.14
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/dist/api/index.d.mts +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +1 -1
- package/dist/api/index.mjs +1 -1
- package/dist/index.d.mts +139 -139
- package/dist/index.d.ts +139 -139
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/types.d.ts +258 -258
- package/package.json +1 -1
- package/.husky/pre-commit +0 -2
- package/scripts/create-types.ts +0 -24
- package/src/api/application/client.ts +0 -70
- package/src/api/application/database_hosts.ts +0 -65
- package/src/api/application/eggs.ts +0 -43
- package/src/api/application/mounts.ts +0 -109
- package/src/api/application/nodes.ts +0 -126
- package/src/api/application/nodes_allocations.ts +0 -47
- package/src/api/application/roles.ts +0 -39
- package/src/api/application/servers.ts +0 -145
- package/src/api/application/servers_databases.ts +0 -53
- package/src/api/application/types/container.ts +0 -9
- package/src/api/application/types/database_host.ts +0 -11
- package/src/api/application/types/egg.ts +0 -65
- package/src/api/application/types/index.ts +0 -10
- package/src/api/application/types/location.ts +0 -7
- package/src/api/application/types/mount.ts +0 -12
- package/src/api/application/types/node.ts +0 -58
- package/src/api/application/types/role.ts +0 -6
- package/src/api/application/types/server.ts +0 -24
- package/src/api/application/types/server_allocation.ts +0 -20
- package/src/api/application/types/user.ts +0 -34
- package/src/api/application/users.ts +0 -146
- package/src/api/base/request.ts +0 -44
- package/src/api/base/types.ts +0 -40
- package/src/api/client/account.ts +0 -77
- package/src/api/client/client.ts +0 -56
- package/src/api/client/server.ts +0 -74
- package/src/api/client/server_activity.ts +0 -25
- package/src/api/client/server_allocations.ts +0 -50
- package/src/api/client/server_backups.ts +0 -82
- package/src/api/client/server_databases.ts +0 -51
- package/src/api/client/server_files.ts +0 -145
- package/src/api/client/server_schedules.ts +0 -130
- package/src/api/client/server_settings.ts +0 -36
- package/src/api/client/server_startup.ts +0 -41
- package/src/api/client/server_users.ts +0 -55
- package/src/api/client/server_websocket.ts +0 -570
- package/src/api/client/types/index.ts +0 -5
- package/src/api/client/types/server.ts +0 -72
- package/src/api/client/types/server_allocation.ts +0 -10
- package/src/api/client/types/server_subuser.ts +0 -55
- package/src/api/client/types/user.ts +0 -31
- package/src/api/client/types/websocket.ts +0 -138
- package/src/api/common/types/egg.ts +0 -9
- package/src/api/common/types/enums.ts +0 -21
- package/src/api/common/types/index.ts +0 -9
- package/src/api/common/types/server_backup.ts +0 -13
- package/src/api/common/types/server_database.ts +0 -13
- package/src/api/common/types/server_files.ts +0 -11
- package/src/api/common/types/server_limits.ts +0 -18
- package/src/api/common/types/server_power.ts +0 -1
- package/src/api/common/types/server_schedule.ts +0 -37
- package/src/api/common/types/server_startup.ts +0 -11
- package/src/api/index.ts +0 -17
- package/src/humane/Account.ts +0 -60
- package/src/humane/Client.ts +0 -44
- package/src/humane/Server.ts +0 -206
- package/src/humane/ServerAllocation.ts +0 -41
- package/src/humane/ServerBackup.ts +0 -44
- package/src/humane/ServerDatabase.ts +0 -37
- package/src/humane/ServerFile.ts +0 -91
- package/src/humane/ServerSchedule.ts +0 -160
- package/src/humane/ServerUser.ts +0 -44
- package/src/index.ts +0 -21
- package/src/types.ts +0 -3
- package/src/utils/sized.ts +0 -13
- package/src/utils/transform.ts +0 -21
- package/src/utils/types.ts +0 -10
|
@@ -1,570 +0,0 @@
|
|
|
1
|
-
import {AxiosInstance} from "axios"
|
|
2
|
-
import {EventEmitter} from "events"
|
|
3
|
-
import WebSocket from "isomorphic-ws"
|
|
4
|
-
import stripColor from "strip-color"
|
|
5
|
-
import {
|
|
6
|
-
BackupCompletedJson,
|
|
7
|
-
PowerState,
|
|
8
|
-
SOCKET_EVENT,
|
|
9
|
-
StatsWsJson,
|
|
10
|
-
WebsocketEvent
|
|
11
|
-
} from "@/api/client/types/websocket"
|
|
12
|
-
import {ServerSignalOption} from "@/api/common/types/server_power"
|
|
13
|
-
|
|
14
|
-
const isBrowser = typeof window !== "undefined"
|
|
15
|
-
|
|
16
|
-
type WebsocketHandshakePayload = {data: {token: string; socket: string}}
|
|
17
|
-
|
|
18
|
-
type SocketEventPayloadMap = {
|
|
19
|
-
[SOCKET_EVENT.AUTH_SUCCESS]: undefined
|
|
20
|
-
[SOCKET_EVENT.STATUS]: PowerState
|
|
21
|
-
[SOCKET_EVENT.CONSOLE_OUTPUT]: string
|
|
22
|
-
[SOCKET_EVENT.STATS]: StatsWsJson
|
|
23
|
-
[SOCKET_EVENT.DAEMON_ERROR]: undefined
|
|
24
|
-
[SOCKET_EVENT.DAEMON_MESSAGE]: string
|
|
25
|
-
[SOCKET_EVENT.INSTALL_OUTPUT]: string
|
|
26
|
-
[SOCKET_EVENT.INSTALL_STARTED]: undefined
|
|
27
|
-
[SOCKET_EVENT.INSTALL_COMPLETED]: undefined
|
|
28
|
-
[SOCKET_EVENT.TRANSFER_LOGS]: string
|
|
29
|
-
[SOCKET_EVENT.TRANSFER_STATUS]: string
|
|
30
|
-
[SOCKET_EVENT.BACKUP_COMPLETED]: BackupCompletedJson
|
|
31
|
-
[SOCKET_EVENT.BACKUP_RESTORE_COMPLETED]: undefined
|
|
32
|
-
[SOCKET_EVENT.TOKEN_EXPIRING]: undefined
|
|
33
|
-
[SOCKET_EVENT.TOKEN_EXPIRED]: undefined
|
|
34
|
-
[SOCKET_EVENT.JWT_ERROR]: string
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
type Listener<E extends SOCKET_EVENT> =
|
|
38
|
-
SocketEventPayloadMap[E] extends undefined
|
|
39
|
-
? () => void
|
|
40
|
-
: (payload: SocketEventPayloadMap[E]) => void
|
|
41
|
-
|
|
42
|
-
type MessageEventLike = {data?: unknown}
|
|
43
|
-
|
|
44
|
-
type CloseEventLike = Parameters<NonNullable<WebSocket["onclose"]>>[0]
|
|
45
|
-
|
|
46
|
-
type ErrorEventLike = Parameters<NonNullable<WebSocket["onerror"]>>[0]
|
|
47
|
-
|
|
48
|
-
const RECONNECT_ERRORS = new Set([
|
|
49
|
-
"jwt: exp claim is invalid",
|
|
50
|
-
"jwt: created too far in past (denylist)"
|
|
51
|
-
])
|
|
52
|
-
|
|
53
|
-
const FALLBACK_LOG_MESSAGE = "No logs - is the server online?"
|
|
54
|
-
|
|
55
|
-
export class ServerWebsocket {
|
|
56
|
-
private readonly r: AxiosInstance
|
|
57
|
-
private readonly serverId: string
|
|
58
|
-
private socket?: WebSocket
|
|
59
|
-
private currentToken?: string
|
|
60
|
-
private readonly bus = new EventEmitter()
|
|
61
|
-
private debugLogging = false
|
|
62
|
-
private stripColors: boolean
|
|
63
|
-
private detachMessageListener?: () => void
|
|
64
|
-
|
|
65
|
-
constructor(
|
|
66
|
-
requester: AxiosInstance,
|
|
67
|
-
id: string,
|
|
68
|
-
stripColors: boolean = false
|
|
69
|
-
) {
|
|
70
|
-
this.r = requester
|
|
71
|
-
this.serverId = id
|
|
72
|
-
this.stripColors = stripColors
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
public on<E extends SOCKET_EVENT>(
|
|
76
|
-
event: E,
|
|
77
|
-
listener: Listener<E>
|
|
78
|
-
): () => void {
|
|
79
|
-
const handler = listener as (...args: unknown[]) => void
|
|
80
|
-
this.bus.on(event, handler)
|
|
81
|
-
return () => {
|
|
82
|
-
this.bus.removeListener(event, handler)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
public deregister<E extends SOCKET_EVENT>(
|
|
87
|
-
event: E,
|
|
88
|
-
listener: Listener<E>
|
|
89
|
-
): void {
|
|
90
|
-
const handler = listener as (...args: unknown[]) => void
|
|
91
|
-
this.bus.removeListener(event, handler)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
private emit<E extends SOCKET_EVENT>(
|
|
95
|
-
event: E,
|
|
96
|
-
...args: SocketEventPayloadMap[E] extends undefined
|
|
97
|
-
? []
|
|
98
|
-
: [SocketEventPayloadMap[E]]
|
|
99
|
-
): void {
|
|
100
|
-
if (args.length === 0) {
|
|
101
|
-
this.bus.emit(event)
|
|
102
|
-
} else {
|
|
103
|
-
this.bus.emit(event, args[0])
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
public async connect(
|
|
108
|
-
resumable?: boolean,
|
|
109
|
-
debugLogging?: boolean
|
|
110
|
-
): Promise<void> {
|
|
111
|
-
this.debugLogging = debugLogging ?? false
|
|
112
|
-
|
|
113
|
-
if (this.socket) {
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const socketUrl = await this.refreshCredentials()
|
|
118
|
-
|
|
119
|
-
this.socket = isBrowser
|
|
120
|
-
? new WebSocket(socketUrl)
|
|
121
|
-
: new WebSocket(socketUrl, undefined, {
|
|
122
|
-
origin: new URL(socketUrl).origin
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
await new Promise<void>((resolve, reject) => {
|
|
126
|
-
const socket = this.socket
|
|
127
|
-
if (!socket) {
|
|
128
|
-
reject(new Error("Failed to create socket connection"))
|
|
129
|
-
return
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
socket.onopen = async () => {
|
|
133
|
-
try {
|
|
134
|
-
await this.authenticate()
|
|
135
|
-
this.attachMessageListener()
|
|
136
|
-
socket.onopen = null
|
|
137
|
-
socket.onerror = null
|
|
138
|
-
resolve()
|
|
139
|
-
} catch (error) {
|
|
140
|
-
socket.onopen = null
|
|
141
|
-
socket.onerror = null
|
|
142
|
-
reject(
|
|
143
|
-
error instanceof Error
|
|
144
|
-
? error
|
|
145
|
-
: new Error("Websocket authentication failed")
|
|
146
|
-
)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
socket.onerror = (event: ErrorEventLike) => {
|
|
151
|
-
socket.onopen = null
|
|
152
|
-
socket.onerror = null
|
|
153
|
-
reject(
|
|
154
|
-
event instanceof Error
|
|
155
|
-
? event
|
|
156
|
-
: new Error("Websocket connection error")
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
if (resumable) {
|
|
162
|
-
this.makeResumable(true)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
public onSocketDisconnect(handler: (event: CloseEventLike) => void): void {
|
|
167
|
-
if (!this.socket) {
|
|
168
|
-
console.error(new Error("No socket connection"))
|
|
169
|
-
return
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
this.socket.onclose = handler
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
public onSocketError(handler: (event: ErrorEventLike) => void): void {
|
|
176
|
-
if (!this.socket) {
|
|
177
|
-
console.error(new Error("No socket connection"))
|
|
178
|
-
return
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
this.socket.onerror = handler
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
public makeResumable(disconnectsToo: boolean): void {
|
|
185
|
-
const scheduleReconnect = () => {
|
|
186
|
-
setTimeout(() => {
|
|
187
|
-
const previous = this.socket
|
|
188
|
-
this.detachMessageListener?.()
|
|
189
|
-
this.detachMessageListener = undefined
|
|
190
|
-
this.socket = undefined
|
|
191
|
-
previous?.close()
|
|
192
|
-
void this.connect(true, this.debugLogging)
|
|
193
|
-
}, 1000)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
this.onSocketError(() => scheduleReconnect())
|
|
197
|
-
|
|
198
|
-
if (disconnectsToo) {
|
|
199
|
-
this.onSocketDisconnect(() => scheduleReconnect())
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
private attachMessageListener(): void {
|
|
204
|
-
if (!this.socket) {
|
|
205
|
-
throw new Error("No socket connection")
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
this.detachMessageListener?.()
|
|
209
|
-
|
|
210
|
-
const handler = (event: unknown) => {
|
|
211
|
-
void this.handleIncomingMessage(event)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (typeof this.socket.addEventListener === "function") {
|
|
215
|
-
this.socket.addEventListener(
|
|
216
|
-
"message",
|
|
217
|
-
handler as (event: MessageEventLike) => void
|
|
218
|
-
)
|
|
219
|
-
this.detachMessageListener = () => {
|
|
220
|
-
this.socket?.removeEventListener?.(
|
|
221
|
-
"message",
|
|
222
|
-
handler as (event: MessageEventLike) => void
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
const fallback = (data: unknown) =>
|
|
227
|
-
handler({data} satisfies MessageEventLike)
|
|
228
|
-
const socket = this.socket as unknown as {
|
|
229
|
-
on?: (event: string, listener: (data: unknown) => void) => void
|
|
230
|
-
off?: (event: string, listener: (data: unknown) => void) => void
|
|
231
|
-
removeListener?: (
|
|
232
|
-
event: string,
|
|
233
|
-
listener: (data: unknown) => void
|
|
234
|
-
) => void
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
socket.on?.("message", fallback)
|
|
238
|
-
this.detachMessageListener = () => {
|
|
239
|
-
const target = this.socket as unknown as
|
|
240
|
-
| typeof socket
|
|
241
|
-
| undefined
|
|
242
|
-
if (!target) {
|
|
243
|
-
return
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (typeof target.off === "function") {
|
|
247
|
-
target.off("message", fallback)
|
|
248
|
-
} else if (typeof target.removeListener === "function") {
|
|
249
|
-
target.removeListener("message", fallback)
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
private async handleIncomingMessage(event: unknown): Promise<void> {
|
|
256
|
-
const message = this.parseMessage(event)
|
|
257
|
-
if (!message) {
|
|
258
|
-
return
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
try {
|
|
262
|
-
await this.dispatchMessage(message)
|
|
263
|
-
} catch (error) {
|
|
264
|
-
if (this.debugLogging) {
|
|
265
|
-
console.error("Error while handling websocket message", error)
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
private parseMessage(event: unknown): WebsocketEvent | null {
|
|
271
|
-
const payload = this.normalisePayload(event)
|
|
272
|
-
if (!payload) {
|
|
273
|
-
return null
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
try {
|
|
277
|
-
return JSON.parse(payload) as WebsocketEvent
|
|
278
|
-
} catch (error) {
|
|
279
|
-
if (this.debugLogging) {
|
|
280
|
-
console.warn("Failed to parse websocket payload", error)
|
|
281
|
-
}
|
|
282
|
-
return null
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
private normalisePayload(event: unknown): string | null {
|
|
287
|
-
if (typeof event === "string") {
|
|
288
|
-
return event
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (typeof event === "object" && event !== null && "data" in event) {
|
|
292
|
-
return this.normalisePayload((event as MessageEventLike).data)
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (typeof Buffer !== "undefined" && Buffer.isBuffer(event)) {
|
|
296
|
-
return event.toString("utf8")
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (
|
|
300
|
-
typeof ArrayBuffer !== "undefined"
|
|
301
|
-
&& event instanceof ArrayBuffer
|
|
302
|
-
) {
|
|
303
|
-
if (typeof TextDecoder !== "undefined") {
|
|
304
|
-
return new TextDecoder().decode(new Uint8Array(event))
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (typeof Buffer !== "undefined") {
|
|
308
|
-
return Buffer.from(event).toString("utf8")
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return null
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
private async dispatchMessage(message: WebsocketEvent): Promise<void> {
|
|
316
|
-
switch (message.event) {
|
|
317
|
-
case SOCKET_EVENT.AUTH_SUCCESS: {
|
|
318
|
-
if (this.debugLogging) {
|
|
319
|
-
console.debug("Auth success")
|
|
320
|
-
}
|
|
321
|
-
this.emit(SOCKET_EVENT.AUTH_SUCCESS)
|
|
322
|
-
break
|
|
323
|
-
}
|
|
324
|
-
case SOCKET_EVENT.STATUS: {
|
|
325
|
-
if (this.debugLogging) {
|
|
326
|
-
console.debug("Received status event", message.args[0])
|
|
327
|
-
}
|
|
328
|
-
this.emit(SOCKET_EVENT.STATUS, message.args[0])
|
|
329
|
-
break
|
|
330
|
-
}
|
|
331
|
-
case SOCKET_EVENT.CONSOLE_OUTPUT: {
|
|
332
|
-
let output = message.args[0]
|
|
333
|
-
if (this.stripColors) {
|
|
334
|
-
output = stripColor(output)
|
|
335
|
-
}
|
|
336
|
-
if (this.debugLogging) {
|
|
337
|
-
console.debug("Received console output", output)
|
|
338
|
-
}
|
|
339
|
-
this.emit(SOCKET_EVENT.CONSOLE_OUTPUT, output)
|
|
340
|
-
break
|
|
341
|
-
}
|
|
342
|
-
case SOCKET_EVENT.STATS: {
|
|
343
|
-
try {
|
|
344
|
-
const payload = JSON.parse(message.args[0]) as StatsWsJson
|
|
345
|
-
this.emit(SOCKET_EVENT.STATS, payload)
|
|
346
|
-
} catch (error) {
|
|
347
|
-
if (this.debugLogging) {
|
|
348
|
-
console.warn("Failed to parse stats payload", error)
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
break
|
|
352
|
-
}
|
|
353
|
-
case SOCKET_EVENT.DAEMON_ERROR: {
|
|
354
|
-
this.emit(SOCKET_EVENT.DAEMON_ERROR)
|
|
355
|
-
break
|
|
356
|
-
}
|
|
357
|
-
case SOCKET_EVENT.BACKUP_COMPLETED: {
|
|
358
|
-
try {
|
|
359
|
-
const payload = JSON.parse(
|
|
360
|
-
message.args[0]
|
|
361
|
-
) as BackupCompletedJson
|
|
362
|
-
this.emit(SOCKET_EVENT.BACKUP_COMPLETED, payload)
|
|
363
|
-
} catch (error) {
|
|
364
|
-
if (this.debugLogging) {
|
|
365
|
-
console.warn("Failed to parse backup payload", error)
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
break
|
|
369
|
-
}
|
|
370
|
-
case SOCKET_EVENT.DAEMON_MESSAGE: {
|
|
371
|
-
let output = message.args[0]
|
|
372
|
-
if (this.stripColors) {
|
|
373
|
-
output = stripColor(output)
|
|
374
|
-
}
|
|
375
|
-
this.emit(SOCKET_EVENT.DAEMON_MESSAGE, output)
|
|
376
|
-
break
|
|
377
|
-
}
|
|
378
|
-
case SOCKET_EVENT.INSTALL_OUTPUT: {
|
|
379
|
-
let output = message.args[0]
|
|
380
|
-
if (this.stripColors) {
|
|
381
|
-
output = stripColor(output)
|
|
382
|
-
}
|
|
383
|
-
this.emit(SOCKET_EVENT.INSTALL_OUTPUT, output)
|
|
384
|
-
break
|
|
385
|
-
}
|
|
386
|
-
case SOCKET_EVENT.BACKUP_RESTORE_COMPLETED: {
|
|
387
|
-
this.emit(SOCKET_EVENT.BACKUP_RESTORE_COMPLETED)
|
|
388
|
-
break
|
|
389
|
-
}
|
|
390
|
-
case SOCKET_EVENT.INSTALL_COMPLETED: {
|
|
391
|
-
this.emit(SOCKET_EVENT.INSTALL_COMPLETED)
|
|
392
|
-
break
|
|
393
|
-
}
|
|
394
|
-
case SOCKET_EVENT.INSTALL_STARTED: {
|
|
395
|
-
this.emit(SOCKET_EVENT.INSTALL_STARTED)
|
|
396
|
-
break
|
|
397
|
-
}
|
|
398
|
-
case SOCKET_EVENT.TRANSFER_LOGS: {
|
|
399
|
-
this.emit(SOCKET_EVENT.TRANSFER_LOGS, message.args[0])
|
|
400
|
-
break
|
|
401
|
-
}
|
|
402
|
-
case SOCKET_EVENT.TRANSFER_STATUS: {
|
|
403
|
-
this.emit(SOCKET_EVENT.TRANSFER_STATUS, message.args[0])
|
|
404
|
-
break
|
|
405
|
-
}
|
|
406
|
-
case SOCKET_EVENT.TOKEN_EXPIRING: {
|
|
407
|
-
this.emit(SOCKET_EVENT.TOKEN_EXPIRING)
|
|
408
|
-
if (this.debugLogging) {
|
|
409
|
-
console.warn("Token expiring, renewing...")
|
|
410
|
-
}
|
|
411
|
-
await this.refreshCredentials()
|
|
412
|
-
await this.authenticate()
|
|
413
|
-
break
|
|
414
|
-
}
|
|
415
|
-
case SOCKET_EVENT.TOKEN_EXPIRED: {
|
|
416
|
-
this.emit(SOCKET_EVENT.TOKEN_EXPIRED)
|
|
417
|
-
throw new Error("Token expired")
|
|
418
|
-
}
|
|
419
|
-
case SOCKET_EVENT.JWT_ERROR: {
|
|
420
|
-
const reason = message.args[0]
|
|
421
|
-
if (RECONNECT_ERRORS.has(reason)) {
|
|
422
|
-
this.emit(SOCKET_EVENT.TOKEN_EXPIRING)
|
|
423
|
-
if (this.debugLogging) {
|
|
424
|
-
console.warn("Token expiring (JWT error), renewing...")
|
|
425
|
-
}
|
|
426
|
-
await this.refreshCredentials()
|
|
427
|
-
await this.authenticate()
|
|
428
|
-
} else {
|
|
429
|
-
this.emit(SOCKET_EVENT.JWT_ERROR, reason)
|
|
430
|
-
throw new Error("Token expired")
|
|
431
|
-
}
|
|
432
|
-
break
|
|
433
|
-
}
|
|
434
|
-
default: {
|
|
435
|
-
if (this.debugLogging) {
|
|
436
|
-
console.warn("Unknown websocket event", message)
|
|
437
|
-
}
|
|
438
|
-
break
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
private async refreshCredentials(): Promise<string> {
|
|
444
|
-
const {data} = await this.r.get<WebsocketHandshakePayload>(
|
|
445
|
-
`/servers/${this.serverId}/websocket`
|
|
446
|
-
)
|
|
447
|
-
this.currentToken = data.data.token
|
|
448
|
-
return data.data.socket
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
private async authenticate(): Promise<void> {
|
|
452
|
-
if (!this.socket) {
|
|
453
|
-
throw new Error("No socket connection")
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (!this.currentToken) {
|
|
457
|
-
throw new Error("Missing websocket token")
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
this.socket.send(
|
|
461
|
-
JSON.stringify({event: "auth", args: [this.currentToken]})
|
|
462
|
-
)
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
public disconnect(): void {
|
|
466
|
-
this.detachMessageListener?.()
|
|
467
|
-
this.detachMessageListener = undefined
|
|
468
|
-
if (this.socket) {
|
|
469
|
-
this.socket.close()
|
|
470
|
-
this.socket = undefined
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
public requestStats(): void {
|
|
475
|
-
this.send("send stats", [null])
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
public requestLogs(): void {
|
|
479
|
-
this.send("send logs", [null])
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
private send(event: string, args: unknown[]): void {
|
|
483
|
-
if (!this.socket) {
|
|
484
|
-
if (this.debugLogging) {
|
|
485
|
-
console.warn(
|
|
486
|
-
`Attempted to send "${event}" without an active websocket connection`
|
|
487
|
-
)
|
|
488
|
-
}
|
|
489
|
-
return
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
this.socket.send(JSON.stringify({event, args}))
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
public getStats(): Promise<StatsWsJson> {
|
|
496
|
-
return new Promise((resolve, reject) => {
|
|
497
|
-
if (!this.socket) {
|
|
498
|
-
reject(new Error("No socket connection"))
|
|
499
|
-
return
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
let off: (() => void) | undefined
|
|
503
|
-
const timeout = setTimeout(() => {
|
|
504
|
-
off?.()
|
|
505
|
-
reject(new Error("Timed out waiting for stats"))
|
|
506
|
-
}, 5000)
|
|
507
|
-
|
|
508
|
-
off = this.on(SOCKET_EVENT.STATS, payload => {
|
|
509
|
-
clearTimeout(timeout)
|
|
510
|
-
off?.()
|
|
511
|
-
resolve(payload)
|
|
512
|
-
})
|
|
513
|
-
|
|
514
|
-
this.requestStats()
|
|
515
|
-
})
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
public getLogs(): Promise<string[]> {
|
|
519
|
-
return new Promise((resolve, reject) => {
|
|
520
|
-
if (!this.socket) {
|
|
521
|
-
reject(new Error("No socket connection"))
|
|
522
|
-
return
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
const lines: string[] = []
|
|
526
|
-
let off: (() => void) | undefined
|
|
527
|
-
let initialTimeout: ReturnType<typeof setTimeout> | undefined
|
|
528
|
-
let idleTimeout: ReturnType<typeof setTimeout> | undefined
|
|
529
|
-
|
|
530
|
-
const finalize = (payload: string[]) => {
|
|
531
|
-
off?.()
|
|
532
|
-
if (initialTimeout) {
|
|
533
|
-
clearTimeout(initialTimeout)
|
|
534
|
-
}
|
|
535
|
-
if (idleTimeout) {
|
|
536
|
-
clearTimeout(idleTimeout)
|
|
537
|
-
}
|
|
538
|
-
resolve(payload)
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
initialTimeout = setTimeout(() => {
|
|
542
|
-
finalize(lines.length > 0 ? lines : [FALLBACK_LOG_MESSAGE])
|
|
543
|
-
}, 5000)
|
|
544
|
-
|
|
545
|
-
off = this.on(SOCKET_EVENT.CONSOLE_OUTPUT, line => {
|
|
546
|
-
lines.push(line)
|
|
547
|
-
if (initialTimeout) {
|
|
548
|
-
clearTimeout(initialTimeout)
|
|
549
|
-
initialTimeout = undefined
|
|
550
|
-
}
|
|
551
|
-
if (idleTimeout) {
|
|
552
|
-
clearTimeout(idleTimeout)
|
|
553
|
-
}
|
|
554
|
-
idleTimeout = setTimeout(() => {
|
|
555
|
-
finalize(lines)
|
|
556
|
-
}, 1000)
|
|
557
|
-
})
|
|
558
|
-
|
|
559
|
-
this.requestLogs()
|
|
560
|
-
})
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
public sendPoweraction(action: ServerSignalOption): void {
|
|
564
|
-
this.send("set state", [action])
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
public sendCommand(cmd: string): void {
|
|
568
|
-
this.send("send command", [cmd])
|
|
569
|
-
}
|
|
570
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import {GenericListResponse, GenericResponse} from "@/api/base/types"
|
|
2
|
-
import {EggVariable} from "@/api/common/types/egg"
|
|
3
|
-
import {ServerSubuser} from "@/api/client/types/server_subuser"
|
|
4
|
-
import {FeatureLimits, ServerLimits} from "@/api/common/types/server_limits"
|
|
5
|
-
import {ServerAllocation} from "@/api/client/types/server_allocation"
|
|
6
|
-
import {Nullable} from "@/utils/types"
|
|
7
|
-
|
|
8
|
-
export type Server = {
|
|
9
|
-
server_owner: boolean
|
|
10
|
-
identifier: string
|
|
11
|
-
internal_id?: number
|
|
12
|
-
uuid: string
|
|
13
|
-
name: string
|
|
14
|
-
node: string
|
|
15
|
-
is_node_under_maintenance: boolean
|
|
16
|
-
sftp_details: {ip: string; alias: Nullable<string>; port: number}
|
|
17
|
-
description: string
|
|
18
|
-
limits: ServerLimits
|
|
19
|
-
invocation: string
|
|
20
|
-
docker_image: string
|
|
21
|
-
egg_features: Nullable<string[]>
|
|
22
|
-
feature_limits: FeatureLimits
|
|
23
|
-
status: Nullable<unknown>
|
|
24
|
-
is_suspended: boolean
|
|
25
|
-
is_installing: boolean
|
|
26
|
-
is_transferring: boolean
|
|
27
|
-
relationships: {
|
|
28
|
-
allocations: GenericListResponse<
|
|
29
|
-
GenericResponse<ServerAllocation, "allocation">
|
|
30
|
-
>
|
|
31
|
-
variables: GenericListResponse<
|
|
32
|
-
GenericResponse<EggVariable, "egg_variable">
|
|
33
|
-
>
|
|
34
|
-
egg?: GenericResponse<{uuid: string; name: string}, "egg">
|
|
35
|
-
subusers?: GenericListResponse<
|
|
36
|
-
GenericResponse<ServerSubuser, "server_subuser">
|
|
37
|
-
>
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export type ServerStats = {
|
|
42
|
-
current_state:
|
|
43
|
-
| "installing"
|
|
44
|
-
| "install_failed"
|
|
45
|
-
| "reinstall_failed"
|
|
46
|
-
| "suspended"
|
|
47
|
-
| "restoring_backup"
|
|
48
|
-
| "running"
|
|
49
|
-
| "stopped"
|
|
50
|
-
| "offline"
|
|
51
|
-
is_suspended: boolean
|
|
52
|
-
resources: ServerResources
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
type ServerResources = {
|
|
56
|
-
memory_bytes: number
|
|
57
|
-
cpu_absolute: number
|
|
58
|
-
disk_bytes: number
|
|
59
|
-
network_tx_bytes: number
|
|
60
|
-
network_rx_bytes: number
|
|
61
|
-
uptime: number
|
|
62
|
-
}
|
|
63
|
-
export type ServerActivityLog = {
|
|
64
|
-
id: string
|
|
65
|
-
event: string
|
|
66
|
-
is_api: boolean
|
|
67
|
-
ip: string
|
|
68
|
-
description: Nullable<string>
|
|
69
|
-
properties: Record<string, string>
|
|
70
|
-
has_additional_metadata: boolean
|
|
71
|
-
timestamp: string
|
|
72
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
export type ServerSubuser = {
|
|
2
|
-
uuid: string
|
|
3
|
-
username: string
|
|
4
|
-
email: string
|
|
5
|
-
language: string
|
|
6
|
-
image: string
|
|
7
|
-
admin: false
|
|
8
|
-
root_admin: false
|
|
9
|
-
"2fa_enabled": boolean
|
|
10
|
-
created_at: string
|
|
11
|
-
permissions: SubuserPermission[] | string[]
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type SubuserPermission =
|
|
15
|
-
| "activity.read"
|
|
16
|
-
| "allocation.create"
|
|
17
|
-
| "allocation.delete"
|
|
18
|
-
| "allocation.read"
|
|
19
|
-
| "allocation.update"
|
|
20
|
-
| "backup.create"
|
|
21
|
-
| "backup.delete"
|
|
22
|
-
| "backup.download"
|
|
23
|
-
| "backup.read"
|
|
24
|
-
| "backup.restore"
|
|
25
|
-
| "control.console"
|
|
26
|
-
| "control.restart"
|
|
27
|
-
| "control.start"
|
|
28
|
-
| "control.stop"
|
|
29
|
-
| "database.create"
|
|
30
|
-
| "database.delete"
|
|
31
|
-
| "database.read"
|
|
32
|
-
| "database.update"
|
|
33
|
-
| "database.view-password"
|
|
34
|
-
| "file.archive"
|
|
35
|
-
| "file.create"
|
|
36
|
-
| "file.delete"
|
|
37
|
-
| "file.read"
|
|
38
|
-
| "file.read-content"
|
|
39
|
-
| "file.sftp"
|
|
40
|
-
| "file.update"
|
|
41
|
-
| "schedule.create"
|
|
42
|
-
| "schedule.delete"
|
|
43
|
-
| "schedule.read"
|
|
44
|
-
| "schedule.update"
|
|
45
|
-
| "settings.description"
|
|
46
|
-
| "settings.reinstall"
|
|
47
|
-
| "settings.rename"
|
|
48
|
-
| "startup.docker-image"
|
|
49
|
-
| "startup.read"
|
|
50
|
-
| "startup.update"
|
|
51
|
-
| "user.create"
|
|
52
|
-
| "user.delete"
|
|
53
|
-
| "user.read"
|
|
54
|
-
| "user.update"
|
|
55
|
-
| "websocket.connect"
|