The code¶
A map of the Python package unseenet (src/unseenet/): where each part
lives, and where new code goes. Every file opens with a docstring saying what
belongs in it - when in doubt, read the top of the file. The protocol itself
is in the UN-RFCs; the code follows them, and a file names
the sections it implements.
The layers¶
core/ the protocol: articles, keys, groups, postage - shared by node and client
client/ the client core: Session, the runtime, the local client API, the TUI
node/ the node: an ONNTP server that stores groups and passes articles on
cli/ the command line: `unseenet` (a client) and `unseenet-node` (a node)
core knows nothing of clients or nodes. client and node both build on
core, never on each other. Every client - the terminal client, the
graphical client (unseenet-gui), the web client, the command line, bots and
gateways - goes through Session, so they behave alike.
core: the protocol¶
| File | What |
|---|---|
article.py |
the article: parsing, the canonical form, Message-IDs (UN-RFC 0002) |
crypto.py, encoding.py |
identities, signatures, encryption, group keys (UN-RFC 0003) |
groups.py |
Group IDs, manifests, closed-group encryption, posting rules (UN-RFC 0004) |
pow.py |
proof-of-work postage (UN-RFC 0006) |
ripening.py |
key ripening (UN-RFC 0025) |
vault.py |
the encrypted client vault (UN-RFC 0007) |
tor.py |
starting Tor, its control port, onion connections |
markup.py |
Markdown and emoji as a small, safe tree (UN-RFC 0031) |
profiles.py |
profiles, pictures, identicons (UN-RFC 0022) |
blobs.py |
files as blobs (UN-RFC 0027) |
pins.py, pages.py |
pinned posts and pages, the kinds of kept articles (UN-RFC 0033, 0035) |
reconcile.py |
set reconciliation of key-bound state (UN-RFC 0040) |
store/ |
the node's store in SQLite - see below |
portals.py, gateways.py |
portals and the gateway directory (UN-RFC 0023, 0038) |
addresses.py |
unseenet: addresses: reading (also older forms) and writing (UN-RFC 0031 3.4.1) |
poster.py |
posting with no one at the keyboard: bots, gateways, scripts |
core/store: the node's store¶
| File | What |
|---|---|
__init__.py |
the SQLite schema, and Store joined from the parts |
base.py |
opening the store, the history of Message-IDs seen |
articles.py |
storing, finding, deleting and expiring articles |
groups.py |
manifests, carried groups, state, epochs, removal |
keybound.py |
key-bound groups: lifetime and reconciliation |
kept.py |
kept articles: pins and pages |
blobs.py |
blob references, deletion, refusal, quotas |
withdrawals.py |
cancels and edits |
peers.py |
peer queues, pull and reconcile state |
stats.py |
numbers for the operator's monitor |
A new table goes in the schema in __init__.py, its code in the file of its area.
client: the client core¶
| File | What |
|---|---|
session/ |
Session, the client core - see below and the reference |
runtime.py |
ClientRuntime: start-up, refresh and push, the same for every client |
events.py |
the events a session reports |
threads.py, grouptree.py, groupfilter.py |
laying out a group, the group tree, search - the same in every client |
naming.py |
names of groups and identities in the client (UN-RFC 0018, 0019) |
headless.py |
a session for a service with only a key |
media.py |
what a file is from its content, and pictures saved again without their metadata |
localapi/ |
the local client API (UN-RFC 0046) - see below and its page |
tui.py, richtext.py |
the terminal client |
client/session: Session¶
| File | What |
|---|---|
__init__.py |
the shared types (Message, GroupInfo, SessionError, ...), and Session joined from the parts |
base.py |
the vault, identities, settings, events |
ripening.py |
key ripening |
nodes.py |
nodes, the connection, push, Tor |
labels.py |
how people and groups are shown: names and labels |
groups.py |
manifests, creating and changing groups, moderation, roles, portals |
private.py |
the inbox, private posts and chats, key-bound groups and renewal |
profiles.py |
profiles and pictures |
people.py |
contacts, ignoring, for you and mentions, notices, bots, reporting |
reading.py |
following, fetching, threads and views, the offline cache, read marks |
posting.py |
posting, postage, editing and withdrawing |
attachments.py |
files on posts: preparing and checking them (UN-RFC 0027) |
kept.py |
pinned posts and the pages of sites, as the nodes keep them (UN-RFC 0033, 0035) |
personal.py |
an identity's personal feed and site (UN-RFC 0029 section 2.1) |
following.py |
following feeds and people, the timeline (UN-RFC 0034 sections 6, 7) |
state.py |
your state in the network, encrypted, merged and written (UN-RFC 0044) |
A new function goes in the file whose docstring says it belongs there; a new
area gets a file of its own, added to Session in __init__.py. Every public
function has a docstring - a test checks it.
client/localapi: the local client API¶
server.py puts the API on HTTP and a WebSocket; api/ is what answers, one
file per section of UN-RFC 0046: state.py (4.1),
setup.py (4.2), groups.py (4.3), writing.py (4.4, 4.5), people.py
(4.6), running.py (4.7), identity.py (4.8), articles.py (4.9) and
events.py (5). A new request goes in its section's file, with a route in
server.py.
node: the node¶
| File | What |
|---|---|
server/ |
Node and Session (one connection) - see below |
peering.py |
streaming articles to peers (UN-RFC 0005 section 5.2) |
pulling.py |
catching up from peers (UN-RFC 0017, 0040) |
blobfetch.py |
blobs following their article (UN-RFC 0027 section 6.3) |
stats.py |
what the node tells its operator |
node/server¶
Node |
Session (one connection) |
||
|---|---|---|---|
node.py |
the node, watchers, node info, serving | connection.py |
the command loop, CAPABILITIES |
accepting.py |
the accept pipeline: the order of the checks | auth_commands.py |
AUTHINFO, XUN-PEER |
postage.py |
postage, key ripening | lists_commands.py |
LIST, XUN-WATCH, node info |
manifests.py |
manifests, new and removed groups | reading_commands.py |
GROUP, ARTICLE, OVER, HDR |
controls.py |
key updates, cancels | peering_commands.py |
IHAVE, TAKETHIS, NEWNEWS, XUN-RECONCILE, XUN-MANIFESTS |
kept.py |
pins and pages | posting_commands.py |
POST |
blobs.py |
blobs | blob_commands.py |
BLOBPOST, BLOB |
blocks.py |
maintainers' blocks | ||
edits.py |
edits | ||
forwarding.py |
queueing for peers |
The rules for one kind of article go in its file; accepting.py only decides
their order. A new NNTP command is a cmd_<name> method in the commands file
of its area.
cli: the command line¶
node.py is unseenet-node; the unseenet client's commands are by area in
basics.py, groups.py, messages.py, network.py, services.py and
kept.py (pins, pages, personal groups), following.py (profile, follow,
timeline, addresses), and
main.py holds the parser and which function each command runs.
Around them¶
known_nodes.py and hierarchies.py (the project's lists), names.py and
registrar.py (names, UN-RFC 0019), nntp.py (the ONNTP client),
portable.py, launcher.py, update.py and boot.py (the portable and
bootable builds), monitor.py (unseenet-monitor).
Tools for checking the code¶
pytest: the test suite.tests/test_docstrings.pychecks that every publicSessionfunction has a docstring.tools/dev/check_globals.py <root> <package>...: every global name a function in a package looks up exists in its file - catches what a split or a move can break where no test reaches.