Sync WebCal and CalDAV directly; add a skip_past cutoff

WebCal is calcalist's own (src/webcal.rs), with Calendar::split_by_uid to turn
one feed document into one file per UID. Shared crate::http and crate::secret
came out of google/ so every leg uses them.

CalDAV follows, behind a per-endpoint 'native' flag so it can run beside
pimsync one collection at a time: src/caldav/client.rs speaks PROPFIND,
sync-collection, calendar-multiget and conditional PUT/DELETE, and
src/caldav/mod.rs is the pull/push pair. Radicale answers an initial
sync-collection with no members, so a cursor is only stored alongside a
complete read. doctor reports what a server advertises.

skip_past (src/horizon.rs) takes a date, not a flag: a rolling 'before now'
would retire events from the aggregate as they aged, deleting yesterday's
events on every cycle. Pinned to a date, what is mirrored stays mirrored. On
the real configuration it leaves 2600 of 3282 events behind. The filter sits
above the prior-links lookup in mirror_source, which is what makes it safe:
from there DeleteSource is unreachable, so excluding an event can never be
read as the user having deleted its mirror.

pimsync: CWD pinned so vstorage's relative unlink cannot reach the user's
files; the dry-run workspace is removed by Drop rather than by a line every
'?' stepped over.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
randogoth 2026-09-13 15:33:22 +03:00
parent d03748472a
commit 622a71dcd6
28 changed files with 2717 additions and 188 deletions

View file

@ -3,7 +3,11 @@ Description=Synchronise calendars with calcalist
[Service]
Type=oneshot
ExecStart=%h/.local/bin/calcalist sync
# The path the Nix install puts it at, which is also the one that guarantees a
# matching pimsync. A `cargo install` lands in %h/.cargo/bin instead; an
# absolute path is used either way because a user manager's PATH is not the
# login shell's and cannot be relied on to have found either.
ExecStart=%h/.nix-profile/bin/calcalist sync
NoNewPrivileges=true
# Deliberately no ProtectSystem, PrivateTmp or IPC sandboxing. Credentials come

View file

@ -4,7 +4,10 @@ Description=Synchronise calendars with calcalist every 15 minutes
[Timer]
OnBootSec=2m
OnUnitActiveSec=15m
Persistent=true
# No Persistent=: it only has an effect on OnCalendar= timers, and these are
# monotonic. OnBootSec= already covers the case it would be wanted for, which is
# catching up shortly after the machine comes back.
# Spreads requests instead of every installation calling Google on the quarter
# hour. Google's Calendar API quota is per project and enforced per minute, and