basic interactions work

This commit is contained in:
2026-09-28 23:34:04 +06:00
parent b8d3a44d22
commit 4060f64b98
8 changed files with 1034 additions and 38 deletions

110
README.md
View File

@@ -86,23 +86,122 @@ Or with any other CoAP client, e.g. [`coap-cli`](https://www.npmjs.com/package/c
coap get "coap://localhost:5683/hello?name=Imran"
```
## Streaming media
The server also streams two static files, loaded into memory at startup from
`MEDIA_DIR` (default `media/`):
| Route | File | Format |
|--------------|----------------------|-----------------------------------------------|
| `GET /audio` | `media/audio.wav` | PCM WAV, mono, 16-bit, 16 kHz |
| `GET /image` | `media/image.rgb565` | raw RGB565 little-endian, 320×240 (153,600 B) |
A file that is missing or in the wrong format is reported at startup and its
route answers `4.04` with the reason; the rest of the server still runs.
Neither file fits in one datagram, so they go out with block-wise transfer
(Block2, RFC 7959): the client asks for block 0, 1, 2 … and each reply carries
1024 bytes. The server keeps no per-client state — every request names the
block it wants, so it just slices the in-memory file. Every block carries an
ETag (so the client can tell the file did not change mid-transfer), block 0
carries Size2 (the total size), and a block past the end gets `4.02`.
### Make test media
```bash
mkdir -p media
```
```bash
ffmpeg -f lavfi -i "sine=frequency=440:duration=10" -ac 1 -ar 16000 -c:a pcm_s16le media/audio.wav
```
```bash
ffmpeg -f lavfi -i "testsrc=size=320x240" -frames:v 1 -f rawvideo -pix_fmt rgb565le media/image.rgb565
```
Or convert your own files:
```bash
ffmpeg -i input.mp3 -ac 1 -ar 16000 -c:a pcm_s16le media/audio.wav
```
```bash
ffmpeg -i photo.png -vf scale=320:240 -f rawvideo -pix_fmt rgb565le media/image.rgb565
```
`media/` is gitignored.
### Play it
`src/bin/stream.rs` downloads a file block by block and pipes it into `ffplay`
(part of ffmpeg), which opens the window:
```bash
cargo run --release --bin stream -- image
```
```bash
cargo run --release --bin stream -- audio
```
The image opens in a 320×240 window that stays until you close it; the audio
plays with a waveform window. Closing the window stops the download.
| Flag | Effect |
|------------------|----------------------------------------------------|
| `--out FILE` | Also save the received bytes |
| `--no-play` | Don't start ffplay (download only) |
| `--timeout-ms N` | First retransmission timeout (default 2000, doubles, 4 retries) |
Measured on localhost:
| File | Blocks | Download, `--no-play` | Retransmits |
|-------|--------|-----------------------|-------------|
| image | 150 | under 1 s | 0 |
| audio | 313 | 0.16 s | 0 |
Each block reply is 1050 B on the wire (26 B of CoAP header and options plus
1024 B of data). When playing, blocks are written to ffplay as they arrive and
a full pipe slows the download down, but ffplay buffers several seconds ahead:
a 10 s clip finishes downloading after about 2.4 s while it plays.
To see one block byte by byte:
```bash
./coap-inspect.py get /image --block 0
```
To test streaming end to end (generates its own media and server):
```bash
./test-stream.sh
```
Limits: at most 65,536 blocks per file (about 67 MB, roughly 35 minutes of this
audio), download only, and no encryption.
## Test
```bash
cargo test
```
Five unit tests cover the greeting, payload parsing (text + JSON) and query
decoding.
Unit tests cover the greeting, payload parsing (text + JSON), query decoding,
block selection, WAV and RGB565 validation, and the Block2/ETag/Size2 reply.
## Layout
| Path | What it is |
|---------------------|---------------------------------------------------------|
| `src/main.rs` | The server: socket, read loop, route table, helpers. |
| `src/lib.rs` | Shared CoAP client used by the CLI and the bridge. |
| `src/lib.rs` | Shared CoAP client, including block-wise downloads. |
| `src/bin/client.rs` | CLI client for smoke tests. |
| `src/bin/bridge.rs` | HTTP -> CoAP proxy so a browser can reach the server. |
| `src/bin/stream.rs` | Streams `/audio` or `/image` into an ffplay window. |
| `media/` | Audio and image files the server streams (gitignored). |
| `coap-inspect.py` | Sends one request and shows both packets byte by byte. |
| `test-stream.sh` | End-to-end streaming test with its own server and media. |
| `static/index.html` | CoAP reference page: routes, codes, copyable commands. |
| `nodejs/` | The earlier Node.js version, kept for reference. |
@@ -113,6 +212,7 @@ decoding.
| `COAP_PORT` | `5683` | server, client, bridge |
| `COAP_HOST` | `0.0.0.0` | server, client, bridge |
| `HTTP_PORT` | `8080` | bridge |
| `MEDIA_DIR` | `media` | server |
## Design notes
@@ -136,8 +236,8 @@ decoding.
- **DTLS.** Plaintext CoAP has no encryption or authentication. Production uses
`coaps://` on port 5684 — see `webrtc-dtls` or a gateway like `libcoap`.
- **Block-wise transfer** (RFC 7959) for payloads past ~1 KB; `coap-lite` ships
a `BlockHandler` for this.
- **Block-wise upload** (Block1, RFC 7959). Downloads already use Block2 (see
Streaming media); `coap-lite`'s `BlockHandler` can reassemble uploads.
- **Observe** (RFC 7641) for server-pushed updates; `coap-lite` provides
`Subject` and `create_notification`.
- **Deduplication.** A CoAP server should track recent message IDs and replay