wispjs 2.4.0 → 3.0.1

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.
@@ -1,369 +0,0 @@
1
- import { io, Socket } from "socket.io-client";
2
-
3
- const WISP_DEBUG = process.env.WISP_DEBUG === "true";
4
-
5
- type Logger = {
6
- log(...args: any[]): void;
7
- error(...args: any[]): void;
8
- debug(...args: any[]): void;
9
- }
10
-
11
- /**
12
- * The struct used to define the events that can be sent from the server to the client
13
- *
14
- * @internal
15
- */
16
- export interface ServerToClientEvents {
17
- "error": (message: string) => void;
18
- "auth_success": (message: string) => void;
19
- "filesearch-results": (data: FilesearchResults) => void;
20
- "git-error": (data: string) => void;
21
- "git-success": (message?: string) => void;
22
- "git-clone": (data: GitCloneData) => void;
23
- "git-pull": (data: GitPullData) => void;
24
- "console": (message: ConsoleMessage) => void;
25
- "initial status": (message: any) => void;
26
- }
27
-
28
-
29
- /**
30
- * The struct used to define the events that can be sent from the client to the server
31
- *
32
- * @internal
33
- */
34
- export interface ClientToServerEvents {
35
- "auth": (token: string) => void;
36
- "filesearch-start": (query: string) => void;
37
- "git-clone": (data: GitCloneData) => void;
38
- "git-pull": (data: GitPullData) => void;
39
- "send command": (command: string) => void;
40
- }
41
-
42
-
43
- /**
44
- * The struct sent from the server containing console messages
45
- *
46
- * @param type The type of message. Currently unknown what varients exist
47
- * @param line The actual content of the console messages
48
- *
49
- * @internal
50
- */
51
- export interface ConsoleMessage {
52
- type: string;
53
- line: string;
54
- }
55
-
56
-
57
- /**
58
- * Struct used to initiate a Git Clone action
59
- *
60
- * @param dir The directory to clone into
61
- * @param url The HTTPS URL to clone
62
- * @param branch The repository branch
63
- * @param authkey The authentication key to use when pulling
64
- *
65
- * @internal
66
- */
67
- export interface GitCloneData {
68
- dir: string;
69
- url: string;
70
- branch: string;
71
- authkey?: string | undefined;
72
- }
73
-
74
-
75
- /**
76
- * Return struct after finishing a Git Clone action
77
- *
78
- * @param isPrivate Whether or not the repository is private
79
- *
80
- * @internal
81
- */
82
- export interface GitCloneResult {
83
- isPrivate: boolean;
84
- }
85
-
86
-
87
- /**
88
- * Struct used to initiate a Git Pull action
89
- *
90
- * @param dir The directory to pull
91
- * @param authkey The authentication key to use when pulling
92
- *
93
- * @internal
94
- */
95
- export interface GitPullData {
96
- dir: string;
97
- authkey?: string;
98
- }
99
-
100
-
101
- /**
102
- * Struct returned after a Git Pull action finishes
103
- *
104
- * @param output The actual output
105
- * @param isPrivate Whether or not the repository is private
106
- *
107
- * @internal
108
- */
109
- export interface GitPullResult {
110
- output: string;
111
- isPrivate: boolean;
112
- }
113
-
114
-
115
- /**
116
- * An individual filesearch result
117
- *
118
- * @param results How many results are present in the file
119
- * @param lines A map of line numbers to their contents. These lines include nearby context of matched lines
120
- *
121
- * @internal
122
- */
123
- export interface FilesearchFile {
124
- results: number;
125
- lines: {[key: string]: string};
126
- }
127
-
128
-
129
- /**
130
- * The results of a file search
131
- *
132
- * @param files A map of file names to matched+context lines within each file
133
- * @param tooMany Whether or not there were too many results to display
134
- *
135
- * @internal
136
- */
137
- export interface FilesearchResults {
138
- files: {[key: string]: FilesearchFile};
139
- tooMany: boolean;
140
- }
141
-
142
-
143
- /**
144
- * The events that can be sent from the server to the client
145
- * @internal
146
- */
147
- export type WispWebsocket = Socket<ServerToClientEvents, ClientToServerEvents>;
148
-
149
-
150
- /**
151
- * A single worker in the Websocket Pool
152
- *
153
- * @internal
154
- */
155
- interface PoolWorker {
156
- pool: WebsocketPool;
157
- socket: WispWebsocket;
158
- idx: number;
159
- token: string;
160
- ready: boolean;
161
- done: boolean;
162
- logger: Logger;
163
- }
164
-
165
-
166
- /**
167
- * A single Worker within a {@link WebsocketPool}
168
- *
169
- * @param pool The pool this worker is a part of
170
- *
171
- * @internal
172
- */
173
- class PoolWorker {
174
- constructor(pool: WebsocketPool) {
175
- this.pool = pool
176
- this.ready = false
177
- this.done = false
178
-
179
- this.idx = pool.workers.length
180
- this.token = pool.token
181
- this.socket = io(pool.url, {
182
- forceNew: true,
183
- transports: ["websocket"],
184
- addTrailingSlash: true,
185
- autoConnect: false
186
- })
187
-
188
- const logPrefix = `[Worker #${this.idx}]`
189
- this.logger = {
190
- log: (...args: any[]) => console.log(logPrefix, args),
191
- error: (...args: any[]) => console.error(logPrefix, args),
192
- debug: (...args: any[]) => {
193
- if (!WISP_DEBUG) return;
194
- console.debug(logPrefix, args)
195
- }
196
- }
197
-
198
- this.connect().then(() => this.processWork()).catch(err => this.logger.error(err))
199
- }
200
-
201
- connect() {
202
- const socket = this.socket
203
- const logger = this.logger
204
-
205
- socket.onAnyOutgoing(this.logger.log)
206
-
207
- logger.log("Connecting to websocket...")
208
-
209
- return new Promise<void>((resolve, reject) => {
210
- const timeout = setTimeout(() => {
211
- logger.error("Socket didn't connect in time")
212
- reject("Connection Timeout")
213
- }, 10000)
214
-
215
- socket.on("connect", () => {
216
- logger.log("Connected to WebSocket")
217
- logger.log("Emitting:", "auth", this.token)
218
- socket.emit("auth", this.token)
219
- })
220
-
221
- socket.on("error", (reason: string) => {
222
- logger.error(`WebSocket error: ${reason}`)
223
- })
224
-
225
- socket.on("connect_error", (error: Error) => {
226
- logger.error(`WebSocket Connect error: ${error.toString()}`)
227
-
228
- this.done = true
229
- clearTimeout(timeout)
230
- reject(`Connection error: ${error.toString()}`)
231
- })
232
-
233
- socket.on("disconnect", (reason: string) => {
234
- logger.log(`Disconnected from WebSocket: ${reason}`)
235
- })
236
-
237
- socket.on("auth_success", () => {
238
- logger.log("Auth success")
239
-
240
- this.ready = true
241
- clearTimeout(timeout)
242
- resolve()
243
- })
244
-
245
- socket.connect()
246
- });
247
- }
248
-
249
- disconnect() {
250
- this.ready = false;
251
-
252
- return new Promise<void>((resolve, reject) => {
253
- const timeout = setTimeout(() => {
254
- this.logger.error("Socket didn't disconnect in time")
255
- reject()
256
- }, 5000)
257
-
258
- this.socket.once("disconnect", () => {
259
- this.done = true
260
- clearTimeout(timeout)
261
- resolve()
262
- });
263
-
264
- this.socket.disconnect()
265
- })
266
- }
267
-
268
- private async processWork() {
269
- while (!this.done) {
270
- if (!this.ready) {
271
- await new Promise(resolve => setTimeout(resolve, 100))
272
- continue
273
- }
274
-
275
- const work = this.pool.getWork()
276
- if (work) {
277
- this.ready = false
278
-
279
- try {
280
- this.logger.debug("Running my work")
281
- await work(this)
282
- this.logger.debug("Done with my work, ready for more")
283
- } catch (e) {
284
- this.logger.error("Failed to run work")
285
- this.logger.error(e)
286
- } finally {
287
- this.ready = true
288
- }
289
- } else {
290
- await new Promise(resolve => setTimeout(resolve, 100))
291
- }
292
- }
293
- }
294
- }
295
-
296
-
297
- /**
298
- * Struct used to manage a pool of WebSocket workers
299
- */
300
- export interface WebsocketPool {
301
- workers: PoolWorker[];
302
- token: string;
303
- url: string;
304
- maxWorkers: number;
305
- logger: Logger;
306
- queue: ((worker: PoolWorker) => Promise<any>)[];
307
- }
308
-
309
- /**
310
- * A pool of {@link PoolWorker}s
311
- *
312
- * This is used to manage a pool of WebSocket workers that can be used to run tasks in parallel
313
- * This alleviates the need to wait for every WebSocket instruction to fully complete before starting another
314
- *
315
- * @param url The WebSocket URL to connect to
316
- * @param token The token to use for WebSocket authentication
317
- *
318
- * @internal
319
- */
320
- export class WebsocketPool {
321
- constructor(url: string, token: string) {
322
- const envMaxWorkers = process.env.WISP_MAX_WORKERS
323
- this.maxWorkers = envMaxWorkers ? parseInt(envMaxWorkers) : 5
324
- this.token = token
325
- this.url = url
326
-
327
- const logPrefix = "[Pool]"
328
- this.logger = {
329
- log: (...args: any[]) => console.log(logPrefix, args),
330
- error: (...args: any[]) => console.error(logPrefix, args),
331
- debug: (...args: any[]) => {
332
- if (!WISP_DEBUG) return;
333
- console.debug(logPrefix, args);
334
- }
335
- }
336
-
337
- this.workers = []
338
- this.queue = []
339
-
340
- this.logger.log(`Creating a new Pool with ${this.maxWorkers} workers`)
341
- for (let i = 0; i < this.maxWorkers; i++) {
342
- this.workers.push(new PoolWorker(this));
343
- }
344
- }
345
-
346
- public getWork(): ((worker: PoolWorker) => Promise<any>) | undefined {
347
- return this.queue.shift();
348
- }
349
-
350
- async disconnect() {
351
- this.logger.log("Disconnecting all workers...")
352
- await Promise.all(this.workers.map((worker: PoolWorker) => worker.disconnect()))
353
- this.logger.log("All workers disconnected")
354
- }
355
-
356
- async run(work: (worker: PoolWorker) => Promise<any>): Promise<any> {
357
- return new Promise(async (resolve, reject) => {
358
- this.queue.push(async (worker) => {
359
- try {
360
- const result = await work(worker)
361
- resolve(result)
362
- } catch (e) {
363
- worker.logger.error("Failed to run a job!")
364
- reject(e)
365
- }
366
- });
367
- });
368
- }
369
- }