Skip to content

Commit

Permalink
feat: add HTTP long-polling implementation based on fetch()
Browse files Browse the repository at this point in the history
  • Loading branch information
darrachequesne committed Apr 22, 2024
1 parent fa47916 commit 92a4441
Show file tree
Hide file tree
Showing 11 changed files with 497 additions and 336 deletions.
3 changes: 3 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ export { transports } from "./transports/index.js";
export { installTimerFunctions } from "./util.js";
export { parse } from "./contrib/parseuri.js";
export { nextTick } from "./transports/websocket-constructor.js";

export { Fetch } from "./transports/polling-fetch.js";
export { XHR } from "./transports/polling-xhr.js";
4 changes: 2 additions & 2 deletions lib/transports/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Polling } from "./polling.js";
import { XHR } from "./polling-xhr.js";
import { WS } from "./websocket.js";
import { WT } from "./webtransport.js";

export const transports = {
websocket: WS,
webtransport: WT,
polling: Polling,
polling: XHR,
};
73 changes: 73 additions & 0 deletions lib/transports/polling-fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Polling } from "./polling.js";
import { CookieJar, createCookieJar } from "./xmlhttprequest.js";

/**
* HTTP long-polling based on `fetch()`
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/fetch
*/
export class Fetch extends Polling {
private readonly cookieJar?: CookieJar;

constructor(opts) {
super(opts);

if (this.opts.withCredentials) {
this.cookieJar = createCookieJar();
}
}

override async doPoll() {
try {
const res = await this._fetch();

if (!res.ok) {
return this.onError("fetch read error", res.status, res);
}

const data = await res.text();
this.onData(data);
} catch (e) {
this.onError("fetch read error", e);
}
}

override async doWrite(data: string, callback: () => void) {
try {
const res = await this._fetch(data);

if (!res.ok) {
return this.onError("fetch write error", res.status, res);
}

callback();
} catch (e) {
this.onError("fetch write error", e);
}
}

private async _fetch(data?: string) {
const isPost = data !== undefined;
const headers = new Headers(this.opts.extraHeaders);

if (isPost) {
headers.set("content-type", "text/plain;charset=UTF-8");
}

this.cookieJar?.appendCookies(headers);

const res = await fetch(this.uri(), {
method: isPost ? "POST" : "GET",
body: isPost ? data : null,
headers,
credentials: this.opts.withCredentials ? "include" : "omit",
});

if (this.cookieJar) {
// @ts-ignore getSetCookie() was added in Node.js v19.7.0
this.cookieJar.parseCookies(res.headers.getSetCookie());
}

return res;
}
}

0 comments on commit 92a4441

Please sign in to comment.