diff --git a/README.md b/README.md index 8b9093b..687ca67 100644 --- a/README.md +++ b/README.md @@ -11,67 +11,76 @@ A client-websocket written in TypeScript to be used from within browsers with fo - Uses the browser-native WebSocket-functionality - Copies the event-based WebSocket-API - Provides low-level access to the underlying WebSocket if needed -- Optional automatic reconnects +- Optionally automatic reconnect when disconnected - With easy-to-configure parameters (time between retries) -- Optional pending-messages +- Optionally buffer messages while disconnected - With easy-to-configure buffers (size, behaviour) - Builder-class for easy initialization and configuration ## Usage -New instances can be easily created through the Builder-class. +New instances can be created with the Builder. ```typescript -const ws = new Builder('ws://localhost:42421').build(); +const ws = new WsBuilder('ws://localhost:42421').build(); ``` #### Callbacks -You can register callbacks for `onOpen`-, `onClose`-, `onError`- and `onMessage`-events. The callbacks get called with the websocket-instance that caused the event plus the event as parameters. +You can register callbacks for `onOpen`-, `onClose`-, `onError`- and `onMessage`-events. The callbacks get called with the websocket-instance plus the event itself as parameters. ```typescript -const ws = new Builder('ws://localhost:42421') - .onOpen((i, e) => { console.log("opened") }) - .onClose((i, e) => { console.log("closed") }) - .onError((i, e) => { console.log("error") }) - .onMessage((i, e) => { i.send(e.data) }) +const ws = new WsBuilder('ws://localhost:42421') + .onOpen((ws, e) => { console.log("opened") }) + .onClose((ws, e) => { console.log("closed") }) + .onError((ws, e) => { console.log("error") }) + .onMessage((ws, e) => { ws.send(e.data) }) .build(); ``` It is possible to register multiple callbacks for the same event, they are called in stack-order: ```typescript -const ws = new Builder('ws://localhost:42421') - .onMessage((i, e) => { console.log("sent echo") }) - .onMessage((i, e) => { i.send(e.data) }) - .onMessage((i, e) => { console.log("message received") }) +const ws = new WsBuilder('ws://localhost:42421') + .onMessage((ws, e) => { console.log("sent echo") }) + .onMessage((ws, e) => { i.send(e.data) }) + .onMessage((ws, e) => { console.log("message received") }) .build(); ``` #### Buffer -To buffer pending messages while your websocket is disconnected, configure it to use a Buffer. These pending messages - will be sent out as soon as the connection is (re)-established. +To buffer pending messages while your websocket is disconnected, configure it to use a ```Buffer```. While disconnected, +calls to the `send()`-method will write the message you want to send to the buffer. These pending messages +will be sent out in the order that they were inserted as soon as the connection is (re)-established. ```typescript -const ws = new Builder('ws://localhost:42421') - .withBuffer(new LRUBuffer(100)) // buffers up to 100 messages, substitutes old messages with new ones +// LRUBuffer with a capacity of 1000 messages. If the buffer is full, +// the oldest message will be replaced by the newest and so on. +const ws = new WsBuilder('ws://localhost:42421') + .withBuffer(new LRUBuffer(1000)) .build(); ``` ```typescript -const ws = new Builder('ws://localhost:42421') - .withBuffer(new TimeBuffer(5 * 60 * 1000)) // buffers messages that were written within the last 5 minutes +// TimeBuffer keeping all messages from the last five minutes, +// older messages are dropped. +const ws = new WsBuilder('ws://localhost:42421') + .withBuffer(new TimeBuffer(5 * 60 * 1000)) .build(); ``` #### Reconnect / Backoff -To configure the websocket to automatically reconnect when the connection gets lost, provide it with a Backoff. -The type of backoff provided decides the delay between connection-retries. +When provided with a ```Backoff```, the websocket will automatically try to reconnect when the connection got lost. The +type of backoff provided dictates the delay between connection-retries in milliseconds. ```typescript -const ws = new Builder('ws://localhost:42421') - .withBackoff(new ConstantBackoff(500)) // Always waits 500 ms between retries +// ConstantBackoff will wait a fixed time between connection-retries. +const ws = new WsBuilder('ws://localhost:42421') + .withBackoff(new ConstantBackoff(500)) .build(); ``` ```typescript -const ws = new Builder('ws://localhost:42421') - .withBackoff(new ExponentialBackoff(100)) // Doubles the time between reconnects with every try +// ExponentialBackoff will double the time to wait between retries with +// every unsuccessful retry until a maximum is reached. This one goes from +// 100 * 2^0 to 100 * 2^5, so [100, 200, 400, 800, 1600, 3200] milliseconds. +const ws = new WsBuilder('ws://localhost:42421') + .withBackoff(new ExponentialBackoff(100, 0, 5)) .build(); ``` \ No newline at end of file diff --git a/package.json b/package.json index 44b0711..502d494 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "websocket-ts", - "version": "1.0.0-rc5", + "version": "1.0.1", "main": "lib/index.js", "types": "lib/", "license": "MIT", diff --git a/src/buffer/timebuffer.ts b/src/buffer/timebuffer.ts index e0da088..59fd2a2 100644 --- a/src/buffer/timebuffer.ts +++ b/src/buffer/timebuffer.ts @@ -5,6 +5,9 @@ import {Buffer} from "./buffer"; * within maxAge milliseconds. E.g. to only keep items in the * buffer that are less than a minute old, create the buffer with * a maximum age of 60.000. + * + * When reading from the TimeBuffer, elements will be returned + * in FIFO-order (queue). */ export class TimeBuffer implements Buffer { private readonly maxAge: number; diff --git a/src/index.ts b/src/index.ts index 2b982f1..56dba92 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,4 +2,4 @@ export * from './backoff/backoff'; export * from './buffer/buffer'; export * from './buffer/lrubuffer' export * from './websocket'; -export * from './builder'; +export * from './wsbuilder'; diff --git a/src/websocket.ts b/src/websocket.ts index 493c8de..04c463a 100644 --- a/src/websocket.ts +++ b/src/websocket.ts @@ -20,7 +20,7 @@ interface WebsocketEventMap { open: Event; } -export type Listeners = { +type Listeners = { open: eventListener[]; close: eventListener[]; error: eventListener[]; @@ -90,7 +90,7 @@ export class Websocket { if (l.options !== undefined && (l.options as AddEventListenerOptions).once) remove.push(l); if (l.options !== undefined && (l.options as AddEventListenerOptions).passive && ev.defaultPrevented) - console.log("default was prevent when listener was market as passive"); + console.log("default was prevent when listener was marked as passive"); } const listeners = this.listeners[type] as eventListener[]; listeners.forEach(l => dispatch(l)); @@ -110,7 +110,7 @@ export class Websocket { const wsIsClosed = this.websocket?.readyState == this.websocket?.CLOSED; const wsIsClosing = this.websocket?.readyState === this.websocket?.CLOSING; if (!this.closedByUser && (wsIsClosed || wsIsClosing)) { - this.reconnect(); + this.reconnectWithBackoff(); } if (type === WebsocketEvents.open) { if (this.timer !== undefined) @@ -122,8 +122,10 @@ export class Websocket { this.dispatchEvent(type, ev); } - private reconnect() { - const backoff = this.backoff?.Next() || 0; + private reconnectWithBackoff() { + if (this.backoff === undefined) + return; + const backoff = this.backoff.Next() || 0; this.timer = setTimeout(() => { this.tryConnect(); }, backoff); diff --git a/src/builder.ts b/src/wsbuilder.ts similarity index 91% rename from src/builder.ts rename to src/wsbuilder.ts index 48db507..bc0e695 100644 --- a/src/builder.ts +++ b/src/wsbuilder.ts @@ -2,7 +2,7 @@ import {Backoff} from "./backoff/backoff"; import {Buffer} from "./buffer/buffer"; import {Websocket, WebsocketEvents} from "./websocket"; -export class Builder { +export class WsBuilder { private readonly url: string; private protocols?: string | string[] private backoff?: Backoff @@ -16,22 +16,22 @@ export class Builder { this.url = url; } - public withProtocols(p: string | string[]): Builder { + public withProtocols(p: string | string[]): WsBuilder { this.protocols = p; return this; } - public withBackoff(backoff: Backoff): Builder { + public withBackoff(backoff: Backoff): WsBuilder { this.backoff = backoff; return this; } - public withBuffer(buffer: Buffer): Builder { + public withBuffer(buffer: Buffer): WsBuilder { this.buffer = buffer; return this; } - public onOpen(fn: (instance: Websocket, ev: Event) => any): Builder { + public onOpen(fn: (instance: Websocket, ev: Event) => any): WsBuilder { const onOpen = this.onOpenChain; this.onOpenChain = (instance: Websocket, ev2: Event) => { fn(instance, ev2); @@ -41,7 +41,7 @@ export class Builder { return this; } - public onClose(fn: (instance: Websocket, ev: CloseEvent) => any): Builder { + public onClose(fn: (instance: Websocket, ev: CloseEvent) => any): WsBuilder { const onClose = this.onCloseChain; this.onCloseChain = (instance: Websocket, ev2: CloseEvent) => { fn(instance, ev2); @@ -51,7 +51,7 @@ export class Builder { return this; } - public onError(fn: (instance: Websocket, ev: Event) => any): Builder { + public onError(fn: (instance: Websocket, ev: Event) => any): WsBuilder { const onError = this.onErrorChain; this.onErrorChain = (instance: Websocket, ev2: Event) => { fn(instance, ev2); @@ -61,7 +61,7 @@ export class Builder { return this; } - public onMessage(fn: (instance: Websocket, ev: MessageEvent) => any): Builder { + public onMessage(fn: (instance: Websocket, ev: MessageEvent) => any): WsBuilder { const onMessage = this.onMessageChain; this.onMessageChain = (instance: Websocket, ev2: MessageEvent) => { fn(instance, ev2); diff --git a/test/builder.test.ts b/test/builder.test.ts index 2986390..5e0d13f 100644 --- a/test/builder.test.ts +++ b/test/builder.test.ts @@ -1,12 +1,12 @@ -import {Builder, LRUBuffer, Websocket} from "../src"; +import {WsBuilder, LRUBuffer, Websocket} from "../src"; import {ConstantBackoff} from "../src/backoff/constantbackoff"; describe("Testsuite for Builder", () => { const url = "ws://localhost:42421"; - let builder: Builder + let builder: WsBuilder beforeEach(() => { - builder = new Builder(url); + builder = new WsBuilder(url); }); test("Builder should set protocols", () => { diff --git a/test/websocket.test.ts b/test/websocket.test.ts index 497486f..2807c4f 100644 --- a/test/websocket.test.ts +++ b/test/websocket.test.ts @@ -1,5 +1,5 @@ -import {Websocket, WebsocketEvents} from "../src/websocket"; -import {Builder} from "../src/builder"; +import {Websocket, WebsocketEvents} from "../src"; +import {WsBuilder} from "../src"; import {Server} from "ws"; describe("Testsuite for Websocket events", () => { @@ -27,7 +27,7 @@ describe("Testsuite for Websocket events", () => { test("Websocket event-onOpen", async () => { await new Promise>(resolve => { - ws = new Builder(url).onOpen((instance, ev) => { + ws = new WsBuilder(url).onOpen((instance, ev) => { resolve({instance, ev}); }).build(); }).then(e => { @@ -38,7 +38,7 @@ describe("Testsuite for Websocket events", () => { test("Websocket event-onClose", async () => { await new Promise>(resolve => { - ws =new Builder(url).onClose((instance, ev) => { + ws =new WsBuilder(url).onClose((instance, ev) => { resolve({instance, ev}); }).build(); wss?.close(); @@ -51,7 +51,7 @@ describe("Testsuite for Websocket events", () => { test("Websocket event-onError", async () => { await new Promise>(resolve => { wss?.close(); - ws = new Builder(url).onError((instance, ev) => { + ws = new WsBuilder(url).onError((instance, ev) => { resolve({instance, ev}); }).build(); }).then(e => { @@ -63,7 +63,7 @@ describe("Testsuite for Websocket events", () => { test("Websocket event-onMessage", async () => { const testMsg = "this is a test-message!"; const onMessagePromise = new Promise>(resolve => { - ws = new Builder(url).onMessage((instance, ev) => { + ws = new WsBuilder(url).onMessage((instance, ev) => { resolve({instance, ev}); }).build(); }).then(e => {