diff --git a/app/src/lib/platform_shared/websocket_message.ts b/app/src/lib/platform_shared/websocket_message.ts index f85e958..4b6d1d3 100644 --- a/app/src/lib/platform_shared/websocket_message.ts +++ b/app/src/lib/platform_shared/websocket_message.ts @@ -67,9 +67,17 @@ export interface RSSIData { } export interface SubscribeNotification { + tag: number; } export interface UnsubscribeNotification { + tag: number; +} + +export interface PingMsg { +} + +export interface PongMsg { } /** @@ -79,6 +87,8 @@ export interface UnsubscribeNotification { export interface WebsocketMessage { subNotif?: SubscribeNotification | undefined; unsubNotif?: UnsubscribeNotification | undefined; + pingmsg?: PingMsg | undefined; + pongmsg?: PongMsg | undefined; imu?: IMUData | undefined; imuCalibrate?: IMUCalibrateData | undefined; mode?: ModeData | undefined; @@ -910,11 +920,14 @@ export const RSSIData: MessageFns = { }; function createBaseSubscribeNotification(): SubscribeNotification { - return {}; + return { tag: 0 }; } export const SubscribeNotification: MessageFns = { - encode(_: SubscribeNotification, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + encode(message: SubscribeNotification, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.tag !== 0) { + writer.uint32(8).int32(message.tag); + } return writer; }, @@ -925,6 +938,14 @@ export const SubscribeNotification: MessageFns = { while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.tag = reader.int32(); + continue; + } } if ((tag & 7) === 4 || tag === 0) { break; @@ -934,30 +955,37 @@ export const SubscribeNotification: MessageFns = { return message; }, - fromJSON(_: any): SubscribeNotification { - return {}; + fromJSON(object: any): SubscribeNotification { + return { tag: isSet(object.tag) ? globalThis.Number(object.tag) : 0 }; }, - toJSON(_: SubscribeNotification): unknown { + toJSON(message: SubscribeNotification): unknown { const obj: any = {}; + if (message.tag !== 0) { + obj.tag = Math.round(message.tag); + } return obj; }, create, I>>(base?: I): SubscribeNotification { return SubscribeNotification.fromPartial(base ?? ({} as any)); }, - fromPartial, I>>(_: I): SubscribeNotification { + fromPartial, I>>(object: I): SubscribeNotification { const message = createBaseSubscribeNotification(); + message.tag = object.tag ?? 0; return message; }, }; function createBaseUnsubscribeNotification(): UnsubscribeNotification { - return {}; + return { tag: 0 }; } export const UnsubscribeNotification: MessageFns = { - encode(_: UnsubscribeNotification, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + encode(message: UnsubscribeNotification, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.tag !== 0) { + writer.uint32(8).int32(message.tag); + } return writer; }, @@ -965,6 +993,61 @@ export const UnsubscribeNotification: MessageFns = { const reader = input instanceof BinaryReader ? input : new BinaryReader(input); const end = length === undefined ? reader.len : reader.pos + length; const message = createBaseUnsubscribeNotification(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.tag = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): UnsubscribeNotification { + return { tag: isSet(object.tag) ? globalThis.Number(object.tag) : 0 }; + }, + + toJSON(message: UnsubscribeNotification): unknown { + const obj: any = {}; + if (message.tag !== 0) { + obj.tag = Math.round(message.tag); + } + return obj; + }, + + create, I>>(base?: I): UnsubscribeNotification { + return UnsubscribeNotification.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): UnsubscribeNotification { + const message = createBaseUnsubscribeNotification(); + message.tag = object.tag ?? 0; + return message; + }, +}; + +function createBasePingMsg(): PingMsg { + return {}; +} + +export const PingMsg: MessageFns = { + encode(_: PingMsg, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): PingMsg { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBasePingMsg(); while (reader.pos < end) { const tag = reader.uint32(); switch (tag >>> 3) { @@ -977,20 +1060,63 @@ export const UnsubscribeNotification: MessageFns = { return message; }, - fromJSON(_: any): UnsubscribeNotification { + fromJSON(_: any): PingMsg { return {}; }, - toJSON(_: UnsubscribeNotification): unknown { + toJSON(_: PingMsg): unknown { const obj: any = {}; return obj; }, - create, I>>(base?: I): UnsubscribeNotification { - return UnsubscribeNotification.fromPartial(base ?? ({} as any)); + create, I>>(base?: I): PingMsg { + return PingMsg.fromPartial(base ?? ({} as any)); }, - fromPartial, I>>(_: I): UnsubscribeNotification { - const message = createBaseUnsubscribeNotification(); + fromPartial, I>>(_: I): PingMsg { + const message = createBasePingMsg(); + return message; + }, +}; + +function createBasePongMsg(): PongMsg { + return {}; +} + +export const PongMsg: MessageFns = { + encode(_: PongMsg, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): PongMsg { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBasePongMsg(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(_: any): PongMsg { + return {}; + }, + + toJSON(_: PongMsg): unknown { + const obj: any = {}; + return obj; + }, + + create, I>>(base?: I): PongMsg { + return PongMsg.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(_: I): PongMsg { + const message = createBasePongMsg(); return message; }, }; @@ -999,6 +1125,8 @@ function createBaseWebsocketMessage(): WebsocketMessage { return { subNotif: undefined, unsubNotif: undefined, + pingmsg: undefined, + pongmsg: undefined, imu: undefined, imuCalibrate: undefined, mode: undefined, @@ -1026,6 +1154,12 @@ export const WebsocketMessage: MessageFns = { if (message.unsubNotif !== undefined) { UnsubscribeNotification.encode(message.unsubNotif, writer.uint32(170).fork()).join(); } + if (message.pingmsg !== undefined) { + PingMsg.encode(message.pingmsg, writer.uint32(242).fork()).join(); + } + if (message.pongmsg !== undefined) { + PongMsg.encode(message.pongmsg, writer.uint32(250).fork()).join(); + } if (message.imu !== undefined) { IMUData.encode(message.imu, writer.uint32(882).fork()).join(); } @@ -1100,6 +1234,22 @@ export const WebsocketMessage: MessageFns = { message.unsubNotif = UnsubscribeNotification.decode(reader, reader.uint32()); continue; } + case 30: { + if (tag !== 242) { + break; + } + + message.pingmsg = PingMsg.decode(reader, reader.uint32()); + continue; + } + case 31: { + if (tag !== 250) { + break; + } + + message.pongmsg = PongMsg.decode(reader, reader.uint32()); + continue; + } case 110: { if (tag !== 882) { break; @@ -1241,6 +1391,8 @@ export const WebsocketMessage: MessageFns = { return { subNotif: isSet(object.subNotif) ? SubscribeNotification.fromJSON(object.subNotif) : undefined, unsubNotif: isSet(object.unsubNotif) ? UnsubscribeNotification.fromJSON(object.unsubNotif) : undefined, + pingmsg: isSet(object.pingmsg) ? PingMsg.fromJSON(object.pingmsg) : undefined, + pongmsg: isSet(object.pongmsg) ? PongMsg.fromJSON(object.pongmsg) : undefined, imu: isSet(object.imu) ? IMUData.fromJSON(object.imu) : undefined, imuCalibrate: isSet(object.imuCalibrate) ? IMUCalibrateData.fromJSON(object.imuCalibrate) : undefined, mode: isSet(object.mode) ? ModeData.fromJSON(object.mode) : undefined, @@ -1270,6 +1422,12 @@ export const WebsocketMessage: MessageFns = { if (message.unsubNotif !== undefined) { obj.unsubNotif = UnsubscribeNotification.toJSON(message.unsubNotif); } + if (message.pingmsg !== undefined) { + obj.pingmsg = PingMsg.toJSON(message.pingmsg); + } + if (message.pongmsg !== undefined) { + obj.pongmsg = PongMsg.toJSON(message.pongmsg); + } if (message.imu !== undefined) { obj.imu = IMUData.toJSON(message.imu); } @@ -1332,6 +1490,12 @@ export const WebsocketMessage: MessageFns = { message.unsubNotif = (object.unsubNotif !== undefined && object.unsubNotif !== null) ? UnsubscribeNotification.fromPartial(object.unsubNotif) : undefined; + message.pingmsg = (object.pingmsg !== undefined && object.pingmsg !== null) + ? PingMsg.fromPartial(object.pingmsg) + : undefined; + message.pongmsg = (object.pongmsg !== undefined && object.pongmsg !== null) + ? PongMsg.fromPartial(object.pongmsg) + : undefined; message.imu = (object.imu !== undefined && object.imu !== null) ? IMUData.fromPartial(object.imu) : undefined; message.imuCalibrate = (object.imuCalibrate !== undefined && object.imuCalibrate !== null) ? IMUCalibrateData.fromPartial(object.imuCalibrate) @@ -1683,7 +1847,19 @@ export const protoMetadata: ProtoMetadata = { "visibility": 0, }, { "name": "SubscribeNotification", - "field": [], + "field": [{ + "name": "tag", + "number": 1, + "label": 1, + "type": 5, + "typeName": "", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "tag", + "options": undefined, + "proto3Optional": false, + }], "extension": [], "nestedType": [], "enumType": [], @@ -1695,6 +1871,42 @@ export const protoMetadata: ProtoMetadata = { "visibility": 0, }, { "name": "UnsubscribeNotification", + "field": [{ + "name": "tag", + "number": 1, + "label": 1, + "type": 5, + "typeName": "", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "tag", + "options": undefined, + "proto3Optional": false, + }], + "extension": [], + "nestedType": [], + "enumType": [], + "extensionRange": [], + "oneofDecl": [], + "options": undefined, + "reservedRange": [], + "reservedName": [], + "visibility": 0, + }, { + "name": "PingMsg", + "field": [], + "extension": [], + "nestedType": [], + "enumType": [], + "extensionRange": [], + "oneofDecl": [], + "options": undefined, + "reservedRange": [], + "reservedName": [], + "visibility": 0, + }, { + "name": "PongMsg", "field": [], "extension": [], "nestedType": [], @@ -1731,6 +1943,30 @@ export const protoMetadata: ProtoMetadata = { "jsonName": "unsubNotif", "options": undefined, "proto3Optional": false, + }, { + "name": "pingmsg", + "number": 30, + "label": 1, + "type": 11, + "typeName": ".PingMsg", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "pingmsg", + "options": undefined, + "proto3Optional": false, + }, { + "name": "pongmsg", + "number": 31, + "label": 1, + "type": 11, + "typeName": ".PongMsg", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "pongmsg", + "options": undefined, + "proto3Optional": false, }, { "name": "imu", "number": 110, @@ -1946,8 +2182,8 @@ export const protoMetadata: ProtoMetadata = { "trailingComments": "", "leadingDetachedComments": [], }, { - "path": [4, 18], - "span": [32, 0, 53, 1], + "path": [4, 20], + "span": [35, 0, 58, 1], "leadingComments": " WebSocket message wrapper\n Only ONE field will be set at a time (oneof ensures this)\n", "trailingComments": "", "leadingDetachedComments": [], @@ -1975,6 +2211,8 @@ export const protoMetadata: ProtoMetadata = { ".RSSIData": RSSIData, ".SubscribeNotification": SubscribeNotification, ".UnsubscribeNotification": UnsubscribeNotification, + ".PingMsg": PingMsg, + ".PongMsg": PongMsg, ".WebsocketMessage": WebsocketMessage, }, dependencies: [], diff --git a/app/src/lib/stores/socket.ts b/app/src/lib/stores/socket.ts index 68aef02..c608dda 100644 --- a/app/src/lib/stores/socket.ts +++ b/app/src/lib/stores/socket.ts @@ -6,9 +6,9 @@ import type { BinaryWriter } from '@bufbuild/protobuf/wire' // -------- START PARSING PROTO DATA -------- -// Auto-build reverse mapping from MessageFns to event key and field number +// Auto-build reverse mapping from MessageFns to event key and tag const MESSAGE_TYPE_TO_KEY = new Map, string>() -const MESSAGE_TYPE_TO_FIELD_NUMBER = new Map, number>() +const MESSAGE_TYPE_TO_TAG = new Map, number>() // Build the mapping using references from metadata const websocketMessageType = websocket_md.fileDescriptor.messageType?.find( @@ -22,7 +22,7 @@ if (websocketMessageType?.field) { const messageFns = websocket_md.references[field.typeName] if (messageFns && field.jsonName && field.number) { MESSAGE_TYPE_TO_KEY.set(messageFns, field.jsonName) - MESSAGE_TYPE_TO_FIELD_NUMBER.set(messageFns, field.number) + MESSAGE_TYPE_TO_TAG.set(messageFns, field.number) } } } @@ -36,11 +36,11 @@ function get_name_from_messagetype(event_type: MessageFns): string { return event } -// Get field number from MessageFns type -function get_field_number_from_messagetype(event_type: MessageFns): number { - const fieldNumber = MESSAGE_TYPE_TO_FIELD_NUMBER.get(event_type) +// Get tag from MessageFns type +function get_tag_from_messagetype(event_type: MessageFns): number { + const fieldNumber = MESSAGE_TYPE_TO_TAG.get(event_type) if (fieldNumber === undefined) { - throw new Error("Field number not found in 'WebsocketMessage'. The MessageFns you passed doesn't correspond to any WebsocketMessage field."); + throw new Error("Tag not found in 'WebsocketMessage'. The MessageFns you passed doesn't correspond to any WebsocketMessage field."); } return fieldNumber } @@ -85,8 +85,10 @@ function createWebSocket() { connect() } - function getListeners(event_type: MessageFns): Set<(data?: unknown) => void> { - const event = get_field_number_from_messagetype(event_type); + function getListeners(event: MessageFns | string): Set<(data?: unknown) => void> { + if (typeof event != "string") { // Parse messagefns to string + event = get_name_from_messagetype(event) + } const event_listeners = listeners.get(event); if (event_listeners == undefined) { @@ -112,10 +114,11 @@ function createWebSocket() { set(true) clearTimeout(reconnectTimeoutId) listeners.get('open')?.forEach(listener => listener(ev)) - for (const event of listeners.keys()) { - if (socketEvents.includes(event as SocketEvent)) continue - subscribeToEvent(event) - } + // TODO: Check if this makes sense? we also call subscribe to event when a new listen calls the "on" function + // for (const event of listeners.keys()) { + // if (socketEvents.includes(event as SocketEvent)) continue + // subscribeToEvent(event) + // } } ws.onmessage = frame => { resetUnresponsiveCheck() @@ -126,12 +129,13 @@ function createWebSocket() { ws.onclose = ev => disconnect('close', ev) } - function unsubscribe(event: string, listener?: (data: unknown) => void) { + function unsubscribe(event_type: MessageFns, listener?: (data: unknown) => void) { + const event = get_name_from_messagetype(event_type) const eventListeners = listeners.get(event) if (!eventListeners) return if (!eventListeners.size) { - unsubscribeToEvent(event) + unsubscribeToEvent(event_type) } if (listener) { eventListeners?.delete(listener) @@ -148,20 +152,28 @@ function createWebSocket() { // T must extend a type of WebsocketMessages function sendEvent(event: MessageFns, data: T) { if (!ws || ws.readyState !== WebSocket.OPEN) return - const type = get_event_from_messagetype(event); + const type = get_name_from_messagetype(event); const wsm = WebsocketMessage.create(); (wsm as any)[type] = data send(wsm) } - function unsubscribeToEvent(event: string) { + function unsubscribeToEvent(event_type: MessageFns) { if (!ws || ws.readyState !== WebSocket.OPEN) return - send([1, event]) + const event = get_name_from_messagetype(event_type); + const unsub_msg = WebsocketMessages.UnsubscribeNotification.create( + {tag: get_tag_from_messagetype(event_type)} + ); + send(WebsocketMessage.create({unsubNotif: unsub_msg})); } - function subscribeToEvent(event: string) { + function subscribeToEvent(event_type: MessageFns) { if (!ws || ws.readyState !== WebSocket.OPEN) return - send([0, event]) + const event = get_name_from_messagetype(event_type); + const sub_msg = WebsocketMessages.SubscribeNotification.create( + {tag: get_tag_from_messagetype(event_type)} + ); + send(WebsocketMessage.create({subNotif: sub_msg})); } function send(data: WebsocketMessage) { @@ -171,12 +183,7 @@ function createWebSocket() { } function ping() { - const serialized = encodeMessage([4]) - if (!serialized) { - console.error('Could not serialize message') - return - } - ws.send(serialized) + send(WebsocketMessage.create({pingmsg: {}})) } return { @@ -184,12 +191,13 @@ function createWebSocket() { sendEvent, init, on: (event_type: MessageFns, listener: (data: T) => void): (() => void) => { - const event = get_event_from_messagetype(event_type); + const event = get_name_from_messagetype(event_type); let eventListeners = listeners.get(event) if (!eventListeners) { + // If this is the first listener to this event, also call subscribe to the server if (!socketEvents.includes(event as SocketEvent)) { - subscribeToEvent(event) + subscribeToEvent(event_type) } eventListeners = new Set() listeners.set(event, eventListeners) @@ -197,13 +205,11 @@ function createWebSocket() { eventListeners.add(listener as (data: unknown) => void) return () => { - unsubscribe(event, listener as (data: unknown) => void) + unsubscribe(event_type, listener as (data: unknown) => void) } }, off: (event_type: MessageFns, listener: (data: T) => void) => { - const event = get_event_from_messagetype(event_type); - - unsubscribe(event, listener as (data: unknown) => void) + unsubscribe(event_type, listener as (data: unknown) => void) } } } diff --git a/platform_shared/websocket_message.proto b/platform_shared/websocket_message.proto index 9a990be..e9a3778 100644 --- a/platform_shared/websocket_message.proto +++ b/platform_shared/websocket_message.proto @@ -24,14 +24,11 @@ message WifiSettingsData {} message SonarData {} message RSSIData { int32 rssi = 1; } -message SubscribeNotification {} -message UnsubscribeNotification {} +message SubscribeNotification { int32 tag = 1; } +message UnsubscribeNotification {int32 tag = 1; } -message InternalOpen {} -message InternalClose {} -message InternalError {} -message InternalMessage {} -message InternalUnresponsive {} +message PingMsg {} +message PongMsg {} // WebSocket message wrapper @@ -40,6 +37,8 @@ message WebsocketMessage { oneof message { SubscribeNotification sub_notif = 20; UnsubscribeNotification unsub_notif = 21; + PingMsg pingmsg = 30; + PongMsg pongmsg = 31; IMUData imu = 110; IMUCalibrateData imu_calibrate = 120; ModeData mode = 130;