From 07295de6ae9a259f873d81053af4b1b67f68a086 Mon Sep 17 00:00:00 2001 From: Edward Choi Date: Sun, 29 May 2022 19:16:04 -0700 Subject: [PATCH] Add more robust error handling (#162) Co-authored-by: Hailey Jang <55821834+HaileyJang@users.noreply.github.com> --- main/networking/Runtime.ts | 105 ++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 37 deletions(-) diff --git a/main/networking/Runtime.ts b/main/networking/Runtime.ts index 69bdeff7..fd370ddb 100644 --- a/main/networking/Runtime.ts +++ b/main/networking/Runtime.ts @@ -104,36 +104,41 @@ function readPackets(data: Buffer, previousLeftoverBytes?: Buffer): { leftoverBy * Create TCP packet header and prepend to * payload to send to Runtime. */ -function createPacket(payload: unknown, messageType: MsgType): Buffer { +function createPacket(payload: unknown, messageType: MsgType): Buffer | null { let encodedPayload: Uint8Array; - switch (messageType) { - case MsgType.DEVICE_DATA: - encodedPayload = protos.DevData.encode(payload as protos.IDevData).finish(); - break; - case MsgType.RUN_MODE: - encodedPayload = protos.RunMode.encode(payload as protos.IRunMode).finish(); - break; - case MsgType.START_POS: - encodedPayload = protos.StartPos.encode(payload as protos.IStartPos).finish(); - break; - case MsgType.TIME_STAMPS: - encodedPayload = protos.TimeStamps.encode(payload as protos.ITimeStamps).finish(); - break; - case MsgType.INPUTS: - encodedPayload = protos.UserInputs.encode({ inputs: payload as protos.Input[] }).finish(); - break; - default: - console.log('ERROR: trying to create TCP Packet with unknown message type'); - encodedPayload = new Uint8Array(); - break; - } + try { + switch (messageType) { + case MsgType.DEVICE_DATA: + encodedPayload = protos.DevData.encode(payload as protos.IDevData).finish(); + break; + case MsgType.RUN_MODE: + encodedPayload = protos.RunMode.encode(payload as protos.IRunMode).finish(); + break; + case MsgType.START_POS: + encodedPayload = protos.StartPos.encode(payload as protos.IStartPos).finish(); + break; + case MsgType.TIME_STAMPS: + encodedPayload = protos.TimeStamps.encode(payload as protos.ITimeStamps).finish(); + break; + case MsgType.INPUTS: + encodedPayload = protos.UserInputs.encode({ inputs: payload as protos.Input[] }).finish(); + break; + default: + console.log('ERROR: trying to create TCP Packet with unknown message type'); + encodedPayload = new Uint8Array(); + break; + } - const msgLength = Buffer.byteLength(encodedPayload); - const msgLengthArr = new Uint8Array([msgLength & 0x00ff, msgLength & 0xff00]); // Assuming little-endian byte order, since runs on x64 - const msgTypeArr = new Uint8Array([messageType]); + const msgLength = Buffer.byteLength(encodedPayload); + const msgLengthArr = new Uint8Array([msgLength & 0x00ff, msgLength & 0xff00]); // Assuming little-endian byte order, since runs on x64 + const msgTypeArr = new Uint8Array([messageType]); - return Buffer.concat([msgTypeArr, msgLengthArr, encodedPayload], msgLength + 3); + return Buffer.concat([msgTypeArr, msgLengthArr, encodedPayload], msgLength + 3); + } catch (err) { + console.log(err); + return null; + } } class RuntimeConnection { @@ -189,16 +194,24 @@ class RuntimeConnection { switch (packet.type) { case MsgType.LOG: - decoded = protos.Text.decode(packet.payload); - RendererBridge.reduxDispatch(updateConsole(decoded.payload)); + try { + decoded = protos.Text.decode(packet.payload); + RendererBridge.reduxDispatch(updateConsole(decoded.payload)); + } catch (err) { + this.logger.log(err); + } break; case MsgType.TIME_STAMPS: - decoded = protos.TimeStamps.decode(packet.payload); - const oneWayLatency = (Date.now() - Number(decoded.dawnTimestamp)) / 2; + try { + decoded = protos.TimeStamps.decode(packet.payload); + const oneWayLatency = (Date.now() - Number(decoded.dawnTimestamp)) / 2; - // TODO: we can probably do an average of n timestamps so the display doesn't change too frequently - RendererBridge.reduxDispatch(setLatencyValue(oneWayLatency)); + // TODO: we can probably do an average of n timestamps so the display doesn't change too frequently + RendererBridge.reduxDispatch(setLatencyValue(oneWayLatency)); + } catch (err) { + this.logger.log(err); + } break; case MsgType.DEVICE_DATA: @@ -227,7 +240,7 @@ class RuntimeConnection { break; default: - this.logger.log(`Unsupported received message type: ${packet.type}`) + this.logger.log(`Unsupported received message type: ${packet.type}`); } } @@ -252,6 +265,24 @@ class RuntimeConnection { return cb(event, ...args); }; + sendMessage = (message: Buffer | null, cb?: ((err?: Error | undefined) => void) | undefined) => { + if (message == null) { + return; + } + + this.socket.write(message, cb); + }; + + /** + * Initiates latency check by sending first packet to Runtime + */ + initiateLatencyCheck = (_event: IpcMainEvent, data: protos.ITimeStamps) => { + const message = createPacket(data, MsgType.TIME_STAMPS); + this.sendMessage(message, () => { + this.logger.log(`Sent timestamp data to runtime: ${JSON.stringify(data)}`); + }); + }; + /** * IPC Connection with ConfigBox.ts' saveChanges() * Receives new IP Address to send messages to. @@ -274,7 +305,7 @@ class RuntimeConnection { */ sendRunMode = (_event: IpcMainEvent, runModeData: protos.IRunMode) => { const message = createPacket(runModeData, MsgType.RUN_MODE); - this.socket.write(message, () => { + this.sendMessage(message, () => { this.logger.log(`Run Mode message sent: ${JSON.stringify(runModeData)}`); }); }; @@ -282,7 +313,7 @@ class RuntimeConnection { sendDevicePreferences = (_event: IpcMainEvent, deviceData: protos.IDevData) => { // TODO: Serialize uid from string -> Long type const message = createPacket(deviceData, MsgType.DEVICE_DATA); - this.socket.write(message, () => { + this.sendMessage(message, () => { this.logger.log(`Device preferences sent: ${deviceData.toString()}`); }); }; @@ -290,7 +321,7 @@ class RuntimeConnection { sendRobotStartPos = (_event: IpcMainEvent, startPosData: protos.IStartPos) => { // TODO: Get start pos from sagas const message = createPacket(startPosData, MsgType.START_POS); - this.socket.write(message, () => { + this.sendMessage(message, () => { this.logger.log(`Start position sent: ${startPosData.toString()}`); }); }; @@ -305,7 +336,7 @@ class RuntimeConnection { ); } const message = createPacket(data, MsgType.INPUTS); - this.socket.write(message, (err?: Error) => { + this.sendMessage(message, (err?: Error) => { if (err !== undefined) { this.logger.log(`Error when sending inputs: ${JSON.stringify(err)}`); }