From 04fbef36c42938fc20606f1fa5e3bc9f2c2db206 Mon Sep 17 00:00:00 2001 From: Cellivar <1441553+Cellivar@users.noreply.github.com> Date: Wed, 1 Jan 2025 23:55:44 -0800 Subject: [PATCH 1/2] Add better type checking for message transforming --- src/Commands/Messages.ts | 84 ++++++++++++++++++++++++++++++----- src/Languages/Epl/Messages.ts | 2 +- src/Languages/Zpl/Messages.ts | 2 +- src/Printer.ts | 20 ++------- 4 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/Commands/Messages.ts b/src/Commands/Messages.ts index f9f3be7..d3a61a2 100644 --- a/src/Commands/Messages.ts +++ b/src/Commands/Messages.ts @@ -16,8 +16,15 @@ export interface MessageTransformer { transformerType: Conf.MessageArrayLikeType; combineMessages(...messages: TMessage[]): TMessage; - messageToString(message: TMessage): string; - messageToUint8Array(message: TMessage): Uint8Array; + as( + msg: Conf.MessageArrayLike, + targetType: TTarget, + ): TTarget; + + asType( + msg: Conf.MessageArrayLike, + targetType: Conf.MessageArrayLikeType, + ): TTarget; } export class RawMessageTransformer implements MessageTransformer { @@ -34,12 +41,32 @@ export class RawMessageTransformer implements MessageTransformer { ).buffer; } - messageToString(message: Uint8Array): string { - return asString(message); + as( + msg: Conf.MessageArrayLike, + targetType: TTarget, + ): TTarget { + if (typeof targetType === "string") { + return asString(msg) as TTarget; + } else if (targetType instanceof Uint8Array) { + return msg as TTarget; + } else { + throw new Error("Unknown message type not implemented!"); + } } - messageToUint8Array(message: Uint8Array): Uint8Array { - return message; + asType( + msg: Conf.MessageArrayLike, + targetType: Conf.MessageArrayLikeType, + ): TTarget { + switch(targetType) { + default: + Util.exhaustiveMatchGuard(targetType); + break; + case 'string': + return asString(msg) as TTarget; + case 'Uint8Array': + return msg as TTarget; + } } } @@ -49,11 +76,33 @@ export class StringMessageTransformer implements MessageTransformer { combineMessages(...messages: string[]): string { return messages.join(''); } - messageToString(message: string): string { - return message; + + as( + msg: Conf.MessageArrayLike, + targetType: TTarget, + ): TTarget { + if (typeof targetType === "string") { + return msg as TTarget; + } else if (targetType instanceof Uint8Array) { + return asUint8Array(msg) as TTarget; + } else { + throw new Error("Unknown message type not implemented!"); + } } - messageToUint8Array(message: string): Uint8Array { - return asUint8Array(message); + + asType( + msg: Conf.MessageArrayLike, + targetType: Conf.MessageArrayLikeType, + ): TTarget { + switch(targetType) { + default: + Util.exhaustiveMatchGuard(targetType); + break; + case 'string': + return msg as TTarget; + case 'Uint8Array': + return asUint8Array(msg) as TTarget; + } } } @@ -90,6 +139,21 @@ export function asTargetMessageType( } } +export function asTargetMessageLikeType( + msg: Conf.MessageArrayLike, + targetType: Conf.MessageArrayLikeType, +): TMessage { + switch(targetType) { + default: + Util.exhaustiveMatchGuard(targetType); + break; + case 'Uint8Array': + return asUint8Array(msg) as TMessage; + case 'string': + return asString(msg) as TMessage; + } +} + export type AwaitedCommand = { cmd: IPrinterCommand, promise: Promise, diff --git a/src/Languages/Epl/Messages.ts b/src/Languages/Epl/Messages.ts index fcdc5cc..5b76da8 100644 --- a/src/Languages/Epl/Messages.ts +++ b/src/Languages/Epl/Messages.ts @@ -15,7 +15,7 @@ export function handleMessage( messages: [], remainder: message, } - const msg = Cmds.asString(message); + const msg = Cmds.asTargetMessageLikeType(message, 'string'); let remainder = msg; if (msg === undefined || msg.length === 0) { return result; } diff --git a/src/Languages/Zpl/Messages.ts b/src/Languages/Zpl/Messages.ts index 31db654..deaee04 100644 --- a/src/Languages/Zpl/Messages.ts +++ b/src/Languages/Zpl/Messages.ts @@ -13,7 +13,7 @@ export function handleMessage( messages: [], remainder: message, } - const msg = Cmds.asString(message).trimStart(); + const msg = Cmds.asTargetMessageLikeType(message, 'string').trimStart(); let remainder = msg; if (msg === undefined || msg.length === 0) { return result; } diff --git a/src/Printer.ts b/src/Printer.ts index 694dbd5..92754e4 100644 --- a/src/Printer.ts +++ b/src/Printer.ts @@ -339,26 +339,14 @@ export class LabelPrinter extends Ev }); this.logResultIfDebug(() => { - const debugMsg = Cmds.asString(transaction.commands); + const debugMsg = this._channelMessageTransformer.asType(transaction.commands, 'string'); return `Transaction being sent to printer:\n${debugMsg}\n--end of transaction--`; }); - // TODO: Better type guards?? - let sendCmds: TChannelType; - switch(this._channelType) { - default: - Util.exhaustiveMatchGuard(this._channelType); - break; - case 'Uint8Array': - sendCmds = Cmds.asUint8Array(transaction.commands) as TChannelType; - break; - case 'string': - sendCmds = Cmds.asString(transaction.commands) as TChannelType; - break; - } - await promiseWithTimeout( - this._channel.send(sendCmds), + this._channel.send( + Cmds.asTargetMessageLikeType(transaction.commands, this._channelType) + ), 5000, new Mux.DeviceCommunicationError(`Timed out sending commands to printer, is there a problem with the printer?`) ); From 9caadf1bbcf94b06baf258140bad10b545a3d511 Mon Sep 17 00:00:00 2001 From: Cellivar <1441553+Cellivar@users.noreply.github.com> Date: Thu, 13 Mar 2025 11:19:58 -0700 Subject: [PATCH 2/2] Move promise timeout method to utils --- src/Printer.ts | 20 ++------------------ src/Util/PromiseUtils.test.ts | 11 +++++++++++ src/Util/PromiseUtils.ts | 15 +++++++++++++++ src/Util/index.ts | 1 + 4 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 src/Util/PromiseUtils.test.ts create mode 100644 src/Util/PromiseUtils.ts diff --git a/src/Printer.ts b/src/Printer.ts index 92754e4..d07f479 100644 --- a/src/Printer.ts +++ b/src/Printer.ts @@ -12,22 +12,6 @@ export interface LabelPrinterEventMap { reportedError: CustomEvent; } -function promiseWithTimeout( - promise: Promise, - ms: number, - timeoutError = new Error('Promise timed out') -): Promise { - // create a promise that rejects in milliseconds - const timeout = new Promise((_, reject) => { - setTimeout(() => { - reject(timeoutError); - }, ms); - }); - - // returns a race between timeout and the passed promise - return Promise.race([promise, timeout]); -} - /** Type alias for a Label Printer that communicates over USB. */ export type LabelPrinterUsb = LabelPrinter; @@ -343,7 +327,7 @@ export class LabelPrinter extends Ev return `Transaction being sent to printer:\n${debugMsg}\n--end of transaction--`; }); - await promiseWithTimeout( + await Util.promiseWithTimeout( this._channel.send( Cmds.asTargetMessageLikeType(transaction.commands, this._channelType) ), @@ -354,7 +338,7 @@ export class LabelPrinter extends Ev try { if (this._awaitedCommands.length > 0) { this.logIfDebug(`Awaiting response to ${this._awaitedCommands.length} commands for up to ${this._awaitedCommandTimeoutMS}ms...`); - await promiseWithTimeout( + await Util.promiseWithTimeout( Promise.all(this._awaitedCommands.map(c => c.promise)), this._awaitedCommandTimeoutMS, new Mux.DeviceCommunicationError(`Timed out waiting for sent command response, expected ${this._awaitedCommands.length} responses.`) diff --git a/src/Util/PromiseUtils.test.ts b/src/Util/PromiseUtils.test.ts new file mode 100644 index 0000000..b459943 --- /dev/null +++ b/src/Util/PromiseUtils.test.ts @@ -0,0 +1,11 @@ +import { expect, describe, it } from 'vitest'; +import { promiseWithTimeout } from './PromiseUtils.js'; + + +describe('promiseWithtimeout', () => { + it('Completes a promise before a timeout', async () => { + const complete = Promise.resolve(true); + const out = await promiseWithTimeout(complete, 100); + expect(out).toBe(await complete); + }) +}); diff --git a/src/Util/PromiseUtils.ts b/src/Util/PromiseUtils.ts new file mode 100644 index 0000000..3571492 --- /dev/null +++ b/src/Util/PromiseUtils.ts @@ -0,0 +1,15 @@ +export function promiseWithTimeout( + promise: Promise, + ms: number, + timeoutError = new Error('Promise timed out') +): Promise { + // create a promise that rejects in milliseconds + const timeout = new Promise((_, reject) => { + setTimeout(() => { + reject(timeoutError); + }, ms); + }); + + // returns a race between timeout and the passed promise + return Promise.race([promise, timeout]); +} diff --git a/src/Util/index.ts b/src/Util/index.ts index 9490149..cfdcb73 100644 --- a/src/Util/index.ts +++ b/src/Util/index.ts @@ -4,3 +4,4 @@ export * from './EnumUtils.js'; export * from './NumericRange.js'; export * from './StringUtils.js'; export * from './WebZlpError.js'; +export * from './PromiseUtils.js';