feat: add sync service with WebDAV merge logic
This commit is contained in:
parent
553284f3b2
commit
58e1cd0c19
2 changed files with 147 additions and 0 deletions
90
src/sync/syncService.ts
Normal file
90
src/sync/syncService.ts
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import { Measurement } from '../types'
|
||||
import { initDatabase, getAllMeasurements, upsertMeasurement } from '../database/db'
|
||||
import { getWebDAVConfig } from '../screens/SettingsScreen'
|
||||
|
||||
const WEBDAV_PATH = 'weegschaal/measurements.json'
|
||||
|
||||
type SyncResult = { local: number; remote: number; merged: number }
|
||||
|
||||
export function mergeMeasurements(local: Measurement[], remote: Measurement[]): Measurement[] {
|
||||
const map = new Map<string, Measurement>()
|
||||
|
||||
for (const m of local) {
|
||||
map.set(m.id, m)
|
||||
}
|
||||
|
||||
for (const m of remote) {
|
||||
const existing = map.get(m.id)
|
||||
if (!existing || new Date(m.updatedAt) > new Date(existing.updatedAt)) {
|
||||
map.set(m.id, { ...m, syncStatus: 'synced' })
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(map.values())
|
||||
}
|
||||
|
||||
async function fetchRemote(config: { url: string; username: string; password: string }): Promise<Measurement[]> {
|
||||
const url = `${config.url.replace(/\/+$/, '')}/${WEBDAV_PATH}`
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
Authorization: 'Basic ' + btoa(`${config.username}:${config.password}`),
|
||||
},
|
||||
})
|
||||
|
||||
if (response.status === 404) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`WebDAV fetch failed: ${response.status}`)
|
||||
}
|
||||
|
||||
return response.json()
|
||||
}
|
||||
|
||||
async function uploadRemote(
|
||||
config: { url: string; username: string; password: string },
|
||||
measurements: Measurement[]
|
||||
): Promise<void> {
|
||||
const url = `${config.url.replace(/\/+$/, '')}/${WEBDAV_PATH}`
|
||||
const body = JSON.stringify(measurements)
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
Authorization: 'Basic ' + btoa(`${config.username}:${config.password}`),
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body,
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`WebDAV upload failed: ${response.status}`)
|
||||
}
|
||||
}
|
||||
|
||||
export async function syncAll(): Promise<SyncResult> {
|
||||
const config = await getWebDAVConfig()
|
||||
if (!config) {
|
||||
throw new Error('Geen WebDAV configuratie. Stel deze eerst in in Instellingen.')
|
||||
}
|
||||
|
||||
await initDatabase()
|
||||
|
||||
const local = await getAllMeasurements()
|
||||
const remote = await fetchRemote(config)
|
||||
|
||||
const merged = mergeMeasurements(local, remote)
|
||||
|
||||
for (const m of merged) {
|
||||
await upsertMeasurement(m)
|
||||
}
|
||||
|
||||
await uploadRemote(config, merged)
|
||||
|
||||
return {
|
||||
local: local.length,
|
||||
remote: remote.length,
|
||||
merged: merged.length,
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue