calendar: кэш событий по CTag (Этап 2, DAV ч.2)
listCalendars теперь забирает и cs:getctag (тот же PROPFIND — ноль лишних запросов; DavCalendar.ctag). Новый CalendarEventsCache — дисковый кэш СЫРЫХ REPORT-ответов per (аккаунт, календарь, диапазон), ключ — CTag: не менялся → события парсятся с диска (боевым парсером CalDavClient), REPORT-запросы в сеть не идут. Изменился → сеть + обновление кэша. Хранение сырого XML вместо сериализации моделей — без хрупкого JSON-маппинга ~20 полей события; чистка записей старше 30 дней. CalDavClient.queryEventsInRange разделён на queryEventsRawXml + parseEventsXml (поведение прежнее). Эффект: переключение месяцев, периодический рефреш и возврат в календарь при неизменных календарях — 1 PROPFIND вместо 1+N REPORT. +5 unit-тестов кэша (JVM, TemporaryFolder).
This commit is contained in:
@@ -22,6 +22,9 @@ data class DavCalendar(
|
||||
val href: String,
|
||||
val displayName: String,
|
||||
val color: String? = null,
|
||||
// CTag коллекции (CalendarServer-расширение, Nextcloud поддерживает):
|
||||
// меняется при любом изменении в календаре → ключ инкрементального кэша событий.
|
||||
val ctag: String = "",
|
||||
)
|
||||
|
||||
data class DavEvent(
|
||||
@@ -103,7 +106,7 @@ object CalDavClient {
|
||||
val body = """
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<d:propfind xmlns:d="DAV:" xmlns:cs="http://calendarserver.org/ns/" xmlns:ical="http://apple.com/ns/ical/">
|
||||
<d:prop><d:displayname/><d:resourcetype/><ical:calendar-color/></d:prop>
|
||||
<d:prop><d:displayname/><d:resourcetype/><ical:calendar-color/><cs:getctag/></d:prop>
|
||||
</d:propfind>
|
||||
""".trimIndent()
|
||||
val xml = propfind(client, baseUrl, depth = 1, body)
|
||||
@@ -129,7 +132,15 @@ object CalDavClient {
|
||||
calendar: DavCalendar,
|
||||
rangeStart: Instant,
|
||||
rangeEnd: Instant,
|
||||
): List<DavEvent> {
|
||||
): List<DavEvent> = parseEventsXml(queryEventsRawXml(client, calendar, rangeStart, rangeEnd), calendar)
|
||||
|
||||
/** Сырой REPORT-ответ (для кэширования на диске с ключом по CTag). */
|
||||
fun queryEventsRawXml(
|
||||
client: OkHttpClient,
|
||||
calendar: DavCalendar,
|
||||
rangeStart: Instant,
|
||||
rangeEnd: Instant,
|
||||
): String {
|
||||
val startStr = formatCalDavTime(rangeStart)
|
||||
val endStr = formatCalDavTime(rangeEnd)
|
||||
val body = """
|
||||
@@ -146,10 +157,13 @@ object CalDavClient {
|
||||
</c:calendar-query>
|
||||
""".trimIndent()
|
||||
val href = calendar.href.trimEnd('/') + "/"
|
||||
val xml = report(client, href, body)
|
||||
return parseCalendarQueryResponses(xml, calendar)
|
||||
return report(client, href, body)
|
||||
}
|
||||
|
||||
/** Парсинг REPORT-ответа (в т.ч. взятого из кэша). */
|
||||
fun parseEventsXml(xml: String, calendar: DavCalendar): List<DavEvent> =
|
||||
parseCalendarQueryResponses(xml, calendar)
|
||||
|
||||
fun createEvent(
|
||||
client: OkHttpClient,
|
||||
calendar: DavCalendar,
|
||||
@@ -782,6 +796,7 @@ object CalDavClient {
|
||||
var href = ""
|
||||
var displayName = ""
|
||||
var calendarColor: String? = null
|
||||
var ctag = ""
|
||||
var isCollection = false
|
||||
while (parser.eventType != XmlPullParser.END_DOCUMENT) {
|
||||
when (parser.eventType) {
|
||||
@@ -791,11 +806,13 @@ object CalDavClient {
|
||||
href = ""
|
||||
displayName = ""
|
||||
calendarColor = null
|
||||
ctag = ""
|
||||
isCollection = false
|
||||
}
|
||||
"collection" -> if (inResponse) isCollection = true
|
||||
"displayname" -> if (inResponse) displayName = parser.readText().trim()
|
||||
"calendar-color" -> if (inResponse) calendarColor = parser.readText().trim()
|
||||
"getctag" -> if (inResponse) ctag = parser.readText().trim()
|
||||
"href" -> if (inResponse) href = parser.readText().trim()
|
||||
}
|
||||
XmlPullParser.END_TAG -> if (parser.localTag() == "response" && inResponse) {
|
||||
@@ -809,7 +826,7 @@ object CalDavClient {
|
||||
val name = displayName.ifBlank {
|
||||
fullPath.removePrefix(basePath).trim('/').substringAfterLast('/')
|
||||
}
|
||||
out += DavCalendar(href = full, displayName = name, color = calendarColor)
|
||||
out += DavCalendar(href = full, displayName = name, color = calendarColor, ctag = ctag)
|
||||
}
|
||||
}
|
||||
inResponse = false
|
||||
|
||||
Reference in New Issue
Block a user