commit 6b049a0a5b6a3319325369fce0e30b7fa3da26f7 equwal <truex@equwal.com> 2026-09-25 02:15:58 -0700 Add the feed timer, a deploy script and the feed docs contrib/sbm-feed.service and contrib/sbm-feed.timer run `sbm-sync feed` every 30 minutes as the sbm user with the environment of the server. contrib/deploy.sh builds the server for Linux, keeps the old binary as a backup, installs the binary, the units and sfeed, and restarts the service. The README describes the feed page, the API and the data.
.gitignore | 1 + README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ contrib/deploy.sh | 36 ++++++++++++++++++++++++++++++++++++ contrib/sbm-feed.service | 24 ++++++++++++++++++++++++ contrib/sbm-feed.timer | 11 +++++++++++ 5 files changed, 119 insertions(+)
diff --git a/.gitignore b/.gitignore index 84c3a8c..30a0cce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ data/ /sbm-sync /sbm-sync.exe +/sbm-sync-linux *.env diff --git a/README.md b/README.md index 9b9c855..4e6aae1 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,39 @@ The pages obey the rules of sync: the email address must be confirmed, and with billing on, the account needs its trial or a subscription. The download always works, because the bookmarks belong to their owner. +## Feeds + +After you sign in, the page **/feed** follows RSS and Atom feeds for you. +It uses [sfeed](https://codemadness.org/sfeed.html) on the server: + +- Follow a feed: type its address and a name. The list is one plain file, + `feeds.txt`, with one feed on each line: the URL, a tab and the name. +- The server fetches the feeds every 30 minutes with `sfeed_update` and + shows the items newest first, with the feed, the time and the author. A + setting opens the links in a new tab. +- Explore: turn it on, and the server looks through your bookmarked pages + for feeds with `sfeed_web`, 20 pages with each update, and offers what it + finds. +- Digest: turn it on, and the server sends you the new items by email once + a day, in the form of `sfeed_plain`. The first day after you turn it on + sends nothing, so that you do not get the whole history. + +Read the feed in a terminal with the token of a device (`bm-sync login` +keeps one in `~/.config/sbm/sync`): + + curl -H "Authorization: Bearer $token" https://sbmsync.com/api/feed | sfeed_plain + curl -H "Authorization: Bearer $token" https://sbmsync.com/api/feeds + +`/api/feed` gives the items of all your feeds in the sfeed format, newest +first, so `sfeed_plain`, `sfeed_curses`, `sfeed_html` and the other sfeed +tools read it. `/api/feeds` gives `feeds.txt`. + +The feed job fetches only feeds and pages on the public internet: an +address that points to a private network, or to the server itself, is +skipped. The job runs as the command `sbm-sync feed`; `contrib/` has a +systemd service and a timer for it, and `contrib/deploy.sh` installs them +together with the server. + ## Protocol Plain HTTP, for any client with curl. @@ -92,6 +125,11 @@ Plain HTTP, for any client with curl. 200: the address of a Stripe Checkout page POST /api/portal Authorization: Bearer <token> 200: the address of the Stripe customer portal + GET /api/feed Authorization: Bearer <token> + 200: the items of all feeds, newest first, in + the sfeed(5) format, one item on each line + GET /api/feeds Authorization: Bearer <token> + 200: the feeds, one on each line: URL, tab, name Errors come as text: 401 (sign in again), 402 (the subscription or the trial has ended), 403 (confirm the email address first), 404 (the server @@ -136,6 +174,12 @@ an nginx site and a Caddyfile. With Go installed on another computer: GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build +For the feeds, install `sfeed` (a Debian package) and run `sbm-sync feed` +every 30 minutes with the same environment as the server: +`contrib/sbm-feed.service` and `contrib/sbm-feed.timer` do that with +systemd. `sh contrib/deploy.sh root@sbm.example.org` builds the server, +installs it, the timer and sfeed on the server, and restarts the service. + ### Connect the devices Sign in with the address of your server: `bm-sync login @@ -210,6 +254,9 @@ The Chrome Web Store asks for them. To change them, edit the template customer and subscription state data/files/<account>/<sha256> the last 50 versions of each bookmark file data/files/<account>/HEAD name of the current version + data/feeds/<account>/ the feeds: feeds.txt, the sfeedrc made + from it, items/<feed> from sfeed_update, + explore, and the state of the digest To back up, copy the directory. diff --git a/contrib/deploy.sh b/contrib/deploy.sh new file mode 100644 index 0000000..527676a --- /dev/null +++ b/contrib/deploy.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# deploy.sh: build sbm-sync for Linux and install it on a server that runs +# sbm-sync.service (see sbm-sync.service) with systemd and nginx. +# +# sh contrib/deploy.sh root@example.org +# +# The script keeps the old binary as /usr/local/bin/sbm-sync.bak-<time>, +# installs sfeed for the feed job, and starts sbm-feed.timer. +set -e +host=${1:?usage: sh contrib/deploy.sh user@host} +cd "$(dirname "$0")/.." +GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -o sbm-sync-linux . +scp sbm-sync-linux contrib/sbm-feed.service contrib/sbm-feed.timer "$host:/tmp/" +rm sbm-sync-linux +ssh "$host" sh -s << 'EOF' +set -e +if ! command -v sfeed_update >/dev/null; then + DEBIAN_FRONTEND=noninteractive apt-get install -y -q sfeed +fi +if [ -f /usr/local/bin/sbm-sync ]; then + cp -p /usr/local/bin/sbm-sync "/usr/local/bin/sbm-sync.bak-$(date +%Y%m%d-%H%M%S)" +fi +install -m 755 /tmp/sbm-sync-linux /usr/local/bin/sbm-sync +install -m 644 /tmp/sbm-feed.service /tmp/sbm-feed.timer /etc/systemd/system/ +rm /tmp/sbm-sync-linux /tmp/sbm-feed.service /tmp/sbm-feed.timer +systemctl daemon-reload +systemctl restart sbm-sync +systemctl enable --now sbm-feed.timer +sleep 1 +if ! systemctl is-active --quiet sbm-sync; then + journalctl -u sbm-sync -n 20 --no-pager + exit 1 +fi +echo "sbm-sync: $(systemctl is-active sbm-sync), sbm-feed.timer: $(systemctl is-active sbm-feed.timer)" +systemctl list-timers sbm-feed.timer --no-pager +EOF diff --git a/contrib/sbm-feed.service b/contrib/sbm-feed.service new file mode 100644 index 0000000..1b3993f --- /dev/null +++ b/contrib/sbm-feed.service @@ -0,0 +1,24 @@ +# The feed job of sbm-sync: it fetches the feeds of every account with +# sfeed_update, looks through bookmarks for feeds, and sends the daily +# digests. sbm-feed.timer starts it every 30 minutes. Install: +# apt-get install sfeed +# install -m 644 contrib/sbm-feed.service contrib/sbm-feed.timer /etc/systemd/system/ +# systemctl daemon-reload && systemctl enable --now sbm-feed.timer +[Unit] +Description=sbm Sync feed job +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +User=sbm +Group=sbm +EnvironmentFile=/etc/sbm-sync.env +Environment=SBM_DATA=/var/lib/sbm-sync +ExecStart=/usr/local/bin/sbm-sync feed +NoNewPrivileges=yes +ProtectSystem=strict +ProtectHome=yes +PrivateTmp=yes +PrivateDevices=yes +ReadWritePaths=/var/lib/sbm-sync diff --git a/contrib/sbm-feed.timer b/contrib/sbm-feed.timer new file mode 100644 index 0000000..ab3cff5 --- /dev/null +++ b/contrib/sbm-feed.timer @@ -0,0 +1,11 @@ +# Runs sbm-feed.service every 30 minutes. See sbm-feed.service. +[Unit] +Description=Run the sbm Sync feed job every 30 minutes + +[Timer] +OnCalendar=*:0/30 +RandomizedDelaySec=60 +Persistent=true + +[Install] +WantedBy=timers.target