Add per-adapter architecture docs in event-targets/ directory
- Create docs/architecture/event-targets/ with individual specs: in-process, redis, websocket-client, websocket-server, worker, iroh-spoke, iroh-hub - Update event-targets.md to serve as index with topology model (symmetric vs fan-out) and adapter status table - Update architecture.md index to reference new directory
This commit is contained in:
75
docs/architecture/event-targets/iroh-hub.md
Normal file
75
docs/architecture/event-targets/iroh-hub.md
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-07
|
||||
---
|
||||
|
||||
# Iroh Hub Event Target
|
||||
|
||||
**Import**: `@alkdev/pubsub/event-target-iroh-hub`
|
||||
**Peer dep**: `@rayhanadev/iroh` (optional, NAPI-RS native addon)
|
||||
**Status**: Not yet implemented. Needs R&D on binding stability, NAPI under Deno.
|
||||
|
||||
P2P QUIC event target for the hub (server) side. The hub accepts incoming connections and bidirectional streams. Manages multiple connected spokes.
|
||||
|
||||
## `createIrohHubEventTarget`
|
||||
|
||||
```ts
|
||||
async function createIrohHubEventTarget<TEvent extends TypedEvent>(
|
||||
args: CreateIrohHubEventTargetArgs,
|
||||
): Promise<TypedEventTarget<TEvent>>;
|
||||
```
|
||||
|
||||
### `CreateIrohHubEventTargetArgs`
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `endpoint` | `Endpoint` | Yes | iroh endpoint (created with `Endpoint.create()`) |
|
||||
| `alpn` | `string` | No | Application-layer protocol. Default: `"alkpubsub/1"` |
|
||||
|
||||
## How It Works
|
||||
|
||||
Similar to the WebSocket server adapter, the Iroh hub adapter manages multiple connections:
|
||||
|
||||
- `dispatchEvent` → writes JSON envelope to all connected spokes' `SendStream`s
|
||||
- `addEventListener` → registers local listeners for events from any spoke
|
||||
- On incoming connection → `endpoint.accept()` → `connection.acceptBi()` → new spoke tracked
|
||||
|
||||
Each spoke gets its own read loop that parses length-prefixed JSON messages from `RecvStream` and dispatches locally.
|
||||
|
||||
## Connection Lifecycle
|
||||
|
||||
1. Hub creates `Endpoint` and starts accepting
|
||||
2. Spoke connects → hub gets `Connection` from `endpoint.accept()`
|
||||
3. Hub accepts stream → `connection.acceptBi()` → `SendStream` + `RecvStream`
|
||||
4. Hub creates per-spoke read loop
|
||||
5. On disconnect → `RecvStream.readExact()` throws → remove spoke from set
|
||||
6. Hub continues accepting new connections
|
||||
|
||||
## Fan-Out
|
||||
|
||||
```ts
|
||||
dispatchEvent(event) {
|
||||
const message = encodeEnvelope(event.detail);
|
||||
for (const spoke of this.spokes) {
|
||||
spoke.sendStream.writeAll(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
## Key Properties
|
||||
|
||||
- **Multi-connection** — manages a set of connected spokes
|
||||
- **Fan-out** — dispatchEvent sends to all connected spokes
|
||||
- **Accepts incoming** — endpoint.accept() loop runs continuously
|
||||
- **Cryptographic identity** — each spoke verified by Ed25519 NodeId
|
||||
|
||||
## R&D Needed
|
||||
|
||||
1. **Binding stability** — same as spoke adapter. `@rayhanadev/iroh` needs testing.
|
||||
2. **Concurrent accept** — can `endpoint.accept()` handle multiple simultaneous connections?
|
||||
3. **Stream vs. Connection per spoke** — current design: one bidirectional stream per spoke on a single connection. Alternative: one connection per spoke. Need to benchmark which is better for the expected workload.
|
||||
4. **1:N fan-out** — for hub to N spokes, each spoke gets its own stream. For true broadcast, `iroh-gossip` would be better (not yet available in TS).
|
||||
5. **Connection rejection** — how to reject connections from unknown `NodeId`s.
|
||||
|
||||
See [../iroh-transport.md](../iroh-transport.md) for full protocol details, identity, and comparison with WebSocket.
|
||||
Reference in New Issue
Block a user