Outbox.kt
⎇
Raw
1package org.opentracker
2
3import android.content.Context
4import android.database.sqlite.SQLiteDatabase
5import android.database.sqlite.SQLiteOpenHelper
6
7/**
8 * Points waiting for upload. It survives process death.
9 * The server ignores a point it already has, so resending after a lost reply is safe.
10 */
11class Outbox(context: Context) : SQLiteOpenHelper(context, "outbox.db", null, 1) {
12
13 override fun onCreate(db: SQLiteDatabase) {
14 db.execSQL("CREATE TABLE points (ts INTEGER PRIMARY KEY, json TEXT NOT NULL)")
15 }
16
17 override fun onUpgrade(db: SQLiteDatabase, old: Int, new: Int) = Unit
18
19 /** Drops the oldest points beyond [MAX], so a long offline time cannot fill the disk. */
20 fun add(ts: Long, json: String) {
21 val db = writableDatabase
22 db.execSQL("INSERT OR REPLACE INTO points (ts, json) VALUES (?, ?)", arrayOf(ts, json))
23 db.execSQL("DELETE FROM points WHERE ts < (SELECT ts FROM points ORDER BY ts DESC LIMIT 1 OFFSET $MAX)")
24 }
25
26 /** The oldest points, as (ts, json). */
27 fun peek(limit: Int): List<Pair<Long, String>> =
28 readableDatabase.rawQuery("SELECT ts, json FROM points ORDER BY ts LIMIT $limit", null).use { c ->
29 buildList { while (c.moveToNext()) add(c.getLong(0) to c.getString(1)) }
30 }
31
32 fun removeUpTo(ts: Long) {
33 writableDatabase.execSQL("DELETE FROM points WHERE ts <= ?", arrayOf(ts))
34 }
35
36 fun count(): Long = readableDatabase.compileStatement("SELECT COUNT(*) FROM points").simpleQueryForLong()
37
38 /** Unix seconds of the oldest waiting point, or null. */
39 fun oldest(): Long? =
40 readableDatabase.rawQuery("SELECT MIN(ts) FROM points", null).use { c ->
41 if (c.moveToFirst() && !c.isNull(0)) c.getLong(0) else null
42 }
43
44 companion object {
45 const val MAX = 50_000
46 }
47}
48