Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: de-duplicate queued messages for not-yet-open channel #6

Merged
merged 3 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/react.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ if (channel.isOpen()) {

> Note: if you or another MUPPET client attempts to send events over a channel before a receiving client is connected, the events will be temporarily held in an in-memory queue in the sender's app (will not disappear).
>
> As soon as both apps have connected to the same MuppetChannel, all of these pending events will be "replayed"--sent over the channel--so the receiver can receive them.
> As soon as both apps have connected to the same MuppetChannel, all of these pending events will be "replayed"--sent over the channel--so the receiver can receive them. Any queued messages with the same `destination` and `eventClass` will be de-duplicated--using only the latest one--to avoid jittery behavior in the receiver when it comes online.

## Hooks

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@noaa-gsl/idsse-muppet",
"version": "0.0.12",
"version": "0.0.13",
"description": "Connect to, send, and receive data over MUPPET data channels in convenient React interfaces using the MUPPETs protocol",
"main": "index.js",
"scripts": {
Expand Down
17 changes: 12 additions & 5 deletions src/MuppetChannel.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,14 @@ class MuppetChannel {
this.#dataChannel,
);
if (!this.isOpen()) {
console.warn(`[${this.#clientName}] [${this.room}] Channel not ready to receive data`);
console.warn(
`[${this.#clientName}] [${this.room}] Channel not ready to receive data. Message queued`,
);

// de-duplicate queue, so recipient app won't try to process successive state changes when it comes online
this.#queuedMessages = this.#queuedMessages.filter(
(it) => !(it.eventClass === data.eventClass && it.destination === it.destination),
);
this.#queuedMessages.push(data); // stash this message until channel opens (hopefully)
return false;
}
Expand All @@ -337,7 +344,7 @@ class MuppetChannel {
* @param {string} requestId (optional) the UUID of the original message that this message is responding to.
* @returns {object} the message, ready to be sent over WebRTC
*/
#createMuppetMessage = (eventClass, event, destination, requestId = null) => ({
buildMuppetMessage = (eventClass, event, destination, requestId = null) => ({
id: crypto.randomUUID(),
destination,
requestId: requestId || undefined,
Expand All @@ -357,11 +364,11 @@ class MuppetChannel {
* @returns {boolean} True if message sent successfully.
*/
sendEvent = ({ eventClass, event = {}, destination = '*', requestId = null }) => {
console.log(
console.debug(
`[${this.#clientName}] [${this.room}] Sending MUPPET event ${eventClass} with body`,
event,
);
const data = this.#createMuppetMessage(eventClass, event, destination, requestId);
const data = this.buildMuppetMessage(eventClass, event, destination, requestId);
return this.sendRawData(data);
};

Expand All @@ -383,7 +390,7 @@ class MuppetChannel {
requestReject = reject;
});

const message = this.#createMuppetMessage(eventClass, event, destination);
const message = this.buildMuppetMessage(eventClass, event, destination);
// track this message as expecting a response, saving the resolve() to be invoked by onReceiveMessage
this.#requests[message.id] = { callback: requestResolve };

Expand Down