@atomist/automation-client
Version:
Atomist API for software low-level client
114 lines (99 loc) • 2.69 kB
text/typescript
import * as TinyQueue from "tinyqueue";
import * as WebSocket from "ws";
import { logger } from "../../../util/logger";
import { sendMessage } from "./WebSocketMessageClient";
export interface WebSocketLifecycle {
/**
* Set the WebSocket to manage
* @param ws
*/
set(ws: WebSocket): void;
/**
* Is the WebSocket is connected and healthy
*/
connected(): boolean;
/**
* Get the raw WebSocket that is managed here
*/
get(): WebSocket;
/**
* Reset the WebSocket
*/
reset(): void;
/**
* Send a message over the managed WebSocket
* If the WebSocket isn't connected, messages are queued for later
* when a WebSocket is connected again.
* @param msg
*/
send(msg: any): void;
}
/**
* Lifecycle owning a WebSocket connection wrt message sending
*/
export class QueuingWebSocketLifecycle implements WebSocketLifecycle {
private readonly messages: TinyQueue<any>;
private ws: WebSocket;
private timer: NodeJS.Timer;
constructor() {
// This is odd but the only way to the types working
this.messages = new TinyQueue();
}
/**
* Set the WebSocket to manage
* @param ws
*/
public set(ws: WebSocket): void {
this.ws = ws;
}
/**
* Is the WebSocket is connected and healthy
*/
public connected(): boolean {
return !!this.ws && this.ws.readyState === WebSocket.OPEN;
}
/**
* Get the raw WebSocket that is managed here
*/
public get(): WebSocket {
return this.ws;
}
/**
* Reset the WebSocket
*/
public reset(): void {
this.ws = null;
}
/**
* Send a message over the managed WebSocket
* If the WebSocket isn't connected, messages are queued for later
* when a WebSocket is connected again.
* @param msg
*/
public send(msg: any): void {
if (!this) {
logger.warn(`WebSocket has been destroyed before we were able to send the message`);
return;
} else if (this.connected()) {
sendMessage(msg, this.ws, true);
} else {
if (!this.timer) {
this.init();
}
this.messages.push(msg);
}
}
/**
* Init the internal queue processing
*/
private init(): void {
this.timer = setInterval(async () => {
const queuedMessages = [];
while (this.messages.length > 0) {
queuedMessages.push(this.messages.pop());
}
queuedMessages.forEach(this.send);
}, 1000);
this.timer.unref();
}
}