Development
cargo fmt --check && cargo clippy --all-targets -- -D warnings && cargo test| Tests cover | |
|---|---|
| Parser and conversion | against examples/telegram and examples/whatsapp |
| Share links | visitor isolation, PIN lockout, media allow-list, rooms, names, blocking, auth bypass |
| MCP client | mock servers of every protocol era (HTTP, legacy SSE, stdio) |
| Relay | hub, names, forwarding |
The desktop crate is separate: cd desktop && cargo check.
Layout
src/ server (axum), parsers, LLM agent, MCP client, share links, relay, Telegram
server/ the owner's HTTP API, one file per area: assets, uploads, exports, chats,
messages, settings, media; mod.rs builds the routers
share_api/ share links: owner.rs (managing links and visitors), visitor.rs (/s/…)
web/ the UI: index.html, app.css and js/ (served as one app.js), embedded into the binary
js/ one file per area of the UI, numbered in load order (one script, one scope)
desktop/ Tauri app around the same server
deploy/ Caddy + Docker Compose
examples/ two fictional exportsThe documentation and the splash page of iroof.top are not in this repository. They live in irooftop/irooftop.github.io: docs/ (this site) and landing/.
Docs
The docs are in irooftop/irooftop.github.io. They take the images and the app version from this repository: check out both side by side, then build there.
cd irooftop.github.io/docs
npm ci
ROOFTOP_SRC=../../rooftop npm run dev # http://localhost:5173/
ROOFTOP_SRC=../../rooftop npm run build # docs/.vitepress/distThe site deploys to irooftop.github.io on every push to main of that repository that touches docs/. demo.svg is built by python3 scripts/demo-svg.py in the app repository (plain SVG and CSS, so GitHub renders it).
Releasing
bump Cargo.toml ─▶ tag vX.Y.Z ─┬─▶ Release: crates.io + ghcr.io image (amd64 + arm64, native runners)
└─▶ desktop: installers ─▶ publish release (latest) ─▶ Homebrew: formula + cask- Bump
versioninCargo.toml(anddesktop/), commit, push a tagvX.Y.Z. The tag must be numeric for the Windows MSI. Everything below then runs without further clicks. - Release publishes the crate (secret
CARGO_REGISTRY_TOKEN, environmentcrates-io) and the Docker image: one job per architecture on a native runner (ubuntu-latest,ubuntu-24.04-arm) pushes by digest, and amergejob creates the multi-arch tags. Run it by hand withdry_runto check crate publishing. - desktop builds installers for macOS (arm64, x64), Windows and Linux into a draft release. When all of them are attached, its
publishjob fills in generated release notes, publishes the release and marks it latest. - Its
homebrewjob then calls Homebrew, which pushesFormula/rooftop.rbandCasks/irooftop.rbtoirooftop/homebrew-tap. It needs the secretHOMEBREW_TAP_TOKEN(fine-grained token,irooftop/homebrew-tap, Contents: read and write) orHOMEBREW_TAP_DEPLOY_KEY; without one it skips with a notice. (A release published byGITHUB_TOKENdoes not firerelease: published, which is why the call is explicit; publishing a release by hand still triggers Homebrew through that event.)
Rerun the tap update for an existing tag, for example after adding the secret:
gh workflow run homebrew.yml -f tag=v0.3.0scripts/homebrew-tap.sh vX.Y.Z <tap checkout> renders the same files locally. If the installers of a tag failed, rerun the failed desktop jobs: publish and homebrew follow once they pass.