mavcaldav: reconcile the render collection on startup

Withdrawal read published, which is in-memory, so the second loop only
ever withdrew reminders this process had published. Fire a reminder,
restart mavcaldav, and its event stayed in the collection forever with
nothing left to revisit it. "Losing it costs nothing, the next tick
rebuilds it" holds for events that should be there and not for the ones
that should not.

The first tick now PROPFINDs the collection and reconciles what it finds
against what is pending. Only hrefs carrying ReminderUIDPrefix are read
back, so the pass can never propose deleting a file maven did not create.
A failed read is retried on the next tick rather than skipped for the
life of the process.

Two smaller things from the same review. checkRenderTarget takes the
whole read set, so a second calendar to read cannot quietly fall outside
the guarantee the package comment makes. writeIfChanged loses its
confidence parameter, which every caller passed 1.0 and nothing read.
Found in review of #56.
This commit is contained in:
kami
2026-08-01 14:11:07 +04:00
parent bddf52d1ee
commit 1c94df76b7
5 changed files with 264 additions and 34 deletions
+24
View File
@@ -2,6 +2,7 @@ package calendar
import (
"fmt"
"strconv"
"strings"
"time"
)
@@ -43,3 +44,26 @@ func ReminderEvent(id int64, fire time.Time, payload string, dur time.Duration)
func ReminderPath(id int64) string {
return fmt.Sprintf("%s%d.ics", ReminderUIDPrefix, id)
}
// ReminderIDFromPath reads back what ReminderPath wrote, given an href out of a
// PROPFIND. It reports false for anything that is not a resource maven
// published, which is what keeps a reconciliation pass from touching a file it
// did not create.
func ReminderIDFromPath(href string) (int64, bool) {
name := href
if i := strings.LastIndex(name, "/"); i >= 0 {
name = name[i+1:]
}
if !strings.HasPrefix(name, ReminderUIDPrefix) || !strings.HasSuffix(name, ".ics") {
return 0, false
}
digits := name[len(ReminderUIDPrefix) : len(name)-len(".ics")]
if digits == "" {
return 0, false
}
id, err := strconv.ParseInt(digits, 10, 64)
if err != nil || id <= 0 {
return 0, false
}
return id, true
}