The daemon-agnostic gopher mechanics shared by
gopher-cta (live CTA trains over
gopher) and gopher-blog (the
debene.dev phlog). Extracted from the spine both daemons had copied verbatim, once
the [Entry] host/port API settled.
Deliberately tiny and std-only — no serde, no external deps:
- Menu model —
Entry/ItemKindand theinfo/linkbuilders;Entry::with_hoststamps a concrete host/port on a cross-server link.ItemKindcoversText(0),Menu(1),Search(7, index-search),Url(h, external link) andBin(9, binary download). - Serializer —
render_menu_index: anEntrylist -> a geomyidae.gphindex. (Targeting another daemon = rewrite only this.) - Publish primitives —
new_snapshot(out-<ts>/),write_files,flip_current(atomic symlink rename),gc(out, keep)(keep newestkeep+ whatevercurrentresolves to), and thepublishconvenience.
gopher-core = { git = "https://github.com/felipedbene/gopher-core", tag = "v0.2.0" }use gopher_core::{info, link, ItemKind, render_menu_index, publish};
let menu = vec![
info(" my hole"),
link(ItemKind::Menu, "Posts", "/posts"),
link(ItemKind::Menu, "Other hole", "/").with_host("other.example", 70),
];
let gph = render_menu_index(&menu); // -> geomyidae .gph
// publish(out_dir, &[(path, bytes)], keep) // atomic snapshot + flip + gcEach consumer pins its own tag and bumps when it chooses, so a core change never auto-propagates into a live build.
MIT — see LICENSE.