preprintd 0.2.5

Printer swarm-worker daemon implementation for PreConnect.
## `preprintd`

Printer swarm-worker daemon implementation for [PreConnect](https://github.com/sabbirba/preconnect).

### Overview

This tiny worker is just a `TcpStream` under the hood, constantly listening for jobs and claiming one if open. It works by constantly listening for incoming data from the `api.preconnect.app` endpoint (which uses [Mercure](https://mercure.rocks) under the hood for streaming real-time data), and then initiating the claiming procedure.

### Compiling

Requires [Rust](https://rust-lang.org/) (2024 edition or later) to be installed.

Run the traditional release command:

```bash
cargo build --release
```

> [!NOTE]
> The release binary is optimized for the smallest-possible size, although you can change this behavior by disabling the optimizations specified in the `[profile.release]` section of [Cargo.toml]./Cargo.toml.

### Prebuilt Binaries

See the [GitHub Releases](https://github.com/hitblast/preprintd/releases) for a prebuilt binary for either Windows, Linux (built via CI workers running Ubuntu), or macOS.

### Daemon Usage

Create a new `systemd` service which you can enable later:

```bash
sudo nano /etc/systemd/system/preprintd.service
```

Write the following INI configuration in your `preprintd.service` file. Make sure to replace the following things as well:

1. Under `Environment=`:

- `WORKER_KEY`: Your worker key credential (from the PreConnect API).
- `AGENT`: Agent name to use for outbound requests.
- `DEF_HOST`: The default printer host to use in case the API cannot provide one.
- `DEF_QUEUE`: The default queue name to send printable data to.

2. Under `User`, replace `username` with the username you're logged in with on your local machine.

```ini
[Unit]
Description=PreConnect Printer Worker Daemon
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/preprintd --debug
Restart=always
Environment="WORKER_KEY=yourworkerkeyhere" "AGENT=preprintd" "DEF_HOST=192.168.0.102" "DEF_QUEUE=queuename"
User=username

[Install]
WantedBy=multi-user.target
```

Enable and start it once you're done:

```bash
sudo systemctl daemon-reload
sudo systemctl enable preprintd.service
sudo systemctl start preprintd.service

# now check status:
systemctl status preprintd.service
```

To check the logs in real-time, run:

```bash
journalctl -u preprintd.service -f
```

### Code Inspection

When you're going through the code, you'll see these:

- Some `decode_b64_string()` calls - those are primarily for obfuscation needs but since the inner value is Base64-encoded, you can easily use a decoder to decouple the values underneath. One such tool that you can use is [this]https://www.base64decode.org.
- The standard LPR/LPD sequence (except the code doing HTTP requests via [reqwest's]https://github.com/seanmonstar/reqwest blocking API and every other code surrounding/using this logic).
- LOTS of `LazyLock` usage. ALthough this is not optimal for a program that's supposed to be tiny, we've kept this pattern to reuse as much data as physically possible without hardcoding and messing up.

#### Mercure SSE Connection Protocol

`preprintd` streams real-time job notifications from the Mercure Hub (`/.well-known/mercure`).

1. **Endpoint**: `https://api.preconnect.app/.well-known/mercure?topic=https%3A%2F%2Fpreconnect.app%2Fprinter`
2. **Authorization**: `Bearer <subscriber-jwt>`
   - The subscriber JWT is created by signing `{"mercure":{"subscribe":["https://preconnect.app/printer"]}}` with HMAC-SHA256 using `WORKER_KEY`.
3. **Replay Support**: On reconnect, pass the `Last-Event-ID` header containing the last `id: ` value received from the stream to receive any missed jobs.

### Reference Implementation

See: https://github.com/sabbirba/preconnect/blob/main/printer.py (courtesy: [@sabbirba](https://github.com/sabbirba))

### License

Licensed under the [GNU General Public License v3](./LICENSE).