Wire Protocol¶
Plugins using the Go SDK don't need to know the wire protocol. This section is for authors implementing plugins in other languages.
Overview¶
Plugins use two communication channels:
| Channel | Format | Purpose |
|---|---|---|
| stdin/stdout | Line-delimited JSON | Lifecycle events, target pushes |
| Unix socket | Length-prefixed msgpack | Request-response hooks |
stdin/stdout — Lifecycle & Pushes¶
Prox → Plugin: configure¶
Sent once after the plugin starts, and again on config reload.
{
"method": "configure",
"params": {
"route_id": "gateway:0",
"match": { "domain": "*.**", "path": "/ws" }
}
}
Plugin → Prox: ready¶
Sent after configure to declare request-response capabilities. This tells prox to connect to the plugin's Unix socket for hook calls.
{
"method": "ready",
"params": {
"socket": "/tmp/prox-p-12345.sock",
"hooks": ["on_request", "on_response", "on_connect"]
}
}
Available hook names: on_request, on_response, on_connect.
Plugin → Prox: set_targets¶
Push new targets to the route's balancer. Sent whenever the target pool changes.
Flat mode:
{
"method": "set_targets",
"params": {
"route_id": "gateway:0",
"targets": ["10.0.1.1:3505", "10.0.1.2:3505"]
}
}
Grouped mode:
{
"method": "set_targets",
"params": {
"route_id": "gateway:0",
"groups": {
"de": ["de-node1.internal:8080", "de-node2.internal:8080"],
"us": ["us-node1.internal:8080"]
}
}
}
targets— flat replacement list (not a diff). Previous targets are discarded.groups— keyed replacement map. Each key gets its own sub-balancer.- Use
targetsORgroups, not both in the same message.
Unix Socket — Request-Response Hooks¶
The socket uses length-prefixed msgpack frames:
Frame Structure¶
Each frame is an Envelope containing a hook type and the hook-specific data:
Envelope {
hook: string // "on_request", "on_response", "on_connect"
data: bytes // msgpack-encoded hook payload
}
on_request¶
Request payload:
| Field | msgpack key | Type |
|---|---|---|
| RouteID | r |
string |
| Method | m |
string |
| Path | p |
string |
| Query | q |
string |
| Domain | d |
string |
| Host | ho |
string |
| Proto | pr |
string |
| RemoteAddr | a |
string |
| ContentLength | cl |
int64 |
| Headers | h |
map[string]string |
| Body | bd |
bytes |
| MatchDomain | md |
string |
| MatchGlob | mg |
string |
| MatchPath | mp |
string |
| Vars | v |
map[string]string |
Response payload:
| Field | msgpack key | Type |
|---|---|---|
| Allow | ok |
bool |
| Drop | dr |
bool |
| Status | s |
int |
| Body | b |
string |
| Headers | h |
map[string]string |
on_response¶
Request payload — a pair of request info + upstream response:
ResponsePair {
req: RequestInfo // same as on_request payload
resp: UpstreamResponse {
status: int // msgpack key: "s"
headers: map[string]string // msgpack key: "h"
}
}
Response payload:
| Field | msgpack key | Type |
|---|---|---|
| Status | s |
int (0 = no change) |
| Headers | h |
map[string]string (add/override) |
| Remove | rm |
[]string (headers to remove) |
on_connect¶
Request payload:
| Field | msgpack key | Type |
|---|---|---|
| RouteID | r |
string |
| Domain | d |
string |
| RemoteAddr | a |
string |
Response payload:
| Field | msgpack key | Type |
|---|---|---|
| Allow | ok |
bool |
Minimal Plugin Example (Bash)¶
#!/bin/bash
while IFS= read -r line; do
method=$(echo "$line" | jq -r '.method')
if [ "$method" = "configure" ]; then
route_id=$(echo "$line" | jq -r '.params.route_id')
echo '{"result":"ok"}'
# Push initial targets
echo "{\"method\":\"set_targets\",\"params\":{\"route_id\":\"$route_id\",\"targets\":[\"10.0.1.1:3505\"]}}"
fi
done
Note
Bash plugins can only do push-based target discovery. Request-response hooks require a Unix socket server with msgpack framing — use the Go SDK or implement the socket protocol in your language of choice.