Skip to content

Commit

Permalink
feat: add the ability to test all transports
Browse files Browse the repository at this point in the history
  • Loading branch information
darrachequesne committed May 27, 2024
1 parent 2c1851d commit 68d2e76
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 23 deletions.
24 changes: 24 additions & 0 deletions lib/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,19 @@ export interface SocketOptions {
*/
transports?: string[];

/**
* Whether all the transports should be tested, instead of just the first one.
*
* If set to `true`, the client will first try to connect with HTTP long-polling, and then with WebSocket in case of
* failure, and finally with WebTransport if the previous attempts have failed.
*
* If set to `false` (default), if the connection with HTTP long-polling fails, then the client will not test the
* other transports and will abort the connection.
*
* @default false
*/
tryAllTransports?: boolean;

/**
* If true and if the previous websocket connection to the server succeeded,
* the connection attempt will bypass the normal upgrade process and will
Expand Down Expand Up @@ -916,6 +929,17 @@ export class Socket extends Emitter<
private onError(err: Error) {
debug("socket error %j", err);
Socket.priorWebsocketSuccess = false;

if (
this.opts.tryAllTransports &&
this.transports.length > 1 &&
this.readyState === "opening"
) {
debug("trying next transport");
this.transports.shift();
return this.open();
}

this.emitReserved("error", err);
this.onClose("transport error", err);
}
Expand Down
19 changes: 4 additions & 15 deletions lib/transports/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const isReactNative =
typeof navigator.product === "string" &&
navigator.product.toLowerCase() === "reactnative";

/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
* @see https://caniuse.com/mdn-api_websocket
*/
export class WS extends Transport {
private ws: any;

Expand All @@ -37,11 +41,6 @@ export class WS extends Transport {
}

override doOpen() {
if (!this.check()) {
// let probe timeout
return;
}

const uri = this.uri();
const protocols = this.opts.protocols;

Expand Down Expand Up @@ -189,14 +188,4 @@ export class WS extends Transport {

return this.createUri(schema, query);
}

/**
* Feature detection for WebSocket.
*
* @return {Boolean} whether this transport is available.
* @private
*/
private check() {
return !!WebSocket;
}
}
20 changes: 12 additions & 8 deletions lib/transports/webtransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import debugModule from "debug"; // debug()

const debug = debugModule("engine.io-client:webtransport"); // debug()

/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/WebTransport
* @see https://caniuse.com/webtransport
*/
export class WT extends Transport {
private transport: any;
private writer: any;
Expand All @@ -18,15 +22,15 @@ export class WT extends Transport {
}

protected doOpen() {
// @ts-ignore
if (typeof WebTransport !== "function") {
return;
try {
// @ts-ignore
this.transport = new WebTransport(
this.createUri("https"),
this.opts.transportOptions[this.name]
);
} catch (err) {
return this.emitReserved("error", err);
}
// @ts-ignore
this.transport = new WebTransport(
this.createUri("https"),
this.opts.transportOptions[this.name]
);

this.transport.closed
.then(() => {
Expand Down
58 changes: 58 additions & 0 deletions test/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,64 @@ describe("Socket", function () {
});
});

it("should connect with the 2nd transport if tryAllTransports is `true` (polling)", (done) => {
const socket = new Socket({
transports: ["websocket", "polling"],
transportOptions: {
websocket: {
query: {
deny: 1,
},
},
},
tryAllTransports: true,
});

socket.on("open", () => {
expect(socket.transport.name).to.eql("polling");
socket.close();
done();
});
});

it("should connect with the 2nd transport if tryAllTransports is `true` (websocket)", (done) => {
const socket = new Socket({
transports: ["polling", "websocket"],
transportOptions: {
polling: {
query: {
deny: 1,
},
},
},
tryAllTransports: true,
});

socket.on("open", () => {
expect(socket.transport.name).to.eql("websocket");
socket.close();
done();
});
});

it("should not connect with the 2nd transport if tryAllTransports is `false`", (done) => {
const socket = new Socket({
transports: ["polling", "websocket"],
transportOptions: {
polling: {
query: {
deny: 1,
},
},
},
});

socket.on("error", (err) => {
expect(err.message).to.eql("xhr poll error");
done();
});
});

describe("fake timers", function () {
before(function () {
if (isIE11 || isAndroid || isEdge || isIPad) {
Expand Down
6 changes: 6 additions & 0 deletions test/support/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ exports.mochaHooks = {
engine = attach(httpServer, {
pingInterval: 500,
maxHttpBufferSize: 100,
allowRequest: (req, fn) => {
const denyRequest = new URL(`http://${req.url}`).searchParams.has(
"deny"
);
fn(null, !denyRequest);
},
});

rollup(rollupConfig).then(async (bundle) => {
Expand Down

0 comments on commit 68d2e76

Please sign in to comment.