From 6a0fdddf6fa6636f0fe1b5a7cd31fd49b17b3dae Mon Sep 17 00:00:00 2001 From: koalasat Date: Wed, 23 Oct 2024 16:42:46 +0200 Subject: [PATCH] v0.0.1 --- .kotlin/errors/errors-1729681436417.log | 87 +++++++++ .kotlin/errors/errors-1729681461963.log | 87 +++++++++ README.md | 1 + .../5.json | 52 +++++- app/src/main/AndroidManifest.xml | 10 +- .../koalasat/pokey/database/AppDatabase.kt | 3 +- .../koalasat/pokey/database/ApplicationDao.kt | 13 ++ .../koalasat/pokey/database/RelayEntity.kt | 22 +++ .../pokey/service/NotificationsService.kt | 176 +++++++++++++----- app/src/main/res/values/strings.xml | 5 +- 10 files changed, 403 insertions(+), 53 deletions(-) create mode 100644 .kotlin/errors/errors-1729681436417.log create mode 100644 .kotlin/errors/errors-1729681461963.log create mode 100644 app/src/main/java/com/koalasat/pokey/database/RelayEntity.kt diff --git a/.kotlin/errors/errors-1729681436417.log b/.kotlin/errors/errors-1729681436417.log new file mode 100644 index 0000000..0a32741 --- /dev/null +++ b/.kotlin/errors/errors-1729681436417.log @@ -0,0 +1,87 @@ +kotlin version: 2.0.20 +error message: java.lang.IllegalStateException: Storage for [/home/koala/Workspaces/pokey/app/build/kspCaches/debug/symbolLookups/id-to-file.tab] is already registered + at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410) + at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.(PagedFileStorage.java:72) + at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.(ResizeableMappedFile.java:55) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.(PersistentBTreeEnumerator.java:128) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.(PersistentMapImpl.java:165) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.(PersistentMapImpl.java:140) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.(PersistentHashMap.java:45) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.(PersistentHashMap.java:71) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:60) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:57) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:78) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.set(PersistentStorage.kt:94) + at org.jetbrains.kotlin.incremental.LookupStorage.addFileIfNeeded(LookupStorage.kt:165) + at org.jetbrains.kotlin.incremental.LookupStorage.addAll$lambda$4(LookupStorage.kt:117) + at org.jetbrains.kotlin.utils.CollectionsKt.keysToMap(collections.kt:117) + at org.jetbrains.kotlin.incremental.LookupStorage.addAll(LookupStorage.kt:117) + at org.jetbrains.kotlin.incremental.BuildUtilKt.update(buildUtil.kt:134) + at com.google.devtools.ksp.LookupStorageWrapperImpl.update(IncrementalContext.kt:231) + at com.google.devtools.ksp.common.IncrementalContextBase.updateLookupCache(IncrementalContextBase.kt:133) + at com.google.devtools.ksp.common.IncrementalContextBase.updateCaches(IncrementalContextBase.kt:364) + at com.google.devtools.ksp.common.IncrementalContextBase.updateCachesAndOutputs(IncrementalContextBase.kt:470) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.doAnalysis(KotlinSymbolProcessingExtension.kt:362) + at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:112) + at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:75) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze$lambda$12(KotlinToJVMBytecodeCompiler.kt:373) + at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:112) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:364) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.repeatAnalysisIfNeeded(KotlinToJVMBytecodeCompiler.kt:282) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.runFrontendAndGenerateIrUsingClassicFrontend(KotlinToJVMBytecodeCompiler.kt:195) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:106) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:170) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1555) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source) + at java.base/java.lang.reflect.Method.invoke(Unknown Source) + at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) + at java.base/java.lang.Thread.run(Unknown Source) + Suppressed: java.lang.Exception: Storage[/home/koala/Workspaces/pokey/app/build/kspCaches/debug/symbolLookups/id-to-file.tab] registration stack trace + at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437) + at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.(PagedFileStorage.java:72) + at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.(ResizeableMappedFile.java:55) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.(PersistentBTreeEnumerator.java:128) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.(PersistentMapImpl.java:165) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.(PersistentMapImpl.java:140) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.(PersistentHashMap.java:45) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.(PersistentHashMap.java:71) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:60) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageIfExists(LazyStorage.kt:51) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.get(LazyStorage.kt:74) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.get(PersistentStorage.kt:90) + at org.jetbrains.kotlin.incremental.LookupStorage.get(LookupStorage.kt:99) + at com.google.devtools.ksp.LookupStorageWrapperImpl.get(IncrementalContext.kt:224) + at com.google.devtools.ksp.common.IncrementalContextBase.calcDirtyFiles(IncrementalContextBase.kt:234) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$2.invoke(KotlinSymbolProcessingExtension.kt:196) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$2.invoke(KotlinSymbolProcessingExtension.kt:189) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.handleException(KotlinSymbolProcessingExtension.kt:414) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.doAnalysis(KotlinSymbolProcessingExtension.kt:189) + at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:112) + at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:75) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze$lambda$12(KotlinToJVMBytecodeCompiler.kt:373) + at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:112) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:364) + ... 23 more + + diff --git a/.kotlin/errors/errors-1729681461963.log b/.kotlin/errors/errors-1729681461963.log new file mode 100644 index 0000000..0a32741 --- /dev/null +++ b/.kotlin/errors/errors-1729681461963.log @@ -0,0 +1,87 @@ +kotlin version: 2.0.20 +error message: java.lang.IllegalStateException: Storage for [/home/koala/Workspaces/pokey/app/build/kspCaches/debug/symbolLookups/id-to-file.tab] is already registered + at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:410) + at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.(PagedFileStorage.java:72) + at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.(ResizeableMappedFile.java:55) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.(PersistentBTreeEnumerator.java:128) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.(PersistentMapImpl.java:165) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.(PersistentMapImpl.java:140) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.(PersistentHashMap.java:45) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.(PersistentHashMap.java:71) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:60) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageOrCreateNew(LazyStorage.kt:57) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.set(LazyStorage.kt:78) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.set(PersistentStorage.kt:94) + at org.jetbrains.kotlin.incremental.LookupStorage.addFileIfNeeded(LookupStorage.kt:165) + at org.jetbrains.kotlin.incremental.LookupStorage.addAll$lambda$4(LookupStorage.kt:117) + at org.jetbrains.kotlin.utils.CollectionsKt.keysToMap(collections.kt:117) + at org.jetbrains.kotlin.incremental.LookupStorage.addAll(LookupStorage.kt:117) + at org.jetbrains.kotlin.incremental.BuildUtilKt.update(buildUtil.kt:134) + at com.google.devtools.ksp.LookupStorageWrapperImpl.update(IncrementalContext.kt:231) + at com.google.devtools.ksp.common.IncrementalContextBase.updateLookupCache(IncrementalContextBase.kt:133) + at com.google.devtools.ksp.common.IncrementalContextBase.updateCaches(IncrementalContextBase.kt:364) + at com.google.devtools.ksp.common.IncrementalContextBase.updateCachesAndOutputs(IncrementalContextBase.kt:470) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.doAnalysis(KotlinSymbolProcessingExtension.kt:362) + at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:112) + at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:75) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze$lambda$12(KotlinToJVMBytecodeCompiler.kt:373) + at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:112) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:364) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.repeatAnalysisIfNeeded(KotlinToJVMBytecodeCompiler.kt:282) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.runFrontendAndGenerateIrUsingClassicFrontend(KotlinToJVMBytecodeCompiler.kt:195) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:106) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:170) + at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:43) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:103) + at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:49) + at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101) + at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1555) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source) + at java.base/java.lang.reflect.Method.invoke(Unknown Source) + at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source) + at java.base/java.security.AccessController.doPrivileged(Unknown Source) + at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) + at java.base/java.lang.Thread.run(Unknown Source) + Suppressed: java.lang.Exception: Storage[/home/koala/Workspaces/pokey/app/build/kspCaches/debug/symbolLookups/id-to-file.tab] registration stack trace + at org.jetbrains.kotlin.com.intellij.util.io.FilePageCache.registerPagedFileStorage(FilePageCache.java:437) + at org.jetbrains.kotlin.com.intellij.util.io.PagedFileStorage.(PagedFileStorage.java:72) + at org.jetbrains.kotlin.com.intellij.util.io.ResizeableMappedFile.(ResizeableMappedFile.java:55) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentBTreeEnumerator.(PersistentBTreeEnumerator.java:128) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumerator.createDefaultEnumerator(PersistentEnumerator.java:52) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.(PersistentMapImpl.java:165) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapImpl.(PersistentMapImpl.java:140) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.buildImplementation(PersistentMapBuilder.java:88) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentMapBuilder.build(PersistentMapBuilder.java:71) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.(PersistentHashMap.java:45) + at org.jetbrains.kotlin.com.intellij.util.io.PersistentHashMap.(PersistentHashMap.java:71) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.createMap(LazyStorage.kt:60) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.getStorageIfExists(LazyStorage.kt:51) + at org.jetbrains.kotlin.incremental.storage.LazyStorage.get(LazyStorage.kt:74) + at org.jetbrains.kotlin.incremental.storage.PersistentStorageWrapper.get(PersistentStorage.kt:90) + at org.jetbrains.kotlin.incremental.LookupStorage.get(LookupStorage.kt:99) + at com.google.devtools.ksp.LookupStorageWrapperImpl.get(IncrementalContext.kt:224) + at com.google.devtools.ksp.common.IncrementalContextBase.calcDirtyFiles(IncrementalContextBase.kt:234) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$2.invoke(KotlinSymbolProcessingExtension.kt:196) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$2.invoke(KotlinSymbolProcessingExtension.kt:189) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.handleException(KotlinSymbolProcessingExtension.kt:414) + at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.doAnalysis(KotlinSymbolProcessingExtension.kt:189) + at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:112) + at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:75) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze$lambda$12(KotlinToJVMBytecodeCompiler.kt:373) + at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:112) + at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:364) + ... 23 more + + diff --git a/README.md b/README.md index 326877e..7d2ea35 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ What is Nostr: https://www.nostr.how - [ ] Finish POC - [ ] Connect to signer apps like Amber - [ ] Broadcast to other apps +- [ ] Auth to relays - [ ] Use built-in Tor engine - [ ] Multi-account - [ ] InBox Relays management diff --git a/app/schemas/com.koalasat.pokey.database.AppDatabase/5.json b/app/schemas/com.koalasat.pokey.database.AppDatabase/5.json index f2e1d1b..7da7883 100644 --- a/app/schemas/com.koalasat.pokey.database.AppDatabase/5.json +++ b/app/schemas/com.koalasat.pokey.database.AppDatabase/5.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 5, - "identityHash": "304dc2730bab233084f32790628da8ae", + "identityHash": "ca5e9f242001c547b32cdaadcc271c58", "entities": [ { "tableName": "notification", @@ -45,12 +45,60 @@ } ], "foreignKeys": [] + }, + { + "tableName": "relay", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `kind` INTEGER NOT NULL, `createdAt` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "kind", + "columnName": "kind", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "createdAt", + "columnName": "createdAt", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "relay_by_url", + "unique": false, + "columnNames": [ + "url" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `relay_by_url` ON `${TABLE_NAME}` (`url`)" + } + ], + "foreignKeys": [] } ], "views": [], "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, '304dc2730bab233084f32790628da8ae')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ca5e9f242001c547b32cdaadcc271c58')" ] } } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 20c7284..2933935 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,6 +9,13 @@ + + + + + + + + > + + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertRelay(notificationEntity: RelayEntity): Long? + + @Query("DELETE FROM relay where kind = :kind") + fun deleteRelaysByKind(kind: Int): Int + + @Query("SELECT MAX(createdAt) FROM relay WHERE kind = :kind") + fun getLatestRelaysByKind(kind: Int): Long? } diff --git a/app/src/main/java/com/koalasat/pokey/database/RelayEntity.kt b/app/src/main/java/com/koalasat/pokey/database/RelayEntity.kt new file mode 100644 index 0000000..2d12492 --- /dev/null +++ b/app/src/main/java/com/koalasat/pokey/database/RelayEntity.kt @@ -0,0 +1,22 @@ +package com.koalasat.pokey.database + +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity( + tableName = "relay", + indices = [ + Index( + value = ["url"], + name = "relay_by_url", + ) + ], +) +data class RelayEntity( + @PrimaryKey(autoGenerate = true) + val id: Int, + val url: String, + val kind: Int, + val createdAt: Long +) diff --git a/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt b/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt index 8da7023..8915027 100644 --- a/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt +++ b/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt @@ -2,33 +2,31 @@ package com.koalasat.pokey.service import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager +import android.app.PendingIntent import android.app.Service -import android.content.Context import android.content.Intent -import android.content.SharedPreferences import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities +import android.net.Uri import android.os.IBinder import android.util.Log import androidx.core.app.NotificationCompat -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import com.koalasat.pokey.Connectivity -import com.koalasat.pokey.Pokey import com.koalasat.pokey.R import com.koalasat.pokey.database.AppDatabase import com.koalasat.pokey.database.NotificationEntity +import com.koalasat.pokey.database.RelayEntity import com.koalasat.pokey.models.EncryptedStorage.preferences import com.koalasat.pokey.models.PrefKeys import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES import com.vitorpamplona.ammolite.relays.Client +import com.vitorpamplona.ammolite.relays.EVENT_FINDER_TYPES import com.vitorpamplona.ammolite.relays.Relay import com.vitorpamplona.ammolite.relays.RelayPool import com.vitorpamplona.ammolite.relays.TypedFilter import com.vitorpamplona.ammolite.relays.filters.EOSETime import com.vitorpamplona.ammolite.relays.filters.SincePerRelayFilter -import com.vitorpamplona.ammolite.service.HttpClientManager import com.vitorpamplona.quartz.encoders.Nip19Bech32 import com.vitorpamplona.quartz.encoders.Nip19Bech32.uriToRoute import com.vitorpamplona.quartz.events.Event @@ -46,9 +44,13 @@ class NotificationsService : Service() { private var channelRelaysId = "RelaysConnections" private var channelNotificationsId = "Notifications" - private var defaultRelayUrls = arrayOf( - "wss://relay.damus.io", "wss://offchain.pub", "wss://relay.snort.social", "wss://nos.lol", "wss://nostr.wine" + private var subscriptionNotificationId = "subscriptionNotificationId" + private var subscriptionInboxId = "inboxRelays" + + private var defaultRelayUrls = listOf( + "wss://relay.damus.io", "wss://offchain.pub", "wss://relay.snort.social", "wss://nos.lol", "wss://relay.nsec.app", "wss://relay.0xchat.com" ) + private var useDefaultRelays = false private val timer = Timer() private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) @@ -60,11 +62,11 @@ class NotificationsService : Service() { } override fun onSend(relay: Relay, msg: String, success: Boolean) { - Log.d("Pokey", "Relay send: ${relay.url}") + Log.d("Pokey", "Relay send: ${relay.url} - $msg - Success $success") } override fun onBeforeSend(relay: Relay, event: EventInterface) { - Log.d("Pokey", "Relay Before Send: ${relay.url} - $event") + Log.d("Pokey", "Relay Before Send: ${relay.url} - ${event.toJson()}") } override fun onError(error: Error, subscriptionId: String, relay: Relay) { @@ -77,9 +79,12 @@ class NotificationsService : Service() { relay: Relay, afterEOSE: Boolean, ) { - Log.d("Pokey", "Relay Event: ${relay.url} - ${event.id}") - - displayNoteNotification(event) + Log.d("Pokey", "Relay Event: ${relay.url} - $subscriptionId - ${event.toJson()}") + if (subscriptionId == subscriptionNotificationId) { + createNoteNotification(event) + } else if (subscriptionId == subscriptionInboxId) { + manageInboxRelays(event) + } } override fun onNotify(relay: Relay, description: String) { @@ -182,28 +187,21 @@ class NotificationsService : Service() { val hexKey = getHexKey() if (hexKey.isEmpty()) return - if (!Client.isSubscribed(clientListener)) Client.subscribe(clientListener) - - defaultRelayUrls.forEach { - if (RelayPool.getRelays(it).isEmpty()) { - RelayPool.addRelay( - Relay( - it, - read = true, - write = false, - forceProxy = false, - activeTypes = COMMON_FEED_TYPES - ), - ) - } - } - CoroutineScope(Dispatchers.IO).launch { + if (!Client.isSubscribed(clientListener)) Client.subscribe(clientListener) + val dao = AppDatabase.getDatabase(this@NotificationsService, getHexKey()).applicationDao() var latestNotification = dao.getLatestNotification() if (latestNotification == null) latestNotification = Instant.now().toEpochMilli() / 1000 - Client.sendFilter("pushNotifications", listOf(TypedFilter( + var relays = dao.getRelays() + if (relays.isEmpty()){ + relays = defaultRelayUrls.map { RelayEntity(id=0, url = it, kind = 0, createdAt = 0) } + useDefaultRelays = true + } + connectRelays(relays) + + Client.sendFilter(subscriptionNotificationId, listOf(TypedFilter( types = COMMON_FEED_TYPES, filter = SincePerRelayFilter( kinds = listOf(1), @@ -211,6 +209,16 @@ class NotificationsService : Service() { since = RelayPool.getAll().associate { it.url to EOSETime(latestNotification) } ), ))) + Client.sendFilter( + subscriptionInboxId, + listOf(TypedFilter( + types = EVENT_FINDER_TYPES, + filter = SincePerRelayFilter( + kinds = listOf(10050, 10002), + authors = listOf(hexKey) + ), + )) + ) } } @@ -245,7 +253,7 @@ class NotificationsService : Service() { channelRelays.setSound(null, null) val channelNotification = NotificationChannel(channelNotificationsId, getString(R.string.notifications), NotificationManager.IMPORTANCE_HIGH) - val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager notificationManager.createNotificationChannel(channelRelays) notificationManager.createNotificationChannel(channelNotification) @@ -260,9 +268,28 @@ class NotificationsService : Service() { return notificationBuilder.build() } - private fun displayNoteNotification(event: Event) { - val pubKey = getHexKey() - if (event.pubKey == pubKey) return + private fun manageInboxRelays(event: Event) { + CoroutineScope(Dispatchers.IO).launch { + val dao = AppDatabase.getDatabase(this@NotificationsService, getHexKey()).applicationDao() + val lastCreatedRelayAt = dao.getLatestRelaysByKind(event.kind) + + if (lastCreatedRelayAt == null || lastCreatedRelayAt < event.createdAt ) { + dao.deleteRelaysByKind(event.kind) + val relays = event.tags + .filter { it.size > 1 && (it[0] == "relay" || it[0] == "r") } + .map { + val entity = RelayEntity(id = 0, url =it[1], kind = event.kind, createdAt = event.createdAt) + dao.insertRelay(entity) + entity + } + connectRelays(relays) + } + } + } + + private fun createNoteNotification(event: Event) { + val hexKey = getHexKey() + if (event.pubKey == hexKey || !event.taggedUsers().contains(hexKey)) return CoroutineScope(Dispatchers.IO).launch { val dao = AppDatabase.getDatabase(this@NotificationsService, getHexKey()).applicationDao() @@ -273,8 +300,9 @@ class NotificationsService : Service() { dao.insertNotification(NotificationEntity(0, event.id, event.createdAt)) - var title = getString(R.string.unknown) + var title = "" var text = "" + val pubKey = preferences().getString(PrefKeys.NOSTR_PUBKEY, "") if (event.kind == 1) { title = if (event.content().contains("nostr:${pubKey}")) @@ -284,23 +312,53 @@ class NotificationsService : Service() { else getString(R.string.new_reply) text = event.content().replace(Regex("nostr:[a-zA-Z0-9]+"), "") + } else if (event.kind == 4 || event.kind == 13){ + title = getString(R.string.new_private) + } else if (event.kind == 9735) { + title = getString(R.string.new_zap) + } else if (event.kind == 3) { + title = getString(R.string.new_follow) } - val notificationManager = - getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - val builder: NotificationCompat.Builder = - NotificationCompat.Builder( - applicationContext, - channelNotificationsId - ) - .setContentTitle(title) - .setContentText(text) - .setSmallIcon(R.drawable.ic_launcher_foreground) - .setPriority(NotificationCompat.PRIORITY_HIGH) - .setAutoCancel(true) + if (title.isEmpty()) return@launch + + displayNoteNotification(title, text, event) + } + } - notificationManager.notify(event.hashCode(), builder.build()) + private fun displayNoteNotification(title: String, text: String, event: Event) { + val deepLinkIntent = Intent(Intent.ACTION_VIEW).apply { + val nProfile = Nip19Bech32.parseComponents( + "npub", + event.pubKey, + null + ) + if (nProfile != null) { + data = Uri.parse("nostr:${nProfile.nip19raw}") + } } + val pendingIntent = PendingIntent.getActivity( + this@NotificationsService, + 0, + deepLinkIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + + val notificationManager = + getSystemService(NOTIFICATION_SERVICE) as NotificationManager + val builder: NotificationCompat.Builder = + NotificationCompat.Builder( + applicationContext, + channelNotificationsId + ) + .setContentTitle(title) + .setContentText(text) + .setSmallIcon(R.drawable.ic_launcher_foreground) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + + notificationManager.notify(event.hashCode(), builder.build()) } private fun getHexKey(): String { @@ -314,4 +372,26 @@ class NotificationsService : Service() { } return hexKey } + + private fun connectRelays(relays: List) { + Log.d("Pokey", relays.toString()) + if (useDefaultRelays) { + RelayPool.unloadRelays() + useDefaultRelays = false + } + relays.forEach { + if (RelayPool.getRelays(it.url).isEmpty()) { + Client.sendFilterOnlyIfDisconnected() + RelayPool.addRelay( + Relay( + it.url, + read = true, + write = false, + forceProxy = false, + activeTypes = COMMON_FEED_TYPES + ), + ) + } + } + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8ddf1ff..cd1b64c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,12 +9,15 @@ New mention New reply New repost + New private message + New Zap + New Follow Unknown Your nPub Invalid nPub The app requires permissions to work Pokey has not been started - Your InBox relays + Your relays Start Stop \ No newline at end of file