Genesis
This commit is contained in:
102
README.md
Normal file
102
README.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# escpos-proxy
|
||||
|
||||
Minimal ESC/POS print proxy written as a Node.js ESM app.
|
||||
|
||||
It listens for incoming ESC/POS print jobs on a TCP port, **forwards the raw
|
||||
bytes straight to a target printer**, and **logs every job to disk** as both a
|
||||
raw `.bin` file and a decoded `.txt` sidecar.
|
||||
|
||||
A *job* is delimited by either:
|
||||
- a **cut command** ("bladecut") in the stream — ESC/POS `GS V` = `0x1D 0x56`, or
|
||||
- a **connection drop** (the client closes / resets the connection).
|
||||
|
||||
No database, websocket, or receipt re-rendering is involved.
|
||||
|
||||
## Usage
|
||||
|
||||
Configuration lives in `.env` (copy `.env.example` to `.env` and edit). It is loaded via [dotenv](https://www.npmjs.com/package/dotenv).
|
||||
|
||||
```bash
|
||||
cp .env.example .env # first time only
|
||||
npm start
|
||||
```
|
||||
|
||||
### Environment variables (`.env`)
|
||||
|
||||
| Variable | Default | Description |
|
||||
|------------------|------------------|--------------------------------------|
|
||||
| `LISTEN_HOST` | `0.0.0.0` | Host the proxy listens on |
|
||||
| `LISTEN_PORT` | `9100` | Port the proxy listens on |
|
||||
| `TARGET_HOST` | `10.10.10.24` | Printer to forward raw bytes to |
|
||||
| `TARGET_PORT` | `9100` | Printer port |
|
||||
| `LOG_DIR` | `./logs` | Directory for job logs |
|
||||
| `CUT_PREFIX` | `1d 56` | ESC/POS cut command prefix, hex space-separated (`GS V`) |
|
||||
| `KEEP_AFTER_CUT` | `true` | Treat bytes after a cut as the next job |
|
||||
|
||||
Real environment variables always take precedence over `.env`.
|
||||
|
||||
## Logs
|
||||
|
||||
For each completed job, two files are written into `LOG_DIR`:
|
||||
|
||||
- `job-<timestamp>-<seq>.bin` — the exact raw bytes (reprintable).
|
||||
- `job-<timestamp>-<seq>.txt` — the same bytes decoded as `latin1` (ASCII +
|
||||
control characters visible, ESC/POS faithful).
|
||||
|
||||
## Testing
|
||||
|
||||
`test-send.mjs` sends a sample ESC/POS receipt (with a `GS V` cut) to the
|
||||
listener so you can verify logging and forwarding:
|
||||
|
||||
```bash
|
||||
# terminal 1
|
||||
npm start
|
||||
|
||||
# terminal 2
|
||||
npm run test:send
|
||||
```
|
||||
|
||||
## Parsing the logs
|
||||
|
||||
`parser.js` is a **lossless** ESC/POS parser. It decomposes the raw byte stream
|
||||
into the ESC/POS command grammar: each control sequence is recognized by its
|
||||
opcode with its parsed parameters, and text is kept as raw byte spans (decoded
|
||||
via the selected code page). Nothing is *interpreted* into higher-level meaning
|
||||
(no "this is bold", no line/style inference) — it is a faithful tokenization.
|
||||
Every byte is preserved, and the original stream can be rebuilt via
|
||||
`serialize(parse(buf))`.
|
||||
|
||||
Token types:
|
||||
- `{ type: "text", bytes, text }` — raw bytes + code-page decode
|
||||
- `{ type: "command", bytes, group, name, params }` — control sequence + params
|
||||
- `{ type: "image", bytes, width, height, data }` — raster bit image (`GS v 0`)
|
||||
|
||||
`parse-log.mjs` is a CLI wrapper. By default it prints the parsed token stream
|
||||
(opcode + command name + parameters, text spans, images) and verifies the
|
||||
round-trip `serialize(parse(buf)) === buf` (no bytes lost).
|
||||
|
||||
```bash
|
||||
# parsed token stream (default) — a faithful decomposition
|
||||
npm run parse -- logs/job-2026-07-08T21-08-02-523Z-0003.bin
|
||||
|
||||
# parse every .bin in a directory
|
||||
node parse-log.mjs logs --all
|
||||
|
||||
# also show the raw bytes of each token
|
||||
node parse-log.mjs logs/job-...bin --hex
|
||||
|
||||
# convenience: decoded receipt text only (drops structure — not lossless)
|
||||
node parse-log.mjs logs/job-...bin --text
|
||||
|
||||
# also render raster bit images (e.g. QR codes) as ASCII art
|
||||
node parse-log.mjs logs/job-...bin --image --max-width 60
|
||||
```
|
||||
|
||||
As a module:
|
||||
|
||||
```js
|
||||
import { parse, serialize, renderText } from "./parser.js";
|
||||
const buf = fs.readFileSync("logs/job-xxx.bin");
|
||||
const events = parse(buf); // lossless token stream
|
||||
console.log(serialize(events).equals(buf)); // true — nothing lost
|
||||
```
|
||||
Reference in New Issue
Block a user