-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathwebsocket.ts
More file actions
87 lines (66 loc) · 2.29 KB
/
Copy pathwebsocket.ts
File metadata and controls
87 lines (66 loc) · 2.29 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
import EventEmitter from "node:events";
import WebSocket from "isomorphic-ws";
import type TypedEventEmitter from "typed-emitter";
import type { VRChat } from "./client";
import type { Events } from "./events";
import { log } from "./lib/log";
const logWebsocket = log.extend("websocket");
const baseUrl = "wss://pipeline.vrchat.cloud";
export interface VRChatWebsocketOptions {
baseUrl?: string;
headers?: Headers;
authToken?: string;
}
export class VRChatWebsocket extends (EventEmitter as new () => TypedEventEmitter<Events>) {
private url!: URL;
private websocket?: WebSocket;
public constructor(
public readonly options: VRChatWebsocketOptions = {},
private readonly vrchat?: VRChat
) {
super();
this.url = new URL(this.options.baseUrl ?? baseUrl);
if (options.authToken)
this.authenticate(options.authToken);
process.on("beforeExit", () => this.close());
process.on("SIGINT", () => this.close());
}
public get connected(): boolean {
return this.websocket?.readyState === WebSocket.OPEN;
}
public close(): void {
if (!this.websocket || this.websocket.readyState === WebSocket.CLOSED)
return;
logWebsocket("%s()", this.close.name);
this.websocket.close();
}
public async authenticate(authToken: string): Promise<void> {
logWebsocket("%s(authToken: \"%s\")", this.authenticate.name, authToken);
this.close();
this.url.searchParams.set("authToken", authToken);
this.websocket = new WebSocket(this.url, {
headers: Object.fromEntries(this.options.headers?.entries() ?? [])
});
this.websocket.addEventListener("open", (event: WebSocket.Event) => {
logWebsocket("%s", event.type);
});
this.websocket.addEventListener("close", (event: WebSocket.CloseEvent) => {
logWebsocket("%s: %s", event.type, event.reason);
});
this.websocket.addEventListener("error", (event: WebSocket.ErrorEvent) => {
logWebsocket("%s: %O", event.type, event.error);
});
this.websocket.addEventListener("message", (event: WebSocket.MessageEvent) => {
try {
const { type, content: _content } = JSON.parse(event.data.toString());
const content = JSON.parse(_content);
logWebsocket("%s: %O", type, content);
this.emit(type, content);
}
catch (reason) {
logWebsocket("Malformed message: %O", event.data);
logWebsocket(reason);
}
});
}
}