Skip to content
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
84 changes: 74 additions & 10 deletions src/Commands/Messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,15 @@ export interface MessageTransformer<TMessage extends Conf.MessageArrayLike> {
transformerType: Conf.MessageArrayLikeType;
combineMessages(...messages: TMessage[]): TMessage;

messageToString(message: TMessage): string;
messageToUint8Array(message: TMessage): Uint8Array;
as<TTarget extends Conf.MessageArrayLike>(
msg: Conf.MessageArrayLike,
targetType: TTarget,
): TTarget;

asType<TTarget extends Conf.MessageArrayLike>(
msg: Conf.MessageArrayLike,
targetType: Conf.MessageArrayLikeType,
): TTarget;
}

export class RawMessageTransformer implements MessageTransformer<Uint8Array> {
Expand All @@ -34,12 +41,32 @@ export class RawMessageTransformer implements MessageTransformer<Uint8Array> {
).buffer;
}

messageToString(message: Uint8Array): string {
return asString(message);
as<TTarget extends Conf.MessageArrayLike>(
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<TTarget extends Conf.MessageArrayLike>(
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;
}
}
}

Expand All @@ -49,11 +76,33 @@ export class StringMessageTransformer implements MessageTransformer<string> {
combineMessages(...messages: string[]): string {
return messages.join('');
}
messageToString(message: string): string {
return message;

as<TTarget extends Conf.MessageArrayLike>(
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<TTarget extends Conf.MessageArrayLike>(
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;
}
}
}

Expand Down Expand Up @@ -90,6 +139,21 @@ export function asTargetMessageType<TMessage extends Conf.MessageArrayLike>(
}
}

export function asTargetMessageLikeType<TMessage extends Conf.MessageArrayLike>(
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<boolean>,
Expand Down
2 changes: 1 addition & 1 deletion src/Languages/Epl/Messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function handleMessage<TReceived extends Conf.MessageArrayLike>(
messages: [],
remainder: message,
}
const msg = Cmds.asString(message);
const msg = Cmds.asTargetMessageLikeType<string>(message, 'string');
let remainder = msg;
if (msg === undefined || msg.length === 0) { return result; }

Expand Down
2 changes: 1 addition & 1 deletion src/Languages/Zpl/Messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function handleMessage<TReceived extends Conf.MessageArrayLike>(
messages: [],
remainder: message,
}
const msg = Cmds.asString(message).trimStart();
const msg = Cmds.asTargetMessageLikeType<string>(message, 'string').trimStart();
let remainder = msg;
if (msg === undefined || msg.length === 0) { return result; }

Expand Down
40 changes: 6 additions & 34 deletions src/Printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,6 @@ export interface LabelPrinterEventMap {
reportedError: CustomEvent<Cmds.IErrorMessage>;
}

function promiseWithTimeout<T>(
promise: Promise<T>,
ms: number,
timeoutError = new Error('Promise timed out')
): Promise<T> {
// create a promise that rejects in milliseconds
const timeout = new Promise<never>((_, reject) => {
setTimeout(() => {
reject(timeoutError);
}, ms);
});

// returns a race between timeout and the passed promise
return Promise.race<T>([promise, timeout]);
}

/** Type alias for a Label Printer that communicates over USB. */
export type LabelPrinterUsb = LabelPrinter<Uint8Array>;

Expand Down Expand Up @@ -339,34 +323,22 @@ export class LabelPrinter<TChannelType extends Conf.MessageArrayLike> 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),
await Util.promiseWithTimeout(
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?`)
);

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.`)
Expand Down
11 changes: 11 additions & 0 deletions src/Util/PromiseUtils.test.ts
Original file line number Diff line number Diff line change
@@ -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);
})
});
15 changes: 15 additions & 0 deletions src/Util/PromiseUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export function promiseWithTimeout<T>(
promise: Promise<T>,
ms: number,
timeoutError = new Error('Promise timed out')
): Promise<T> {
// create a promise that rejects in milliseconds
const timeout = new Promise<never>((_, reject) => {
setTimeout(() => {
reject(timeoutError);
}, ms);
});

// returns a race between timeout and the passed promise
return Promise.race<T>([promise, timeout]);
}
1 change: 1 addition & 0 deletions src/Util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './EnumUtils.js';
export * from './NumericRange.js';
export * from './StringUtils.js';
export * from './WebZlpError.js';
export * from './PromiseUtils.js';