You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(amuleapi): align web frontend with backend, fix doc drift
The static web frontend and the docs/api reference had both drifted from
the JSON the amuleapi backend actually emits. Verified each field against
src/webapi/Api.cpp and src/webapi/EventDiff.cpp.
Frontend (src/webapi/static):
- downloads.js: register the clients resource under id "client_ecid"
(was "ecid"). The backend keys clients by client_ecid, so the old id
collapsed the whole uploads/clients list to a single "undefined" row.
- events.js: buffer-then-replay on seed() so a delta (especially a
*_removed) arriving while a snapshot fetch is in flight is no longer
clobbered by the snapshot replacing the collection, per EVENTS.md.
- events.js + search.js: wire the SSE search channel
(search_result_added / search_finished), reconciling live upserts with
the existing poll by hash; poll stays as the full-set reconciler and
fallback when the stream isn't live.
Docs (docs/api), corrected to match the backend:
- REFERENCE.md: /status now shows kad.network; /clients and /servers
examples completed; /kad lists firewalled_udp, ip, indexed, buddy;
/logs/amule returns {lines,...} not {log}; /logs/serverinfo returns a
text string (not a lines array); /stats/tree is {nodes:[{label,
children}]} not {tree}; /stats/graphs points are objects
{t,t_unix,value} with a full envelope; /search/results items use
sources{total,complete}+already_have+rating and progress gains active.
- EVENTS.md: log_appended payload is {lines} (no buffer; amule log only);
search_result_added carries no ecid and flattens sources to an int.
Copy file name to clipboardExpand all lines: docs/api/EVENTS.md
+6-7Lines changed: 6 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -214,7 +214,7 @@ Both `since_id` and `newest_id` are uint64. The client never has to compute them
214
214
215
215
## Event catalog
216
216
217
-
Every event the bus publishes. The `_added` and `_updated` payloads are BYTE-FOR-BYTE identical to the matching REST resource's list-item shape — clients receiving a `*_updated` event get the full new state and never need to re-GET. `_removed` carries only the identity field — `hash` for files (`download_removed`, `shared_removed`), `client_ecid` for `client_removed`, `ecid` for `server_removed` — so the client can drop the cache entry without needing the old object. Two events don't fit the collection-delta model: `status_changed` ships a full status envelope (replace, not merge) and `log_appended` is an append operation (`{buffer, lines}` — push the lines onto the named buffer, don't replace). Branch on the event type in your dispatcher accordingly.
217
+
Every event the bus publishes. The `_added` and `_updated` payloads are BYTE-FOR-BYTE identical to the matching REST resource's list-item shape — clients receiving a `*_updated` event get the full new state and never need to re-GET. `_removed` carries only the identity field — `hash` for files (`download_removed`, `shared_removed`), `client_ecid` for `client_removed`, `ecid` for `server_removed` — so the client can drop the cache entry without needing the old object. Two events don't fit the collection-delta model: `status_changed` ships a full status envelope (replace, not merge) and `log_appended` is an append operation (`{lines}` — push the lines onto the amule log buffer, don't replace). Branch on the event type in your dispatcher accordingly.
218
218
219
219
### `downloads` channel
220
220
@@ -384,25 +384,24 @@ Subscribe to this channel alone for a thin "header bar" client that just wants c
384
384
385
385
#### `log_appended`
386
386
387
-
Emitted when amuled or the serverinfo buffer appends new lines.
387
+
Emitted when the amuled log buffer appends new lines.
388
388
389
389
```json
390
-
{ "buffer": "amule", "lines": ["2026-06-19 11:00:00: line one", "2026-06-19 11:00:01: line two"] }
390
+
{ "lines": ["2026-06-19 11:00:00: line one", "2026-06-19 11:00:01: line two"] }
391
391
```
392
392
393
-
`buffer`is `"amule"` or `"serverinfo"`. Multiple lines may be batched into a single event when the underlying buffer landed several lines between refresher ticks. The [Bootstrap example](#bootstrap-snapshot--stream) doesn't pull `/logs/amule`or `/logs/serverinfo`— fetch them in step 2 if your UI shows historical log lines, otherwise treat `log_appended` as a live-only feed.
393
+
Only the amuled log has a live channel; the serverinfo buffer has no SSE feed and is fetched by polling [`GET /logs/serverinfo`](REFERENCE.md#get-apiv0logsserverinfo--delete-apiv0logsserverinfo). Multiple lines may be batched into a single event when the buffer landed several lines between refresher ticks. The [Bootstrap example](#bootstrap-snapshot--stream) doesn't pull `/logs/amule` — fetch it in step 2 if your UI shows historical log lines, otherwise treat `log_appended` as a live-only feed.
394
394
395
395
### `search` channel
396
396
397
397
Driven by the refresher state machine that owns the `POST /search` → completion lifecycle (see [REFERENCE.md](REFERENCE.md#search-results)). Events only fire while a search is active; the channel is silent at idle. The [Bootstrap example](#bootstrap-snapshot--stream) omits `/search/results` because searches are normally client-initiated post-boot; if your UI persists a "search-in-progress" state across reloads, fetch `/search/results` and `/search/progress` in step 2 too.
398
398
399
399
#### `search_result_added`
400
400
401
-
Emitted per new ECID that appears in the results map between refresher ticks.
401
+
Emitted per new result that appears in the results map between refresher ticks.
402
402
403
403
```json
404
404
{
405
-
"ecid": 42,
406
405
"hash": "0123456789abcdef0123456789abcdef",
407
406
"name": "ubuntu-24.04-desktop-amd64.iso",
408
407
"size": 5765873664,
@@ -413,7 +412,7 @@ Emitted per new ECID that appears in the results map between refresher ticks.
413
412
}
414
413
```
415
414
416
-
Payload mirrors a single `/search/results` array entry. ECIDs are amuled-allocated and unique per amuled session, but **not** stable across `POST /search` calls — amuled wipes its searchlist on every new query and re-allocates from the same pool, so subscribers must treat each search as a fresh result space.
415
+
Key results by `hash`. The payload carries the same data as a `/search/results` array entry but in a flatter shape: the source counts arrive as a top-level `sources` (total) integer plus a sibling `complete_sources`, whereas the REST endpoint nests them as `sources: {total, complete}`. amuled wipes its searchlist on every new `POST /search`, so subscribers must treat each search as a fresh result space — clear prior results when you start a new query.
**Query parameters:**`tail=N` — return only the last N lines (default: full buffer).
908
932
909
933
```json
910
-
{ "log": ["2026-06-19 11:00:00: line one", "...line two"] }
934
+
{
935
+
"lines": ["2026-06-19 11:00:00: line one", "...line two"],
936
+
"total_cached": 1024,
937
+
"returned": 2
938
+
}
911
939
```
912
940
941
+
`lines` is the array of log lines; `total_cached` is how many lines are held in the buffer and `returned` how many this response carried (≤ `tail`).
942
+
913
943
#### `DELETE /api/v0/logs/amule`
914
944
915
945
**Auth:**`ADMIN`
@@ -924,7 +954,20 @@ Clears the buffer.
924
954
925
955
**Auth:**`GUEST` / `ADMIN`
926
956
927
-
Same shape; the ed2k server-info log buffer instead of the general log.
957
+
The ed2k server-info log buffer. Unlike `/logs/amule`, amuled ships this one as a
958
+
single accumulated text blob (it rotates it server-side), so the GET returns a
959
+
`text`**string** rather than a `lines` array. `?tail=N` here clamps the number
960
+
of trailing **bytes**, not lines.
961
+
962
+
```json
963
+
{
964
+
"text": "Connecting to eMule Server (203.0.113.5:4242)\nConnection established\n",
965
+
"total_bytes": 4096,
966
+
"returned_bytes": 68
967
+
}
968
+
```
969
+
970
+
`DELETE` clears the buffer and returns `{ "ok": true }`.
928
971
929
972
---
930
973
@@ -934,11 +977,25 @@ Same shape; the ed2k server-info log buffer instead of the general log.
934
977
935
978
**Auth:**`GUEST`
936
979
937
-
A nested object mirroring amuled's "Statistics" tree (transfers, connections, clients, servers, downloads). Cached with a 1 s TTL.
980
+
A tree mirroring amuled's "Statistics" tree (transfers, connections, clients, servers, downloads). Cached with a 1 s TTL.
981
+
982
+
The envelope is `{ "nodes": [...] }`. Each node is `{ "label": "<text>", "children": [...] }`; a leaf is a node whose `children` array is empty, with its value baked into the `label` string (e.g. `"Total uploaded: 12.4 GB"`).
Each point is an object with `t` (ISO8601 UTC), `t_unix` (unix seconds), and `value`. `unit` is `"bps"` for download/upload and `"count"` for connections/kad. `session` carries this-session byte totals so a client doesn't need a separate roundtrip.
@@ -1002,21 +1070,25 @@ This endpoint does NOT busy-wait — it returns whatever amuled has in its resul
1002
1070
{
1003
1071
"results": [
1004
1072
{
1005
-
"hash": "8b54a3c2...",
1006
-
"name": "example-distribution-26.04-amd64.iso",
1007
-
"size": 3825205248,
1008
-
"sources_count": 217,
1009
-
"file_type": "iso"
1073
+
"hash": "8b54a3c2...",
1074
+
"name": "example-distribution-26.04-amd64.iso",
1075
+
"size": 3825205248,
1076
+
"sources": { "total": 217, "complete": 142 },
1077
+
"already_have": false,
1078
+
"rating": 0
1010
1079
}
1011
1080
],
1012
1081
"progress": {
1013
1082
"percent": 67,
1014
-
"complete": false
1083
+
"complete": false,
1084
+
"active": true
1015
1085
}
1016
1086
}
1017
1087
```
1018
1088
1019
-
`progress.percent` is in the `[0, 100]` range. `progress.complete` is `true` whenever amuled reports the search has finished (matches the raw amuled sentinel values `100`, `0xfffe` Kad-done, and `0xffff` local-done — all surface here as `percent: 100, complete: true`).
1089
+
`sources.total` is the swarm size amuled reports for the result; `sources.complete` is how many of those hold the file complete. `already_have` is `true` when the hash is already in your downloads/shared. `rating` is the amuled-aggregated quality rating (`0` when unrated).
1090
+
1091
+
`progress.percent` is in the `[0, 100]` range. `progress.complete` is `true` whenever amuled reports the search has finished (matches the raw amuled sentinel values `100`, `0xfffe` Kad-done, and `0xffff` local-done — all surface here as `percent: 100, complete: true`). `progress.active` is `true` while a `POST /search` is in flight (the refresher is polling amuled) and `false` once it stops or finishes — use it to tell "no search started" (`active: false`) apart from "search running, no hits yet" (`active: true`).
1020
1092
1021
1093
`progress.percent: 0, progress.complete: false` can mean either "no search has been started" OR "Kad search just kicked off but hasn't reached any peers yet" — Kad search progress is not measurable mid-flight, only "started" and "finished". Clients that started the search themselves can treat the second tick onwards as "in progress".
0 commit comments