Skip to content

Commit

Permalink
multiple printers
Browse files Browse the repository at this point in the history
  • Loading branch information
enoy19 committed Aug 3, 2023
1 parent b470fd0 commit d331f5d
Show file tree
Hide file tree
Showing 22 changed files with 635 additions and 111 deletions.
13 changes: 12 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"dependencies": {
"neat-csv": "^7.0.0",
"serialport": "^11.0.1",
"svelte-local-storage-store": "^0.5.0",
"throttle-debounce": "^5.0.0"
}
}
18 changes: 18 additions & 0 deletions src/lib/components/PrintButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script lang="ts">
import { persisted } from 'svelte-local-storage-store';
let selectedPrinter = persisted('selectedPrinter', undefined);
export let printers: string[];
export let buttonLabel: string = 'Print';
export let buttonColor: string = 'variant-filled-primary';
</script>

<div class="input-group input-group-divider grid-cols-[auto_1fr] mt-3">
<select class="select" name="printer" bind:value={$selectedPrinter} required>
{#each printers as printer}
<option value={printer}>{printer}</option>
{/each}
</select>
<button type="submit" class="btn {buttonColor} w-full">{buttonLabel}</button>
</div>
31 changes: 31 additions & 0 deletions src/lib/components/TemplateList.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script lang="ts">
import { enhance } from "$app/forms";
import { confirmed } from "$lib/use/buttonConfirmed";
import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher<{
templateSelected: string
}>();
export let templateNames: string[];
</script>

{#if templateNames.length <= 0}
<span>No Templates yet, start by entering ZPL into the editor below and Save the Template</span>
{:else}
{#each templateNames as templateName, i (`${i}_${templateName}`)}
<div class="flex gap-1 w-full">
<a href={`/p/${templateName}`} class="btn variant-ghost-tertiary">Print</a>
<button class="btn variant-ghost-secondary w-full" on:click={() => dispatch('templateSelected', templateName)}
>{templateName}</button
>
<form method="post" action="?/deleteTemplate" use:enhance>
<input type="hidden" name="templateName" value={templateName} />
<button type="submit" class="btn variant-soft-error" use:confirmed={{
title: 'Delete Template',
body: `Please confirm that you want to delete "${templateName}"`
}}>Delete</button>
</form>
</div>
{/each}
{/if}
56 changes: 56 additions & 0 deletions src/lib/components/printer/PrinterConfig.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<script lang="ts">
import { enhance } from '$app/forms';
import type { PrinterType } from '$lib/types';
import { confirmed } from '$lib/use/buttonConfirmed';
export let identifier: string;
export let type: PrinterType;
export let formAction = '?/savePrinter';
export let formDeleteAction = '?/deletePrinter';
export let deleteHidden = false;
</script>

<div class="card w-full">
<form
method="post"
action={formAction}
use:enhance={() => {
return ({ update }) => {
update({ reset: false });
};
}}
>
<input type="hidden" name="identifier" value={identifier} />
<input type="hidden" name="type" value={type} />
<header class="card-header flex flex-row justify-between items-center">
<h2 class="h2">{identifier}</h2>
<span class="badge variant-filled">{type}</span>
</header>
<section class="p-4">
<label for="name" class="label mb-3">
<span>Name</span>
<input class="input" type="text" name="newIdentifier" id="name" value={identifier} />
</label>
<div class="card p-2">
<header>
<h2>Options</h2>
</header>
<section>
<slot name="options" />
</section>
</div>
</section>
<footer class="card-footer flex flex-row-reverse justify-between">
<button type="submit" class="btn variant-filled-primary">Save</button>
{#if !deleteHidden}
<button formaction={formDeleteAction} class="btn variant-filled-error" use:confirmed={{
title: 'Delete Printer',
body: `Please confirm that you want to delete "${identifier}"`
}}>Delete</button>
{:else}
<div />
{/if}
</footer>
</form>
</div>
17 changes: 17 additions & 0 deletions src/lib/components/printer/SerialPrinterOptions.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts">
import { baudRates } from '$lib/constants';
export let options: any;
</script>

<label for="path" class="label">
<span>Path</span>
<input class="input" type="text" name="path" id="path" value={options.path} />
</label>
<label for="baudRate" class="label">
<span>Baud rate</span>
<select class="select" name="baudRate" id="baudRate" value={options.baudRate}>
{#each baudRates as baudRate}
<option value={baudRate}>{baudRate}</option>
{/each}
</select>
</label>
12 changes: 12 additions & 0 deletions src/lib/components/printer/TcpPrinterOptions.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script lang="ts">
export let options: any;
</script>

<label for="host" class="label">
<span>Host</span>
<input class="input" type="text" name="host" id="host" value={options.host} placeholder="localhost" />
</label>
<label for="port" class="label">
<span>Port</span>
<input class="select" type="number" min="0" max="65535" name="port" id="port" value={options.port}>
</label>
8 changes: 8 additions & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const densities = [6, 8, 12, 24] as const;

export const baudRates = [
50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 28800, 38400, 57600,
76800, 115200, 230400, 460800, 576000, 921600
];

export const printerTypes = ['serial', 'tcp'] as const;
2 changes: 1 addition & 1 deletion src/lib/server/fileUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async function createEmptyJsonFile(path: string) {
await storeObject({}, path);
}

async function fileExists(path: string) {
export async function fileExists(path: string) {
try {
await fs.access(getDataFilePathFor(path));
return true;
Expand Down
54 changes: 54 additions & 0 deletions src/lib/server/printers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { PrinterConfig, PrinterConfigs, PrinterOptions, PrinterType } from '$lib/types';
import { createEmptyJsonFileIfNotExists, readJson, storeObject } from '../fileUtil';
import type { Printer } from './printer';
import { SerialPrinter } from './serialPrinter';
import { TcpPrinter } from './tcpPrinter';

const printersFilename = 'printerConfigs.json';
export const printers: Printer[] = [];

await createEmptyJsonFileIfNotExists(printersFilename);

export const printerConfigs: PrinterConfigs = await readJson(printersFilename);
reloadPrinters();

export function reloadPrinters() {
printers.splice(0, printers.length);
for (const identifier in printerConfigs) {
const printer = printerFromConfig(identifier, printerConfigs[identifier]);
printers.push(printer);
}
}

export async function savePrinter<T extends PrinterType>(identifier: string, newIdentifier: string, type: T, options: PrinterOptions<T>) {
delete printerConfigs[identifier];

printerConfigs[newIdentifier] = {
type,
options
};

await storeObject(printerConfigs, printersFilename);
reloadPrinters();
}


export async function deletePrinter(identifier: string) {
delete printerConfigs[identifier];

await storeObject(printerConfigs, printersFilename);
reloadPrinters();
}

function printerFromConfig(identifier: string, printerConfig: PrinterConfig<any>) {
switch (printerConfig.type) {
case 'serial': {
return new SerialPrinter(identifier, printerConfig.options);
}
case 'tcp': {
return new TcpPrinter(identifier, printerConfig.options);
}
default:
throw new Error(`unknown printer type ${printerConfig.type}`);
}
}
7 changes: 7 additions & 0 deletions src/lib/server/printers/printer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

export abstract class Printer {
constructor(public readonly identifier: string) {}

public abstract print(zpl: string): Promise<void>;

}
37 changes: 37 additions & 0 deletions src/lib/server/printers/serialPrinter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { SerialPort } from 'serialport';
import { Printer } from './printer';
import { fileExists } from '../fileUtil';

export class SerialPrinter extends Printer {
constructor(identifier: string, private readonly options: any) {
super(identifier);
}

/**
* @override
*/
public async print(zpl: string): Promise<void> {
const path = this.options.path;
if (!path || !(await fileExists(path))) {
throw new Error(`${path} not found`);
}

const port = new SerialPort(this.options);

try {
await new Promise((resolve, reject) => {
port.write(zpl, (err) => {
if (err) {
console.error('Error writing to port:', err);
reject(err);
} else {
console.log('Message sent');
resolve(undefined);
}
});
});
} finally {
port.close();
}
}
}
25 changes: 25 additions & 0 deletions src/lib/server/printers/tcpPrinter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Printer } from './printer';
import * as net from 'net';

export class TcpPrinter extends Printer {
constructor(identifier: string, private readonly options: any) {
super(identifier);
}

public async print(zpl: string): Promise<void> {
const client = new net.Socket();

await new Promise((resolve, reject) => {
client.connect(this.options.port, this.options.host, () => {
client.write(zpl, () => {
client.end();
resolve(undefined);
});
});

client.on('error', (err) => {
reject(err);
});
});
}
}
30 changes: 26 additions & 4 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const densities = [6, 8, 12, 24] as const;
import type { densities, printerTypes } from './constants';

export type Densities = (typeof densities)[number];

export type Density = `${Densities}dpmm`;
Expand All @@ -7,9 +8,30 @@ export type Variables = Record<string, any>;
export type Template = {
name: string;
zpl: string;
width: number;
height: number;
density: Density;
width: number;
height: number;
density: Density;
};

export type Templates = Record<string, Template>;

export type PrinterType = (typeof printerTypes)[number];

export type PrinterOptions<T extends PrinterType> = T extends 'serial'
? {
path: string;
baudRate: number;
}
: T extends 'tcp'
? {
host: string;
port: number;
}
: never;

export type PrinterConfig<T extends PrinterType> = {
type: T;
options: PrinterOptions<T>;
};

export type PrinterConfigs = Record<string, PrinterConfig<any>>;
Loading

0 comments on commit d331f5d

Please sign in to comment.