Skip to content

Commit

Permalink
feat: close conn. when receiving close message
Browse files Browse the repository at this point in the history
wip: needs tests
  • Loading branch information
ilbertt committed Dec 8, 2023
1 parent 81e971f commit b456157
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 0 deletions.
16 changes: 16 additions & 0 deletions src/ic-websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { IDL } from "@dfinity/candid";
import { Principal } from "@dfinity/principal";
import {
CanisterAckMessageContent,
CanisterCloseMessageContent,
CanisterWsMessageArguments,
ClientKeepAliveMessageContent,
ClientKey,
Expand Down Expand Up @@ -371,6 +372,10 @@ export default class IcWebSocket<
this._outgoingMessagesQueue.enableAndProcess();
} else if ("AckMessage" in serviceMessage) {
await this._handleAckMessageFromCanister(serviceMessage.AckMessage);
} else if ("CloseMessage" in serviceMessage) {
await this._handleCloseMessageFromCanister(serviceMessage.CloseMessage);
// we don't have to process any further message (there shouldn't be any anyway)
return false;
} else {
throw new Error("Invalid service message from canister");
}
Expand Down Expand Up @@ -399,6 +404,17 @@ export default class IcWebSocket<
await this._sendKeepAliveMessage();
}

private async _handleCloseMessageFromCanister(content: CanisterCloseMessageContent): Promise<void> {
if ("ClosedByApplication" in content.reason) {
logger.debug("[onWsMessage] Received close message from canister. Reason: ClosedByApplication");
this._wsInstance.close(4001, "ClosedByApplication");
} else {
logger.error("[onWsMessage] Received close message from canister. Reason:", content.reason);
this._callOnErrorCallback(new Error(`Received close message from canister. Reason: ${content.reason}`));
this._wsInstance.close(4000, "Received close message from canister");
}
}

private async _sendKeepAliveMessage(): Promise<void> {
const keepAliveMessageContent: ClientKeepAliveMessageContent = {
last_incoming_sequence_num: this._incomingSequenceNum - BigInt(1),
Expand Down
24 changes: 24 additions & 0 deletions src/idl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,26 @@ export type CanisterAckMessageContent = {
export type ClientKeepAliveMessageContent = {
'last_incoming_sequence_num': bigint,
};
export type CloseMessageReason = {
WrongSequenceNumber: null,
} | {
InvalidServiceMessage: null,
} | {
KeepAliveTimeout: null,
} | {
ClosedByApplication: null
};
export type CanisterCloseMessageContent = {
reason: CloseMessageReason,
};
export type WebsocketServiceMessageContent = {
OpenMessage: CanisterOpenMessageContent,
} | {
AckMessage: CanisterAckMessageContent,
} | {
KeepAliveMessage: ClientKeepAliveMessageContent,
} | {
CloseMessage: CanisterCloseMessageContent,
};

const CanisterOpenMessageContentIdl = IDL.Record({
Expand All @@ -95,10 +109,20 @@ const CanisterAckMessageContentIdl = IDL.Record({
const ClientKeepAliveMessageContentIdl = IDL.Record({
'last_incoming_sequence_num': IDL.Nat64,
});
const CloseMessageReasonIdl = IDL.Variant({
'WrongSequenceNumber': IDL.Null,
'InvalidServiceMessage': IDL.Null,
'KeepAliveTimeout': IDL.Null,
'ClosedByApplication': IDL.Null,
});
const CanisterCloseMessageContentIdl = IDL.Record({
'reason': CloseMessageReasonIdl,
})
const WebsocketServiceMessageContentIdl = IDL.Variant({
'OpenMessage': CanisterOpenMessageContentIdl,
'AckMessage': CanisterAckMessageContentIdl,
'KeepAliveMessage': ClientKeepAliveMessageContentIdl,
'CloseMessage': CanisterCloseMessageContentIdl,
});

export const decodeWebsocketServiceMessageContent = (bytes: Uint8Array): WebsocketServiceMessageContent => {
Expand Down

0 comments on commit b456157

Please sign in to comment.