The dashboard
A page showing one node's view of the swarm, live: a map of the members and the links between them, the node's peers, its figures, and the document, which it can also edit. This page is about using it; how it works underneath (events, LINKS, what is sent when) is at the end, Underneath.
Opening it
The dashboard is in builds with the dashboard cargo feature:
cargo build --release --features mycelium,dashboard
It is at /admin/dashboard on the node's HTTP API, by default
http://127.0.0.1:3000/admin/dashboard, and asks for a user from --htpasswd, as the
rest of the API does. The API listens on localhost unless --bind-addr says otherwise;
to look at a node on another machine, forward the port (ssh -L 3000:localhost:3000 <machine>) or put a TLS proxy in front (trust.md).
Every node has its own dashboard, and shows the swarm as that node sees it: what it knows of the others, what they report to it, and its own figures.
The page
At the top, the node's alias and node ID; in orange, when this node's clock is off
from its peers' (measurements.md, Clocks), by how much; and the connection's status:
| Status | Meaning |
|---|---|
connecting… |
Opening the page's event stream. |
live |
Up to date. The dot beside it breathes with every update from the node. |
reconnecting… |
The stream broke; the browser reconnects by itself. |
disconnected; retrying… |
The node answered with an error (it may be up but not serving the page yet); again in 5 s. |
node stopped; reconnecting… |
The node said it is stopping; again in 3 s, until it is back. |
paused while hidden |
The page was hidden (another tab, a minimised window) for 30 s: it closed its stream, so the node does no work for it. Shown again, it reconnects. |
new version; reloading… |
The node now serves another version of the page; it is loaded. |
A click on the status refreshes everything at once while live, and reconnects at once otherwise. While not live, the page is dimmed and shows what it had last: ages stop counting.
Below, five boxes: the swarm's map on the left; the peers, the figures, the document and the console on the right. In a narrow window they are stacked.
Dragging the space between two boxes resizes them: between the map and the right column, below the peers, between the figures and the document, and above the console. Dragged all the way to the right, the right column goes, and the map takes the whole width; drag the space right of the map back to bring it again. A double-click there sets that space back to its default. The sizes are kept in the browser, for the next time the page is opened.
The ▾ before a box's title collapses it to its title (▸ opens it again). A
collapsed box isn't drawn at all, so it costs the browser nothing while the node
updates; opened, it shows what's current. The open boxes take the room the collapsed
ones leave: in the right column they share it as before (the peers take all of it
when they're the only one open); the map collapsed, the right column takes the width.
The right column all collapsed keeps its width: its titles stay at the top, with a
hint that dragging the space beside them to the right hides the column. Which boxes
are collapsed is kept in the browser too.
The map
Nodes
Every member of the swarm, by alias (or a shortened node ID):
- This node: filled blue, slightly larger.
- Filled: the member reports its links to this node.
- Hollow: it reports none: it doesn't answer this node's LINKS, or its last answer is more than 90 s old (it is unreachable from here, stopped, or doesn't yet take this node for a member).
- Red outline: this node holds it dormant (it has been silent, or said farewell).
- Dashed orange ring: its clock is off the swarm's: it differs from the median of
the members' clocks by more than
--clock-skew-warn, beyond what the measurements allow. The members report their peers' clocks with their links, so this works for members this node doesn't reach itself; it needs three members compared.
Links
Two kinds, drawn over each other:
- Intended (dashed grey): the neighbours the member list gives each member, as this node computes them. Shown only where no measured link backs it.
- Measured (coloured): the links members report. A link is drawn if either end reports it.
A measured link is coloured by transport (blue Mycelium, purple libp2p, teal Tor). The transport in use is the thick line in the middle, labelled with its round trip in milliseconds; the other transports the peers can reach each other on are thin lines beside it, from node to node, bowing out a little (furthest at the middle), with their round trips smaller. The round trips are drawn near the end that measured them: of the two ends' reports, the one drawn is the one with a round trip, else the fresher. Then:
- Solid: direct.
- Dashed: through a relay.
- Dotted: one end reports no links: what is drawn may be out of date.
- Narrow, over a red band: either end holds the other dormant, or the path in use
is down (no path to the peer answers;
/peersshows its connection asnull).
Messages this node exchanges run along its links as dots, from sender to receiver.
They come from the per-peer message counts, which arrive every 2 s: what was sent and
received since is spread over the next 2 s, at most 6 dots per link and direction,
shared out by message kind, each kind in its colour (named in the legend; the console
colours them alike). A dot is as large as its kind's messages were on average
(by the size's logarithm: a ping small, a large sync message large); the slider right
after their legend makes all dots larger or smaller, kept in the browser. A picture
of the traffic, not a record of it; links between other members show none.
messages: on after the slider hides them (messages: off shows them again; the
legend and the slider greyed meanwhile); the choice is kept in the browser.
A label on the map that changes, a round trip or a node's name, breathes once: it glows around its new text and fades (not where the system asks for reduced motion).
links: live beside the box's title says the members tell this node of their links'
changes as they happen. Clicked, it's links: every 30 s: the members are only asked
every 30 s, which costs the swarm fewer messages and leaves the map up to 30 s behind
(this node's own links stay current). It's the node's choice, for every page open on
it, until clicked again or the node restarts.
The legend above the map names the transports that appear; hide legend beside the
box's title gives its room to the map (show legend brings it back).
layout: static, beside it, is the default: nodes move only when the map is laid out
(below). A click switches to layout: dynamic: each measured link is as
long as its round trip is slow, against the median link's, by the square root, from
0.4 to 2.5 times the usual length; links without a round trip keep the usual length.
In either layout, a link only intended (dashed grey) gives way to the measured ones: it
pulls its ends together only a little when stretched, and doesn't push them apart. As
round trips change, the map moves to the new lengths smoothly. Clicked again, it's
static, the nodes staying where they are. The choice is kept in the browser.
Hovering over a node or a link highlights it and shows a tooltip: for a link, each of its lines with transport, direct or relayed, round trip, and how long ago it was measured.
Moving around
- Wheel, or pinching on a touch screen: zoom, around the pointer (or between the fingers, the map moving with them).
- Drag beside the nodes, or along a link: pan.
- Two fingers turning, on a touch screen: the map turns with them; labels stay upright.
- Drag a node: move it. On a dynamic map, the others follow at once, and once let go of, it moves back among them; on a static map it stays where it is put until the map is laid out again.
- Double-click a node: pin it where it is (a dot in its middle): the layout leaves it there. A double-click whose second press drags the node pins it where it's dropped. Double-clicked again, it's let go, and moves to its place among the others (on a static map, only it moves).
The map is laid out when the page opens, and again when the window or the box is resized. A member that comes later is placed among the others, which stay where they are, as they do when links appear or disappear; pinned nodes always stay put. The view and pins last as long as the page is open.
Focus
What the Figures box shows is what is in focus:
- Nothing (the default): this node's figures.
- A node (click it on the map, or its row in Peers): this node's entry for that
peer (as
/peershas it), and the links that member reports. Ringed on the map, highlighted in Peers. A second click on its row, a click beside the nodes or a click on this node goes back. - A link (click it): whether the member list intends it, each end's report of it
(transport, relayed, round trip, dormant, its other transports, and how old the
report is), and, where this node is an end, the link as this node has it in
/peers: where messages go, its paths (each with its connection and round trip), and the addresses known of the other end. Both ends are ringed.
The focus is in the page's address (#<node ID>, or the two IDs of a link), so a
reload keeps it and a link to the page can name it.
Peers
Every peer this node knows, with:
| Column | Meaning |
|---|---|
| peer | Alias, or a shortened node ID (the full one in the tooltip). |
| status | active, dormant (for how long: in the tooltip) or unknown (not heard from since this node started). |
| seen | How long ago this node last heard from it. |
| via | The address this node sends to it at, and whether direct or relayed. |
| rtt | The round trip on that path. |
| clock | How far its clock is ahead of this node's (behind: −), give or take (in the tooltip); in orange beyond --clock-skew-warn, for sure (measurements.md, Clocks). |
| neighbour | Whether this node keeps contact with it (HELLOs, keepalives, sync); others it only answers. |
| same epoch | Whether it is on this node's epoch (remakes.md); blank while unknown. |
The box is as tall as its rows, up to eight; then it scrolls.
Figures
The figures of what is in focus, as a tree: this node's /admin/stats, or a peer's
/peers entry and links. Branches stay as opened across updates, and ages count on
between them. What each figure means: measurements.md.
Document
The swarm's document, as this node holds it, its first level open. A branch is read when opened, and read again when the document changes there; what changed or came breathes once, as the map's labels do: its row glows and fades.
Editing writes to the document, as the user the page was opened as, and the write goes to the whole swarm like any other:
- Double-click an entry to edit it: a string as text, anything else as JSON, a map
or list whole. Saved, it is shown open. The red
DeletebesideSavedeletes the entry instead, on a second click (Delete: sure?) from half a second to 3 s later: a double-click doesn't delete. +on a map's row adds a key and its value.+on a list's row inserts an item at an index (-1: at the end); the items from there on move up.
Protocol data (_continuum) is written only by users in --protocol-writers, and epoch
metadata and the swarm ID by nobody (trust.md). A key containing /, or an empty
key, is listed but can't be opened.
Console
The messages this node exchanged with its peers, one by one: when (on the 24-hour
clock, to the millisecond), which way (→ sent, ← received, ↛ refused: the
transport wouldn't send it), with whom, the type (HELLO, SYNC, STATUS_REPLY,
LINKS, …, in its kind's colour, as on the map) and the size. The latest 500, the
newest at the bottom; scrolled along while at the bottom. They arrive with every update
(every 2 s). The PINGs the paths layer sends on its own, and the PONGs it answers
PINGs with, are listed too: under the node at the address they went to, where it is
known, else under the address. Not listed: WHO and ME, which stay in the layers
below the node (they are counted, measurements.md, Traffic).
A click on a message shows it in the figures box: when, with whom, its type and size, and the message written out (its bytes as sizes). A click on it again, or on anything on the map or in the peers, goes back.
Pointing at a message marks the others of its exchange (a lighter grey, and a bar on their left); while one is shown, its exchange stays marked. An exchange is a PING and its PONG (by their nonce, wherever they were listed), a HELLO and its replies (by the run of the node that sent the HELLO), a LINKS and its replies (by their nonce), a blob's requests and answers, from whichever peers (by the blob), and a delta offered in a SYNC with the blob it is fetched as. A STATUS and its reply carry nothing that ties them, nor does an ordinary SYNC.
While you read
Updates don't pull things from under you: while text is selected in a box, that box waits, and while an entry is edited, the branch it is in waits; both catch up once you are done. The map isn't redrawn under the pointer: what you point at stays put.
When something looks odd
- The status stays at
connecting…, or the page doesn't load: the node isn't built withdashboard(404), or the user isn't in--htpasswd(401). - A hollow node: no links report from it. If it is also dormant here, it is probably down or unreachable; if not, it may not take this node for a member yet (it hasn't registered it), or its answers don't arrive.
- Only dashed grey between two nodes: the member list wants them as neighbours, but neither reports a link to the other: they haven't reached each other (yet).
- A dotted link: one end has stopped reporting; the link is as it was last reported.
- A red band: one end holds the other dormant. If the other end still reports the link, the trouble is likely in one direction only.
Underneath
The page is GET /admin/dashboard, authenticated as the rest of /admin. It is kept up
to date through Server-Sent Events (/admin/dashboard/events);
/admin/dashboard/state has the latest state at once.
Events. One producer per node serves every client, and runs only while one is
connected (or for a minute after a /state request); a page hidden for 30 s
disconnects until it is shown again. Every 2 s it builds the state; when anything but
ages changed, it sends every client a JSON merge patch onto the state before. Nothing
changed, nothing is sent. Ages are as of the event, and the page counts them on. A click
on the status refreshes at once (POST /admin/dashboard/refresh). When the node stops,
every client gets an offline event and its stream ends, so stopping doesn't wait for
them; the page reconnects once the node is back, and reloads if the node now serves
another version of it (the state's page).
The map's graphs. The intended one is the neighbours the member list gives every
member (swarm::topology), as this node computes them. The measured one is every
member's links as it reports them in reply to a LINKS (sent to every member, at most
512, while the producer runs). The LINKS subscribes: the member replies again whenever
its links change (a peer, a transport, relayed, dormant, or a round trip moved by a
fifth; it looks every 2 s), for 90 s, renewed every 30 s (each renewal answered), and
ended when the producer stops; a node that is gone stops it by not renewing. A reply
older than 90 s is left out. A member keeps 64 subscribers at most. With links: every 30 s (POST /admin/dashboard/links?live=false; true back), the subscriptions end
and the members are only asked every 30 s, for every page open on this node, until
asked otherwise or the node restarts.
The links a member reports: its neighbours and the peers it holds dormant (a neighbour
that goes dormant is one no more, but stays listed until it is heard from again), by
which transport, whether only through a relay, the round trip (as the paths layer
measures it), whether it holds the peer dormant or the path is down, the peer's other
transports with a path up (each with its fastest path's round trip, and whether it goes
only through a relay), and the peer's clock against the member's (measurements.md,
Per peer, clock). A member answers a LINKS from members only, at most every 5 s, and
every build answers, with or without the feature (swarm::links).
Clocks. The clocks in the links chain every member's clock to this node's, along
the narrowest bounds, and the map takes each against their median: a member more than
--clock-skew-warn off it, beyond the chained bound, is ringed. With fewer than three
members compared, none is.
Messages on the map come from the per-peer message counts in the state (/peers,
traffic), not from messages of their own. The console's come from a log the node
keeps only while the producer runs (traffic::MessageLog, the latest 1000), sent as a
messages event every 2 s with those since the last.
The document is read through the store API, a level at a time as it is opened
(GET /store?shallow=true, then /store/<path>?shallow=true for each map opened, and
/store/<path> for a long value). Where it changes, the node says so (a document
event with the paths changed, at most every 2 s), and the page reads again what is open
there. A key with / in it (or an empty key) can't be opened: store paths are split at
/.
Edits go through the store API too, as the user the page was opened as: PUT /store/<path> (a text saved becomes a string; the root isn't written whole), a list's
items each on its own (PUT /store/<path>/<index>), a new key with PUT /store/<path>/<key>, an inserted item with POST /store/<path>/<index> (-1 the end;
an index past the end is refused), and DELETE /store/<path>. The dashboard itself
writes nothing to the document: only edits do.
