feat: add printer connector with job queue

This commit is contained in:
Developer 2026-02-12 08:04:20 +00:00
parent 400b716623
commit 002f6dc8f3
2 changed files with 159 additions and 0 deletions

134
src/printer/connector.ts Normal file
View File

@ -0,0 +1,134 @@
interface PrinterConfig {
ip: string;
port: number;
timeout?: number;
}
interface PrintJob {
id: string;
data: Uint8Array;
status: 'pending' | 'printing' | 'completed' | 'failed';
createdAt: Date;
startedAt?: Date;
completedAt?: Date;
error?: string;
}
export class PrinterConnector {
private config: PrinterConfig;
private queueItems: PrintJob[] = [];
private currentJob: PrintJob | null = null;
private connected = false;
private processing = false;
constructor(config: PrinterConfig) {
this.config = {
timeout: 5000,
...config
};
}
isConnected(): boolean {
return this.connected;
}
getQueueLength(): number {
return this.queueItems.length + (this.currentJob ? 1 : 0);
}
queue(data: Uint8Array): string {
const job: PrintJob = {
id: `job_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
data,
status: 'pending',
createdAt: new Date()
};
this.queueItems.push(job);
this.processQueue();
return job.id;
}
getJob(jobId: string): PrintJob | undefined {
if (this.currentJob?.id === jobId) return this.currentJob;
return this.queueItems.find(j => j.id === jobId);
}
getAllJobs(): PrintJob[] {
return this.currentJob
? [this.currentJob, ...this.queueItems]
: [...this.queueItems];
}
cancelJob(jobId: string): boolean {
const index = this.queueItems.findIndex(j => j.id === jobId);
if (index >= 0 && this.queueItems[index].status === 'pending') {
this.queueItems[index].status = 'cancelled' as any;
this.queueItems.splice(index, 1);
return true;
}
return false;
}
async processQueue(): Promise<void> {
if (this.processing || this.queueItems.length === 0) return;
this.processing = true;
while (this.queueItems.length > 0) {
const job = this.queueItems.shift()!;
this.currentJob = job;
job.status = 'printing';
job.startedAt = new Date();
try {
await this.sendToPrinter(job.data);
job.status = 'completed';
job.completedAt = new Date();
} catch (error) {
job.status = 'failed';
job.error = String(error);
console.error(`Print job ${job.id} failed:`, error);
}
}
this.currentJob = null;
this.processing = false;
}
private async sendToPrinter(data: Uint8Array): Promise<void> {
return new Promise((resolve, reject) => {
const socket = new (Bun as any).connect({
hostname: this.config.ip,
port: this.config.port,
});
socket.then((conn: any) => {
this.connected = true;
conn.write(data);
conn.end();
setTimeout(() => {
this.connected = false;
resolve();
}, 1000);
}).catch((err: any) => {
this.connected = false;
reject(err);
});
});
}
async getStatus(): Promise<{ online: boolean; paperStatus: string }> {
try {
const socket = await (Bun as any).connect({
hostname: this.config.ip,
port: this.config.port,
});
socket.end();
return { online: true, paperStatus: 'ok' };
} catch {
return { online: false, paperStatus: 'unknown' };
}
}
}

25
tests/connector.test.ts Normal file
View File

@ -0,0 +1,25 @@
import { describe, it, expect } from 'bun:test';
import { PrinterConnector } from '../src/printer/connector';
describe('Printer Connector', () => {
it('should create connector with config', () => {
const connector = new PrinterConnector({
ip: '192.168.1.100',
port: 9100
});
expect(connector).toBeDefined();
expect(connector.isConnected()).toBe(false);
});
it('should queue print jobs', () => {
const connector = new PrinterConnector({
ip: '192.168.1.100',
port: 9100
});
const data = new Uint8Array([0x1B, 0x40]);
const jobId = connector.queue(data);
expect(jobId).toMatch(/^job_/);
expect(connector.getQueueLength()).toBe(1);
});
});