Commit Graph

20 Commits

Author SHA1 Message Date
Damien Arrachequesne
5bc94b56bc fix: properly report timeout error when connecting
In some specific cases (Node.js client with WebSocket only), the reason
attached to the "connect_error" event was "websocket error" instead of
"timeout".

Related: https://github.com/socketio/socket.io/issues/4062
2023-06-20 18:48:11 +02:00
Damien Arrachequesne
655dce9755 feat: implement retry mechanism
Syntax:

```js
const socket = io({
  retries: 3,
  ackTimeout: 10000
});

// "my-event" will be sent up to 4 times (1 + 3), until the server sends an acknowledgement
socket.emit("my-event", (err) => {});
```

Notes:

- the order of the packets is guaranteed, as we send packets one by one
- the same packet id is reused for consecutive retries, in order to
allow deduplication on the server side
2023-02-01 08:19:34 +01:00
Damien Arrachequesne
9f3292525b test: add test with onAnyOutgoing() and binary attachments 2023-01-30 08:26:56 +01:00
Damien Arrachequesne
47b979d573 feat: add promise-based acknowledgements
This commit adds some syntactic sugar around acknowledgements:

```js
// without timeout
const response = await socket.emitWithAck("hello", "world");

// with a specific timeout
try {
  const response = await socket.timeout(1000).emitWithAck("hello", "world");
} catch (err) {
  // the server did not acknowledge the event in the given delay
}
```

Note: enviroments that do not support Promises ([1]) will need to add a
polyfill in order to use this feature

See also: 184f3cf7af

[1]: https://caniuse.com/promises
2023-01-30 08:08:06 +01:00
Damien Arrachequesne
d882822908 ci: migrate from zuul to webdriver.io
zuul is now archived [1] and does not support the new W3C WebDriver
protocol, since it relies on the wd package [2] under the hood, which
uses the (now deprecated) JSON Wire Protocol.

We will now use the webdriver.io test framework, which allows to run
our tests in local and on Sauce Labs (cross-browser and mobile tests).
This allows us to run our tests on latest versions of Android and iOS,
since Sauce Labs only supports the W3C WebDriver protocol for these
platforms ([3]).

[1]: https://github.com/defunctzombie/zuul
[2]: https://github.com/admc/wd
[3]: https://docs.saucelabs.com/dev/w3c-webdriver-capabilities/
2022-11-17 09:51:12 +01:00
Damien Arrachequesne
74e3e601a4 feat: add support for catch-all listeners for outgoing packets
This is similar to `onAny()`, but for outgoing packets.

Syntax:

```js
socket.onAnyOutgoing((event, ...args) => {
  console.log(event);
});
```

Related: 531104d332
2022-04-23 23:57:03 +02:00
Damien Arrachequesne
522ffbe7a8 fix: prevent double ack with timeout
The ack was not properly removed upon timeout, and could be called
twice.

Related: ccf7998cc5
2021-11-18 13:40:46 +01:00
Damien Arrachequesne
99c2cb8421 fix: fix socket.disconnect().connect() usage
Previously, calling `socket.disconnect().connect()` could, if the
connection was upgraded to WebSocket, result in "disconnect" being
emitted twice, and an engine being leaked.

Here's what happened:

> socket.disconnect()

- calls `socket.destroy()` so the socket doesn't listen to the manager events anymore
- then calls `manager._close()` which closes the underlying engine but not the manager itself (it waits for the "close" event of the engine)

> socket.connect()

- calls `socket.subEvents()` so the socket does listen to the manager events
- calls `manager.open()` which creates a new engine

And then the first engine emits a "close" event, which is forwarded to
the socket, hence the second "disconnect" event.

Related: https://github.com/socketio/socket.io-client/issues/1014
2021-11-18 13:39:40 +01:00
Damien Arrachequesne
d54d12ce63 fix: prevent socket from reconnecting after middleware failure
Related: https://github.com/socketio/socket.io/discussions/4150
2021-11-16 19:57:47 +01:00
Damien Arrachequesne
ccf7998cc5 feat: add timeout feature
Usage:

```js
socket.timeout(5000).emit("my-event", (err) => {
  if (err) {
    // the server did not acknowledge the event in the given delay
  }
});
```
2021-11-16 19:56:44 +01:00
Damien Arrachequesne
16b65698ae feat: provide an ESM build with and without debug
See also: 00d7e7d7ee

Related:

- https://github.com/socketio/socket.io-client/issues/1188
- https://github.com/socketio/socket.io-client/issues/1378
2021-10-13 18:09:41 +02:00
Damien Arrachequesne
91fbd47e1e chore: bump engine.io-client to version 6.0.0
Release notes: https://github.com/socketio/engine.io-client/releases/6.0.0
Diff: https://github.com/socketio/engine.io-client/compare/5.2.0...6.0.0
2021-10-11 23:19:51 +02:00
Damien Arrachequesne
34f822f783 fix: ensure buffered events are sent in order
Before this commit, an event sent in the "connect" handler could be
sent before the events that were buffered while disconnected.

```js
socket.on("connect", () => {
  socket.emit("bar");
});

socket.emit("foo"); // buffered while disconnected
```

In the example above, the "bar" event was sent first, which is not
correct.

Related: https://github.com/socketio/socket.io-client/issues/1458
2021-05-06 14:23:25 +02:00
Damien Arrachequesne
53c73749a8 fix: emit a connect_error event upon connection failure
Related: https://github.com/socketio/socket.io/issues/3734
2021-01-05 11:42:54 +01:00
Damien Arrachequesne
09393952e3 feat: emit an Error object upon middleware error
See 54bf4a44e9
2020-10-30 22:54:13 +01:00
Damien Arrachequesne
969debe88c refactor: rework of the Manager events
- rename "connect_error" to "error"
- remove "reconnecting" (duplicate of "reconnect_attempt")

The updated list of events emitted by the Manager:

- open:                successful (re)connection
- error:               (re)connection failure (previously: "connect_error") or error after a successful connection
- close:               disconnection

- ping:                ping packet
- packet:              data packet

- reconnect_attempt:   reconnection attempt (previously: "reconnect_attempt" & "reconnecting")
- reconnect:           successful reconnection
- reconnect_error:     reconnection failure
- reconnect_failed:    reconnection failure after all attempts

For reference, the Socket instance emits the following events:

- connect:             successful connection to a Namespace
- connect_error:       connection failure
- disconnect:          disconnection
2020-10-27 23:07:44 +01:00
Damien Arrachequesne
13e1db7c94 refactor: rename ERROR to CONNECT_ERROR
The meaning is not modified: this packet type is still used by the
server when the connection to a namespace is refused.

Breaking change: the Socket instance will now emit a "connect_error"
event instead of "error" (which is not a reserved event anymore)

```js
// before
socket.on("error", () => {});

// after
socket.on("connect_error", () => {});
```
2020-10-26 10:04:05 +01:00
Damien Arrachequesne
55f464f59e feat: add support for catch-all listeners
Inspired from EventEmitter2 [1]

The API is similar to the one on the server-side:

```js
socket.onAny((event, ...args) => {});

socket.prependAny((event, ...args) => {});

socket.offAny(); // remove all listeners

socket.offAny(listener);

const listeners = socket.listenersAny();
```

[1]: https://github.com/EventEmitter2/EventEmitter2
2020-10-26 10:03:27 +01:00
Damien Arrachequesne
7ddad2c09d feat: add volatile events
A volatile packet will be dropped if:

- the socket is not connected
- the low-level transport is not ready (for example, a HTTP POST request is already pending)

Syntax:

```js
socket.volatile.emit("volatile event", "might or might not be sent");
```
2020-10-17 03:37:29 +02:00
Damien Arrachequesne
c7998d5446 refactor: add Manager and Socket typings 2020-10-14 22:59:58 +02:00