Refactor: Move history table to its own database

This commit refactors the database structure by moving the `history` table from the main `AppDatabase` into a new, separate `HistoryDatabase`.

Key changes:
- Create a new `HistoryDatabase` and `HistoryDao` to manage all event history records.
- Remove the `history` table and related DAO methods from `AppDatabase` and `ApplicationDao`.
- Add a migration (`MIGRATION_15_16`) to drop the old `history` table from `AppDatabase`.
- Update all call sites throughout the application to use the new `HistoryDatabase` for storing and retrieving history events.
- The `Amber` class now manages instances of `HistoryDatabase` for each account.
This commit is contained in:
greenart7c3
2025-10-24 10:25:39 -03:00
parent 3acf9089b3
commit f84d0bd29e
19 changed files with 581 additions and 156 deletions
@@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 15,
"identityHash": "3690c8720be33c75a319014268cf1afe",
"identityHash": "92867f818b27cf76fafbe2ba5c6cd100",
"entities": [
{
"tableName": "application",
@@ -214,7 +214,7 @@
]
},
{
"tableName": "history2",
"tableName": "history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `time` INTEGER NOT NULL, `accepted` INTEGER NOT NULL)",
"fields": [
{
@@ -261,22 +261,22 @@
},
"indices": [
{
"name": "history_by_pk_key2",
"name": "history_by_pk_key",
"unique": false,
"columnNames": [
"pkKey"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key2` ON `${TABLE_NAME}` (`pkKey`)"
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
},
{
"name": "history_by_id2",
"name": "history_by_id",
"unique": false,
"columnNames": [
"id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id2` ON `${TABLE_NAME}` (`id`)"
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "history_by_time",
@@ -302,7 +302,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3690c8720be33c75a319014268cf1afe')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '92867f818b27cf76fafbe2ba5c6cd100')"
]
}
}
@@ -0,0 +1,222 @@
{
"formatVersion": 1,
"database": {
"version": 16,
"identityHash": "e6b7bce07714a5336bb9200ed1760153",
"entities": [
{
"tableName": "application",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `name` TEXT NOT NULL, `relays` TEXT NOT NULL, `url` TEXT NOT NULL, `icon` TEXT NOT NULL, `description` TEXT NOT NULL, `pubKey` TEXT NOT NULL, `isConnected` INTEGER NOT NULL, `secret` TEXT NOT NULL, `useSecret` INTEGER NOT NULL, `signPolicy` INTEGER NOT NULL, `closeApplication` INTEGER NOT NULL, `deleteAfter` INTEGER NOT NULL, `lastUsed` INTEGER NOT NULL, PRIMARY KEY(`key`))",
"fields": [
{
"fieldPath": "key",
"columnName": "key",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "relays",
"columnName": "relays",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "pubKey",
"columnName": "pubKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "isConnected",
"columnName": "isConnected",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "secret",
"columnName": "secret",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "useSecret",
"columnName": "useSecret",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "signPolicy",
"columnName": "signPolicy",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "closeApplication",
"columnName": "closeApplication",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "deleteAfter",
"columnName": "deleteAfter",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "lastUsed",
"columnName": "lastUsed",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"key"
]
},
"indices": [
{
"name": "index_key",
"unique": true,
"columnNames": [
"key"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_key` ON `${TABLE_NAME}` (`key`)"
},
{
"name": "index_name",
"unique": false,
"columnNames": [
"name"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)"
}
]
},
{
"tableName": "applicationPermission",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `acceptable` INTEGER NOT NULL, `rememberType` INTEGER NOT NULL, `acceptUntil` INTEGER NOT NULL, `rejectUntil` INTEGER NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER"
},
{
"fieldPath": "pkKey",
"columnName": "pkKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "kind",
"columnName": "kind",
"affinity": "INTEGER"
},
{
"fieldPath": "acceptable",
"columnName": "acceptable",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "rememberType",
"columnName": "rememberType",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "acceptUntil",
"columnName": "acceptUntil",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "rejectUntil",
"columnName": "rejectUntil",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "permissions_by_pk_key",
"unique": false,
"columnNames": [
"pkKey"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `permissions_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
},
{
"name": "permissions_unique",
"unique": true,
"columnNames": [
"pkKey",
"type",
"kind"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `permissions_unique` ON `${TABLE_NAME}` (`pkKey`, `type`, `kind`)"
}
],
"foreignKeys": [
{
"table": "application",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"pkKey"
],
"referencedColumns": [
"key"
]
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'e6b7bce07714a5336bb9200ed1760153')"
]
}
}
@@ -0,0 +1,99 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "29d5da9510c1dd78f8bdf4641d6cdf33",
"entities": [
{
"tableName": "history",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `time` INTEGER NOT NULL, `accepted` INTEGER NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "pkKey",
"columnName": "pkKey",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "kind",
"columnName": "kind",
"affinity": "INTEGER"
},
{
"fieldPath": "time",
"columnName": "time",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "accepted",
"columnName": "accepted",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "history_by_pk_key",
"unique": false,
"columnNames": [
"pkKey"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
},
{
"name": "history_by_id",
"unique": false,
"columnNames": [
"id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "history_by_time",
"unique": false,
"columnNames": [
"time"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_time` ON `${TABLE_NAME}` (`time`)"
},
{
"name": "history_by_key_and_time",
"unique": false,
"columnNames": [
"pkKey",
"time"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_key_and_time` ON `${TABLE_NAME}` (`pkKey`, `time`)"
}
]
}
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '29d5da9510c1dd78f8bdf4641d6cdf33')"
]
}
}
@@ -16,6 +16,7 @@ import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.greenart7c3.nostrsigner.database.AppDatabase
import com.greenart7c3.nostrsigner.database.HistoryDatabase
import com.greenart7c3.nostrsigner.database.LogDatabase
import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.AmberSettings
@@ -117,6 +118,7 @@ class Amber : Application(), LifecycleObserver {
private var databases = ConcurrentHashMap<String, AppDatabase>()
private var logDatabases = ConcurrentHashMap<String, LogDatabase>()
private var historyDatabases = ConcurrentHashMap<String, HistoryDatabase>()
val isOnMobileDataState = mutableStateOf(false)
val isOnWifiDataState = mutableStateOf(false)
@@ -382,6 +384,13 @@ class Amber : Application(), LifecycleObserver {
return logDatabases[npub]!!
}
fun getHistoryDatabase(npub: String): HistoryDatabase {
if (!historyDatabases.containsKey(npub)) {
historyDatabases[npub] = HistoryDatabase.getDatabase(this, npub)
}
return historyDatabases[npub]!!
}
fun getSavedRelays(): Set<NormalizedRelayUrl> {
val savedRelays = mutableSetOf<NormalizedRelayUrl>()
LocalPreferences.allSavedAccounts(this).forEach { accountInfo ->
@@ -99,6 +99,7 @@ class SignerProvider : ContentProvider() {
return null
}
val database = Amber.instance.getDatabase(account.npub)
val historyDatabase = Amber.instance.getHistoryDatabase(account.npub)
val permission =
database
.applicationDao()
@@ -113,7 +114,7 @@ class SignerProvider : ContentProvider() {
}
if (!isRemembered) {
scope.launch {
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
packageName,
@@ -122,6 +123,7 @@ class SignerProvider : ContentProvider() {
TimeUtils.now(),
false,
),
account.npub,
)
}
val cursor =
@@ -134,7 +136,7 @@ class SignerProvider : ContentProvider() {
val result = signString(message, account.signer.keyPair.privKey!!).toHexKey()
scope.launch {
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
packageName,
@@ -143,6 +145,7 @@ class SignerProvider : ContentProvider() {
TimeUtils.now(),
true,
),
account.npub,
)
}
@@ -180,6 +183,7 @@ class SignerProvider : ContentProvider() {
}
val database = Amber.instance.getDatabase(account.npub)
val historyDatabase = Amber.instance.getHistoryDatabase(account.npub)
var permission =
database
.applicationDao()
@@ -211,7 +215,7 @@ class SignerProvider : ContentProvider() {
}
if (!isRemembered) {
scope.launch {
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
packageName,
@@ -220,6 +224,7 @@ class SignerProvider : ContentProvider() {
TimeUtils.now(),
false,
),
account.npub,
)
}
@@ -234,7 +239,7 @@ class SignerProvider : ContentProvider() {
val signedEvent = account.signer.signerSync.sign<Event>(event.createdAt, event.kind, event.tags, event.content)
scope.launch {
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
packageName,
@@ -243,6 +248,7 @@ class SignerProvider : ContentProvider() {
TimeUtils.now(),
true,
),
account.npub,
)
}
@@ -278,6 +284,7 @@ class SignerProvider : ContentProvider() {
val account = LocalPreferences.loadFromEncryptedStorageSync(context!!, npub) ?: return null
val database = Amber.instance.getDatabase(account.npub)
val logDatabase = Amber.instance.getLogDatabase(account.npub)
val historyDatabase = Amber.instance.getHistoryDatabase(account.npub)
var permission =
database
.applicationDao()
@@ -312,7 +319,7 @@ class SignerProvider : ContentProvider() {
}
if (!isRemembered) {
scope.launch {
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
packageName,
@@ -321,6 +328,7 @@ class SignerProvider : ContentProvider() {
TimeUtils.now(),
false,
),
account.npub,
)
}
@@ -366,7 +374,7 @@ class SignerProvider : ContentProvider() {
}
scope.launch {
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
packageName,
@@ -375,6 +383,7 @@ class SignerProvider : ContentProvider() {
TimeUtils.now(),
true,
),
account.npub,
)
}
@@ -402,6 +411,7 @@ class SignerProvider : ContentProvider() {
return null
}
val database = Amber.instance.getDatabase(account.npub)
val historyDatabase = Amber.instance.getHistoryDatabase(account.npub)
val permission =
database
.applicationDao()
@@ -417,7 +427,7 @@ class SignerProvider : ContentProvider() {
}
if (!isRemembered) {
scope.launch {
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
packageName,
@@ -426,6 +436,7 @@ class SignerProvider : ContentProvider() {
TimeUtils.now(),
false,
),
account.npub,
)
}
@@ -438,7 +449,7 @@ class SignerProvider : ContentProvider() {
}
scope.launch {
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
packageName,
@@ -447,6 +458,7 @@ class SignerProvider : ContentProvider() {
TimeUtils.now(),
true,
),
account.npub,
)
}
@@ -138,13 +138,22 @@ val MIGRATION_14_15 = object : Migration(14, 15) {
}
}
val MIGRATION_15_16 = object : Migration(15, 16) {
override fun migrate(db: SupportSQLiteDatabase) {
try {
db.execSQL("DROP TABLE history2")
} catch (e: Exception) {
Log.e(Amber.TAG, "No amber_log table", e)
}
}
}
@Database(
entities = [
ApplicationEntity::class,
ApplicationPermissionsEntity::class,
HistoryEntity::class,
],
version = 15,
version = 16,
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
@@ -181,6 +190,7 @@ abstract class AppDatabase : RoomDatabase() {
.addMigrations(MIGRATION_12_13)
.addMigrations(MIGRATION_13_14)
.addMigrations(MIGRATION_14_15)
.addMigrations(MIGRATION_15_16)
.build()
instance.openHelper.writableDatabase.execSQL("VACUUM")
@@ -1,13 +1,11 @@
package com.greenart7c3.nostrsigner.database
import android.util.Log
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import com.greenart7c3.nostrsigner.Amber
import kotlinx.coroutines.flow.Flow
@Dao
@@ -130,50 +128,14 @@ interface ApplicationDao {
@Transaction
suspend fun delete(key: String)
@Insert(onConflict = OnConflictStrategy.REPLACE)
@Transaction
suspend fun innerAddHistory(entity: HistoryEntity)
@Insert(onConflict = OnConflictStrategy.IGNORE)
@Transaction
suspend fun addHistory(entity: HistoryEntity) {
try {
innerAddHistory(entity)
updateLastUsed(entity.pkKey, entity.time)
} catch (e: Exception) {
Log.e(Amber.TAG, "Error adding history", e)
}
}
@Query("UPDATE application SET lastUsed = :time where `key` = :key")
@Transaction
suspend fun updateLastUsed(key: String, time: Long)
@Query("SELECT * FROM history2 where pkKey = :pk ORDER BY time DESC")
fun getAllHistory(pk: String): Flow<List<HistoryEntity>>
@Query("SELECT * FROM history2 ORDER BY time DESC")
fun getAllHistory(): Flow<List<HistoryEntity>>
@Query("DELETE FROM history2 where pkKey = :pk")
suspend fun deleteHistory(pk: String)
@Delete
@Transaction
suspend fun deletePermission(permission: ApplicationPermissionsEntity)
@Query("SELECT COUNT(*) FROM history2 WHERE time < :time")
@Transaction
suspend fun countOldHistory(time: Long): Long
@Query("SELECT * FROM history2 WHERE time < :time LIMIT 100")
@Transaction
suspend fun getOldHistory(time: Long): List<HistoryEntity>
@Delete
@Transaction
suspend fun deleteHistory(historyEntity: HistoryEntity)
@Query("DELETE FROM application WHERE deleteAfter < :time AND deleteAfter > 0")
@Transaction
suspend fun deleteOldApplications(time: Long): Int
@@ -0,0 +1,52 @@
package com.greenart7c3.nostrsigner.database
import android.util.Log
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import com.greenart7c3.nostrsigner.Amber
import kotlinx.coroutines.flow.Flow
@Dao
interface HistoryDao {
@Query("SELECT * FROM history where pkKey = :pk ORDER BY time DESC")
fun getAllHistory(pk: String): Flow<List<HistoryEntity>>
@Query("SELECT * FROM history ORDER BY time DESC")
fun getAllHistory(): Flow<List<HistoryEntity>>
@Query("DELETE FROM history where pkKey = :pk")
suspend fun deleteHistory(pk: String)
@Query("SELECT COUNT(*) FROM history WHERE time < :time")
@Transaction
suspend fun countOldHistory(time: Long): Long
@Query("SELECT * FROM history WHERE time < :time LIMIT 100")
@Transaction
suspend fun getOldHistory(time: Long): List<HistoryEntity>
@Delete
@Transaction
suspend fun deleteHistory(historyEntity: HistoryEntity)
@Insert(onConflict = OnConflictStrategy.REPLACE)
@Transaction
suspend fun innerAddHistory(entity: HistoryEntity)
@Insert(onConflict = OnConflictStrategy.IGNORE)
@Transaction
suspend fun addHistory(entity: HistoryEntity, npub: String?) {
try {
innerAddHistory(entity)
npub?.let {
Amber.instance.getDatabase(npub).applicationDao().updateLastUsed(entity.pkKey, entity.time)
}
} catch (e: Exception) {
Log.e(Amber.TAG, "Error adding history", e)
}
}
}
@@ -0,0 +1,44 @@
package com.greenart7c3.nostrsigner.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import java.util.concurrent.Executors
@Database(
entities = [
HistoryEntity::class,
],
version = 1,
)
@TypeConverters(Converters::class)
abstract class HistoryDatabase : RoomDatabase() {
abstract fun dao(): HistoryDao
companion object {
fun getDatabase(
context: Context,
npub: String,
): HistoryDatabase {
return synchronized(this) {
val executor = Executors.newCachedThreadPool()
val transactionExecutor = Executors.newCachedThreadPool()
val instance =
Room.databaseBuilder(
context,
HistoryDatabase::class.java,
"history_db_$npub",
)
.setQueryExecutor(executor)
.setTransactionExecutor(transactionExecutor)
.build()
instance.openHelper.writableDatabase.execSQL("VACUUM")
instance
}
}
}
}
@@ -5,15 +5,15 @@ import androidx.room.Index
import androidx.room.PrimaryKey
@Entity(
tableName = "history2",
tableName = "history",
indices = [
Index(
value = ["pkKey"],
name = "history_by_pk_key2",
name = "history_by_pk_key",
),
Index(
value = ["id"],
name = "history_by_id2",
name = "history_by_id",
),
Index(
value = ["time"],
@@ -239,11 +239,12 @@ object BunkerRequestUtils {
onLoading(true)
Amber.instance.applicationIOScope.launch {
val database = Amber.instance.getDatabase(account.npub)
val historyDatabase = Amber.instance.getHistoryDatabase(account.npub)
val defaultRelays = Amber.instance.settings.defaultRelays
if (oldKey.isNotBlank()) {
database.applicationDao().delete(oldKey)
database.applicationDao().deleteHistory(oldKey)
historyDatabase.dao().deleteHistory(oldKey)
}
var savedApplication = database.applicationDao().getByKey(key)
@@ -350,7 +351,7 @@ object BunkerRequestUtils {
// assume that everything worked and try to revert it if it fails
EventNotificationConsumer(context).notificationManager().cancelAll()
database.applicationDao().insertApplicationWithPermissions(application)
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
key,
@@ -359,6 +360,7 @@ object BunkerRequestUtils {
TimeUtils.now(),
true,
),
account.npub,
)
if (didChangeRelays) {
Amber.instance.checkForNewRelaysAndUpdateAllFilters(true)
@@ -448,7 +450,7 @@ object BunkerRequestUtils {
if (bunkerRequest.request !is BunkerRequestConnect) {
Amber.instance.getDatabase(account.npub).applicationDao().insertApplicationWithPermissions(application)
Amber.instance.getDatabase(account.npub).applicationDao().addHistory(
Amber.instance.getHistoryDatabase(account.npub).dao().addHistory(
HistoryEntity(
0,
key,
@@ -457,6 +459,7 @@ object BunkerRequestUtils {
TimeUtils.now(),
false,
),
account.npub,
)
}
@@ -15,43 +15,42 @@ class ClearLogsWorker(appContext: Context, workerParams: WorkerParameters) :
override suspend fun doWork(): Result {
LocalPreferences.allSavedAccounts(Amber.instance).forEach {
Amber.instance.getDatabase(it.npub).let { database ->
try {
val oneWeek = System.currentTimeMillis() - (ONE_WEEK * 1000L)
val oneWeekAgo = TimeUtils.oneWeekAgo()
val countHistory = database.applicationDao().countOldHistory(oneWeekAgo)
Log.d(Amber.TAG, "Deleting $countHistory old history entries")
if (countHistory > 0) {
var logs = database.applicationDao().getOldHistory(oneWeekAgo)
var count = 0
while (logs.isNotEmpty()) {
count++
logs.forEach { history ->
database.applicationDao().deleteHistory(history)
}
logs = database.applicationDao().getOldHistory(oneWeekAgo)
try {
val oneWeek = System.currentTimeMillis() - (ONE_WEEK * 1000L)
val oneWeekAgo = TimeUtils.oneWeekAgo()
val historyDatabase = Amber.instance.getHistoryDatabase(it.npub)
val countHistory = historyDatabase.dao().countOldHistory(oneWeekAgo)
Log.d(Amber.TAG, "Deleting $countHistory old history entries")
if (countHistory > 0) {
var logs = historyDatabase.dao().getOldHistory(oneWeekAgo)
var count = 0
while (logs.isNotEmpty()) {
count++
logs.forEach { history ->
historyDatabase.dao().deleteHistory(history)
}
logs = historyDatabase.dao().getOldHistory(oneWeekAgo)
}
val logDatabase = Amber.instance.getLogDatabase(it.npub)
val countLog = logDatabase.logDao().countOldLog(oneWeek)
Log.d(Amber.TAG, "Deleting $countLog old log entries from ${com.greenart7c3.nostrsigner.models.TimeUtils.formatLongToCustomDateTimeWithSeconds(oneWeek)}")
if (countLog > 0) {
var logs = logDatabase.logDao().getOldLog(oneWeek)
var count = 0
while (logs.isNotEmpty()) {
count++
logs.forEach { history ->
Log.d(Amber.TAG, "Deleting log entry ${com.greenart7c3.nostrsigner.models.TimeUtils.formatLongToCustomDateTimeWithSeconds(history.time)}")
logDatabase.logDao().deleteLog(history)
}
logs = logDatabase.logDao().getOldLog(oneWeek)
}
}
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.e(Amber.TAG, "Error deleting old log entries", e)
}
val logDatabase = Amber.instance.getLogDatabase(it.npub)
val countLog = logDatabase.logDao().countOldLog(oneWeek)
Log.d(Amber.TAG, "Deleting $countLog old log entries from ${com.greenart7c3.nostrsigner.models.TimeUtils.formatLongToCustomDateTimeWithSeconds(oneWeek)}")
if (countLog > 0) {
var logs = logDatabase.logDao().getOldLog(oneWeek)
var count = 0
while (logs.isNotEmpty()) {
count++
logs.forEach { history ->
Log.d(Amber.TAG, "Deleting log entry ${com.greenart7c3.nostrsigner.models.TimeUtils.formatLongToCustomDateTimeWithSeconds(history.time)}")
logDatabase.logDao().deleteLog(history)
}
logs = logDatabase.logDao().getOldLog(oneWeek)
}
}
} catch (e: Exception) {
if (e is CancellationException) throw e
Log.e(Amber.TAG, "Error deleting old log entries", e)
}
}
return Result.success()
@@ -150,6 +150,7 @@ class EventNotificationConsumer(private val applicationContext: Context) {
val database = Amber.instance.getDatabase(acc.npub)
val dao = database.applicationDao()
val logDao = Amber.instance.getLogDatabase(acc.npub).logDao()
val historyDao = Amber.instance.getHistoryDatabase(acc.npub).dao()
val notification = Amber.instance.notificationCache[event.id]
if (notification != null) return
@@ -237,7 +238,7 @@ class EventNotificationConsumer(private val applicationContext: Context) {
val permission = dao.getByKey(event.pubKey)
if (permission != null && ((permission.application.secret != permission.application.key && permission.application.useSecret) || permission.application.isConnected) && type == SignerType.CONNECT) {
Amber.instance.applicationIOScope.launch {
dao
historyDao
.addHistory(
HistoryEntity(
0,
@@ -247,6 +248,7 @@ class EventNotificationConsumer(private val applicationContext: Context) {
TimeUtils.now(),
true,
),
acc.npub,
)
}
BunkerRequestUtils.sendBunkerResponse(
@@ -567,6 +567,7 @@ object IntentUtils {
onLoading(true)
Amber.instance.applicationIOScope.launch {
val database = Amber.instance.getDatabase(account.npub)
val historyDatabase = Amber.instance.getHistoryDatabase(account.npub)
val defaultRelays = Amber.instance.settings.defaultRelays
val savedApplication = database.applicationDao().getByKey(key)
val relays = savedApplication?.application?.relays?.ifEmpty { defaultRelays } ?: defaultRelays
@@ -637,7 +638,7 @@ object IntentUtils {
if (packageName != null) {
database.applicationDao().insertApplicationWithPermissions(application)
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
key,
@@ -646,6 +647,7 @@ object IntentUtils {
TimeUtils.now(),
true,
),
account.npub,
)
val intent = Intent()
@@ -777,7 +779,7 @@ object IntentUtils {
}
Amber.instance.getDatabase(account.npub).applicationDao().insertApplicationWithPermissions(application)
Amber.instance.getDatabase(account.npub).applicationDao().addHistory(
Amber.instance.getHistoryDatabase(account.npub).dao().addHistory(
HistoryEntity(
0,
key,
@@ -786,6 +788,7 @@ object IntentUtils {
TimeUtils.now(),
false,
),
account.npub,
)
val activity = Amber.instance.getMainActivity()
@@ -61,8 +61,8 @@ fun ActivitiesScreen(
topPadding: Dp,
account: Account,
) {
val database = Amber.instance.getDatabase(account.npub)
val activities = database.applicationDao().getAllHistory().collectAsStateWithLifecycle(emptyList())
val database = Amber.instance.getHistoryDatabase(account.npub)
val activities = database.dao().getAllHistory().collectAsStateWithLifecycle(emptyList())
val context = LocalContext.current
// State for the search query
var searchQuery by remember { mutableStateOf("") }
@@ -133,7 +133,7 @@ fun ActivitiesScreen(
ApplicationName(
key = activity.pkKey,
accepted = activity.accepted,
database = database,
database = Amber.instance.getDatabase(account.npub),
account = account,
)
@@ -318,7 +318,7 @@ fun EditConfigurationScreen(
application?.let {
scope.launch(Dispatchers.IO) {
Amber.instance.getDatabase(account.npub).applicationDao().delete(it.application)
Amber.instance.getDatabase(account.npub).applicationDao().deleteHistory(it.application.key)
Amber.instance.getHistoryDatabase(account.npub).dao().deleteHistory(it.application.key)
scope.launch(Dispatchers.Main) {
navController.navigate(Route.Applications.route) {
@@ -270,55 +270,54 @@ fun SettingsScreen(
Amber.instance.applicationIOScope.launch {
isLoading = true
LocalPreferences.allSavedAccounts(Amber.instance).forEach {
Amber.instance.getDatabase(it.npub).let { database ->
try {
status = context.getString(R.string.deleting_old_log_entries_from, it.npub)
val oneWeek = System.currentTimeMillis() - (ONE_WEEK * 1000L)
val oneWeekAgo = TimeUtils.oneWeekAgo()
val countHistory = database.applicationDao().countOldHistory(oneWeekAgo)
if (countHistory > 0) {
status = context.getString(R.string.deleting_old_history_entries, countHistory)
var logs = database.applicationDao().getOldHistory(oneWeekAgo)
var count = 0
while (logs.isNotEmpty()) {
count++
status = context.getString(R.string.deleting_old_history_entries_2, 100 * count, countHistory)
logs.forEach { history ->
database.applicationDao().deleteHistory(history)
}
logs = database.applicationDao().getOldHistory(oneWeekAgo)
try {
status = context.getString(R.string.deleting_old_log_entries_from, it.npub)
val oneWeek = System.currentTimeMillis() - (ONE_WEEK * 1000L)
val oneWeekAgo = TimeUtils.oneWeekAgo()
val historyDatabase = Amber.instance.getHistoryDatabase(it.npub)
val countHistory = historyDatabase.dao().countOldHistory(oneWeekAgo)
if (countHistory > 0) {
status = context.getString(R.string.deleting_old_history_entries, countHistory)
var logs = historyDatabase.dao().getOldHistory(oneWeekAgo)
var count = 0
while (logs.isNotEmpty()) {
count++
status = context.getString(R.string.deleting_old_history_entries_2, 100 * count, countHistory)
logs.forEach { history ->
historyDatabase.dao().deleteHistory(history)
}
logs = historyDatabase.dao().getOldHistory(oneWeekAgo)
}
val logDatabase = Amber.instance.getLogDatabase(it.npub)
val countLog = logDatabase.logDao().countOldLog(oneWeek)
if (countLog > 0) {
status = context.getString(R.string.deleting_old_log_entries, countLog)
var logs = logDatabase.logDao().getOldLog(oneWeek)
var count = 0
while (logs.isNotEmpty()) {
count++
status = context.getString(R.string.deleting_old_log_entries_2, 100 * count, countLog)
logs.forEach { history ->
logDatabase.logDao().deleteLog(history)
}
logs = logDatabase.logDao().getOldLog(oneWeek)
}
}
val dbFile = context.getDatabasePath("amber_db_${account.npub}")
val df = DecimalFormat("#.###")
sizeInMBFormatted = df.format(dbFile.length() / (1024.0 * 1024.0))
status = ""
isLoading = false
} catch (e: Exception) {
isLoading = false
if (e is CancellationException) throw e
Log.e(Amber.TAG, "Error deleting old log entries", e)
val dbFile = context.getDatabasePath("amber_db_${account.npub}")
val df = DecimalFormat("#.###")
sizeInMBFormatted = df.format(dbFile.length() / (1024.0 * 1024.0))
status = ""
}
val logDatabase = Amber.instance.getLogDatabase(it.npub)
val countLog = logDatabase.logDao().countOldLog(oneWeek)
if (countLog > 0) {
status = context.getString(R.string.deleting_old_log_entries, countLog)
var logs = logDatabase.logDao().getOldLog(oneWeek)
var count = 0
while (logs.isNotEmpty()) {
count++
status = context.getString(R.string.deleting_old_log_entries_2, 100 * count, countLog)
logs.forEach { history ->
logDatabase.logDao().deleteLog(history)
}
logs = logDatabase.logDao().getOldLog(oneWeek)
}
}
val dbFile = context.getDatabasePath("amber_db_${account.npub}")
val df = DecimalFormat("#.###")
sizeInMBFormatted = df.format(dbFile.length() / (1024.0 * 1024.0))
status = ""
isLoading = false
} catch (e: Exception) {
isLoading = false
if (e is CancellationException) throw e
Log.e(Amber.TAG, "Error deleting old log entries", e)
val dbFile = context.getDatabasePath("amber_db_${account.npub}")
val df = DecimalFormat("#.###")
sizeInMBFormatted = df.format(dbFile.length() / (1024.0 * 1024.0))
status = ""
}
}
@@ -56,7 +56,7 @@ fun ActivityScreen(
account: Account,
key: String,
) {
val activities = Amber.instance.getDatabase(account.npub).applicationDao().getAllHistory(key).collectAsStateWithLifecycle(emptyList())
val activities = Amber.instance.getHistoryDatabase(account.npub).dao().getAllHistory(key).collectAsStateWithLifecycle(emptyList())
val context = LocalContext.current
// State for the search query
var searchQuery by remember { mutableStateOf("") }
@@ -224,6 +224,7 @@ fun IntentMultiEventHomeScreen(
val localKey = packageName ?: continue
val database = Amber.instance.getDatabase(thisAccount.npub)
val historyDatabase = Amber.instance.getHistoryDatabase(thisAccount.npub)
val savedApplication = database.applicationDao().getByKey(localKey)
val application =
@@ -268,7 +269,7 @@ fun IntentMultiEventHomeScreen(
database.applicationDao().insertApplicationWithPermissions(application)
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
localKey,
@@ -277,6 +278,7 @@ fun IntentMultiEventHomeScreen(
TimeUtils.now(),
intentData.checked.value,
),
thisAccount.npub,
)
if (intentData.checked.value) {
@@ -320,7 +322,7 @@ fun IntentMultiEventHomeScreen(
}
database.applicationDao().insertApplicationWithPermissions(application)
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
localKey,
@@ -329,6 +331,7 @@ fun IntentMultiEventHomeScreen(
TimeUtils.now(),
intentData.checked.value,
),
thisAccount.npub,
)
val signedMessage = signString(intentData.data, thisAccount.signer.keyPair.privKey!!).toHexKey()
@@ -358,7 +361,7 @@ fun IntentMultiEventHomeScreen(
database.applicationDao().insertApplicationWithPermissions(application)
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
localKey,
@@ -367,6 +370,7 @@ fun IntentMultiEventHomeScreen(
TimeUtils.now(),
intentData.checked.value,
),
thisAccount.npub,
)
val signature = intentData.encryptedData ?: continue
@@ -592,6 +596,7 @@ fun BunkerMultiEventHomeScreen(
val localKey = request.localKey
val database = Amber.instance.getDatabase(thisAccount.npub)
val historyDatabase = Amber.instance.getHistoryDatabase(thisAccount.npub)
val savedApplication = database.applicationDao().getByKey(localKey)
val secret = if (request.request is BunkerRequestConnect) {
@@ -642,7 +647,7 @@ fun BunkerMultiEventHomeScreen(
database.applicationDao().insertApplicationWithPermissions(application)
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
entity = HistoryEntity(
id = 0,
pkKey = localKey,
@@ -651,6 +656,7 @@ fun BunkerMultiEventHomeScreen(
time = TimeUtils.now(),
accepted = request.checked.value,
),
thisAccount.npub,
)
val localBunkerRequest = request.copy()
@@ -694,7 +700,7 @@ fun BunkerMultiEventHomeScreen(
}
database.applicationDao().insertApplicationWithPermissions(application)
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
localKey,
@@ -703,6 +709,7 @@ fun BunkerMultiEventHomeScreen(
TimeUtils.now(),
request.checked.value,
),
thisAccount.npub,
)
val signedMessage = signString(request.request.params.first(), thisAccount.signer.keyPair.privKey!!).toHexKey()
@@ -737,7 +744,7 @@ fun BunkerMultiEventHomeScreen(
if (savedApplication == null) {
database.applicationDao().insertApplicationWithPermissions(application)
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
localKey,
@@ -746,6 +753,7 @@ fun BunkerMultiEventHomeScreen(
TimeUtils.now(),
request.checked.value,
),
thisAccount.npub,
)
val localBunkerRequest = request.copy()
@@ -791,7 +799,7 @@ fun BunkerMultiEventHomeScreen(
database.applicationDao().insertApplicationWithPermissions(application)
database.applicationDao().addHistory(
historyDatabase.dao().addHistory(
HistoryEntity(
0,
localKey,
@@ -800,6 +808,7 @@ fun BunkerMultiEventHomeScreen(
TimeUtils.now(),
request.checked.value,
),
thisAccount.npub,
)
val signature = request.encryptDecryptResponse ?: continue