From da7fa51c817075eef6e5d5d8bdf21506f275efbb Mon Sep 17 00:00:00 2001 From: koalasat Date: Wed, 6 Nov 2024 18:23:48 +0100 Subject: [PATCH] refactor nostr client --- app/src/main/java/com/koalasat/pokey/Pokey.kt | 5 +- .../com/koalasat/pokey/models/NostrClient.kt | 299 ++++++++++++++++++ .../pokey/service/NotificationsService.kt | 159 +--------- .../pokey/ui/relays/RelayListAdapter.kt | 15 +- .../pokey/ui/relays/RelaysFragment.kt | 122 +------ 5 files changed, 330 insertions(+), 270 deletions(-) create mode 100644 app/src/main/java/com/koalasat/pokey/models/NostrClient.kt diff --git a/app/src/main/java/com/koalasat/pokey/Pokey.kt b/app/src/main/java/com/koalasat/pokey/Pokey.kt index 96123bc..590db07 100644 --- a/app/src/main/java/com/koalasat/pokey/Pokey.kt +++ b/app/src/main/java/com/koalasat/pokey/Pokey.kt @@ -8,9 +8,8 @@ import android.content.SharedPreferences import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.koalasat.pokey.models.EncryptedStorage +import com.koalasat.pokey.models.NostrClient import com.koalasat.pokey.service.NotificationsService -import com.vitorpamplona.ammolite.relays.Client -import com.vitorpamplona.ammolite.relays.RelayPool import com.vitorpamplona.quartz.encoders.Nip19Bech32 import com.vitorpamplona.quartz.encoders.Nip19Bech32.uriToRoute import kotlinx.coroutines.CoroutineScope @@ -27,7 +26,7 @@ class Pokey : Application() { updateIsEnabled(isForegroundServiceEnabled(this)) - RelayPool.register(Client) + NostrClient.init() } override fun onTerminate() { diff --git a/app/src/main/java/com/koalasat/pokey/models/NostrClient.kt b/app/src/main/java/com/koalasat/pokey/models/NostrClient.kt new file mode 100644 index 0000000..354e778 --- /dev/null +++ b/app/src/main/java/com/koalasat/pokey/models/NostrClient.kt @@ -0,0 +1,299 @@ +package com.koalasat.pokey.models + +import android.content.Context +import android.util.Log +import com.koalasat.pokey.Pokey +import com.koalasat.pokey.database.AppDatabase +import com.koalasat.pokey.database.RelayEntity +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.quartz.encoders.toHexKey +import com.vitorpamplona.quartz.events.Event +import com.vitorpamplona.quartz.utils.TimeUtils +import java.time.Instant + +object NostrClient { + private var subscriptionNotificationId = "subscriptionNotificationId" + private var subscriptionInboxId = "inboxRelays" + private var subscriptionReadId = "readRelays" + + 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", + ) + fun init() { + RelayPool.register(Client) + } + + fun stop() { + RelayPool.unloadRelays() + } + + fun start(context: Context) { + connectRelays(context) + getInboxLists(context) + subscribeToInbox(context) + } + + fun checkRelaysHealth(context: Context) { + if (RelayPool.getAll().isEmpty()) { + start(context) + } + RelayPool.getAll().forEach { + if (!it.isConnected()) { + Log.d( + "Pokey", + "Relay ${it.url} is not connected, reconnecting...", + ) + it.connectAndSendFiltersIfDisconnected() + } + } + } + + fun getRelay(url: String): Relay? { + return RelayPool.getRelay(url) + } + + fun deleteRelay(context: Context, url: String, kind: Int) { + val db = AppDatabase.getDatabase(context, Pokey.getInstance().getHexKey()) + db.applicationDao().deleteRelayByUrl(url, kind) + val relayStillExists = db.applicationDao().getReadRelays().any { it.url == url } + val relay = RelayPool.getRelay(url) + if (!relayStillExists && relay != null) { + RelayPool.removeRelay(relay) + } + } + + fun addRelay(context: Context, url: String, kind: Int) { + val db = AppDatabase.getDatabase(context, Pokey.getInstance().getHexKey()) + val existsRelay = db.applicationDao().existsRelay(url, kind) + + if (existsRelay < 1) { + val entity = RelayEntity(id = 0, url, kind = kind, createdAt = 0, read = 1, write = 1) + db.applicationDao().insertRelay(entity) + + val relay = RelayPool.getRelay(url) + if (Pokey.isEnabled.value == true && relay == null) { + RelayPool.addRelay( + Relay( + entity.url, + read = entity.read == 1, + write = entity.write == 1, + forceProxy = false, + activeTypes = COMMON_FEED_TYPES, + ), + ) + RelayPool.connectAndSendFiltersIfDisconnected() + } + } + } + + private fun subscribeToInbox(context: Context) { + val hexKey = Pokey.getInstance().getHexKey() + if (hexKey.isEmpty()) return + + val db = AppDatabase.getDatabase(context, Pokey.getInstance().getHexKey()) + var latestNotification = db.applicationDao().getLatestNotification() + if (latestNotification == null) latestNotification = Instant.now().toEpochMilli() / 1000 + + Client.sendFilter( + subscriptionNotificationId, + listOf( + TypedFilter( + types = COMMON_FEED_TYPES, + filter = SincePerRelayFilter( + kinds = listOf(1, 3, 4, 6, 7, 1059, 9735), + tags = mapOf("p" to listOf(hexKey)), + since = RelayPool.getAll().associate { it.url to EOSETime(latestNotification) }, + ), + ), + ), + ) + } + + fun reconnectInbox(context: Context, kind: Int) { + Log.d("Pokey", "reconnectInbox") + val db = AppDatabase.getDatabase(context, Pokey.getInstance().getHexKey()) + db.applicationDao().deleteRelaysByKind(kind) + Client.close(subscriptionInboxId) + getInboxLists(context) + } + + fun publishPrivateRelays(context: Context) { + val kind = 10050 + + val db = AppDatabase.getDatabase(context, Pokey.getInstance().getHexKey()) + val privateList = db.applicationDao().getRelaysByKind(kind) + + val pubKey = Pokey.getInstance().getHexKey() + val createdAt = TimeUtils.now() + val content = "" + val tags = privateList.map { arrayOf("relay", it.url) }.toTypedArray() + val id = Event.generateId(pubKey, createdAt, kind, tags, content).toHexKey() + val event = + Event( + id = id, + pubKey = pubKey, + createdAt = createdAt, + kind = kind, + tags = tags, + content = content, + sig = "", + ) + ExternalSigner.sign(event) { + val signeEvent = Event( + id = id, + pubKey = pubKey, + createdAt = createdAt, + kind = kind, + tags = tags, + content = content, + sig = it, + ) + Log.d("Pokey", "Relay private list : ${signeEvent.toJson()}") + Client.send(signeEvent) + } + } + + fun publishPublicRelays(context: Context) { + val kind = 10002 + + val db = AppDatabase.getDatabase(context, Pokey.getInstance().getHexKey()) + val publicList = db.applicationDao().getRelaysByKind(kind) + + val pubKey = Pokey.getInstance().getHexKey() + val createdAt = TimeUtils.now() + val content = "" + val tags = publicList.map { + var tag = arrayOf("r", it.url) + if (it.read == 1 && it.write == 0) { + tag += "read" + } else if (it.read == 0 && it.write == 1) { + tag += "write" + } + tag + }.toTypedArray() + val id = Event.generateId(pubKey, createdAt, kind, tags, content).toHexKey() + val event = + Event( + id = id, + pubKey = pubKey, + createdAt = createdAt, + kind = kind, + tags = tags, + content = content, + sig = "", + ) + ExternalSigner.sign(event) { + val signeEvent = Event( + id = id, + pubKey = pubKey, + createdAt = createdAt, + kind = kind, + tags = tags, + content = content, + sig = it, + ) + Log.d("Pokey", "Relay public list : ${signeEvent.toJson()}") + Client.send(signeEvent) + } + } + + private fun getInboxLists(context: Context) { + val hexKey = Pokey.getInstance().getHexKey() + if (hexKey.isEmpty()) return + Log.d("Pokey", "getInboxLists") + + Client.sendFilterAndStopOnFirstResponse( + subscriptionReadId, + listOf( + TypedFilter( + types = EVENT_FINDER_TYPES, + filter = SincePerRelayFilter( + kinds = listOf(10002), + authors = listOf(hexKey), + ), + ), + ), + onResponse = { manageInboxRelays(context, it) }, + ) + Client.sendFilterAndStopOnFirstResponse( + subscriptionInboxId, + listOf( + TypedFilter( + types = EVENT_FINDER_TYPES, + filter = SincePerRelayFilter( + kinds = listOf(10050), + authors = listOf(hexKey), + ), + ), + ), + onResponse = { manageInboxRelays(context, it) }, + ) + } + + private fun connectRelays(context: Context) { + val db = AppDatabase.getDatabase(context, Pokey.getInstance().getHexKey()) + var relays = db.applicationDao().getReadRelays() + if (relays.isEmpty()) { + relays = defaultRelayUrls.map { RelayEntity(id = 0, url = it, kind = 0, createdAt = 0, read = 1, write = 1) } + } + + relays.forEach { + Client.sendFilterOnlyIfDisconnected() + if (RelayPool.getRelays(it.url).isEmpty()) { + RelayPool.addRelay( + Relay( + it.url, + read = true, + write = false, + forceProxy = false, + activeTypes = COMMON_FEED_TYPES, + ), + ) + } + } + } + + private fun manageInboxRelays(context: Context, event: Event) { + Log.d("Pokey", event.kind.toString()) + val db = AppDatabase.getDatabase(context, Pokey.getInstance().getHexKey()) + val lastCreatedRelayAt = db.applicationDao().getLatestRelaysByKind(event.kind) + + if (lastCreatedRelayAt == null || lastCreatedRelayAt < event.createdAt) { + db.applicationDao().getRelaysByKind(event.kind).forEach { + deleteRelay(context, it.url, it.kind) + } + event.tags + .filter { it.size > 1 && (it[0] == "relay" || it[0] == "r") } + .forEach { + var read = 1 + var write = 1 + if (event.kind == 10002 && it.size > 2) { + read = if (it[2] == "read") 1 else 0 + write = if (it[2] == "write") 1 else 0 + } + val entity = RelayEntity(id = 0, url = it[1], kind = event.kind, createdAt = event.createdAt, read = read, write = write) + db.applicationDao().insertRelay(entity) + } + connectRelays(context) + subscribeToInbox(context) + } + + if (event.kind == 10050) { + Pokey.updateLoadingPrivateRelays(false) + } else { + Pokey.updateLoadingPublicRelays(false) + } + } +} 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 38b9fe8..ebd6198 100644 --- a/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt +++ b/app/src/main/java/com/koalasat/pokey/service/NotificationsService.kt @@ -17,24 +17,17 @@ 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 import com.koalasat.pokey.models.ExternalSigner -import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES +import com.koalasat.pokey.models.NostrClient 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.quartz.encoders.Hex import com.vitorpamplona.quartz.encoders.LnInvoiceUtil import com.vitorpamplona.quartz.encoders.toNote import com.vitorpamplona.quartz.encoders.toNpub import com.vitorpamplona.quartz.events.Event import com.vitorpamplona.quartz.events.EventInterface -import java.time.Instant import java.util.Timer import java.util.TimerTask import java.util.concurrent.ConcurrentHashMap @@ -51,15 +44,11 @@ class NotificationsService : Service() { private var channelRelaysId = "RelaysConnections" private var channelNotificationsId = "Notifications" - private var subscriptionNotificationId = "subscriptionNotificationId" - private var subscriptionInboxId = "inboxRelays" - private var subscriptionReadId = "readRelays" - private val timer = Timer() private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private val processedEvents = ConcurrentHashMap() - private val clientListener = + private val clientNotificationListener = object : Client.Listener { override fun onAuth(relay: Relay, challenge: String) { Log.d("Pokey", "Relay on Auth: ${relay.url} : $challenge") @@ -134,7 +123,6 @@ class NotificationsService : Service() { scope.launch(Dispatchers.IO) { stopSubscription() delay(1000) - connectRelays() startSubscription() } } @@ -157,22 +145,12 @@ class NotificationsService : Service() { if (Connectivity.updateNetworkCapabilities(networkCapabilities)) { stopSubscription() delay(1000) - connectRelays() startSubscription() } } } } - 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", - ) - override fun onBind(intent: Intent): IBinder { return null!! } @@ -187,7 +165,6 @@ class NotificationsService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.d("Pokey", "Starting foreground service...") - RelayPool.getAll().forEach { RelayPool.removeRelay(it) } startForeground(1, createNotification()) keepAlive() @@ -200,7 +177,7 @@ class NotificationsService : Service() { override fun onDestroy() { timer.cancel() - RelayPool.getAll().forEach { RelayPool.removeRelay(it) } + stopSubscription() try { val connectivityManager = @@ -217,75 +194,23 @@ class NotificationsService : Service() { val hexKey = Pokey.getInstance().getHexKey() if (hexKey.isEmpty()) return - if (!Client.isSubscribed(clientListener)) Client.subscribe(clientListener) - - val dao = AppDatabase.getDatabase(this@NotificationsService, hexKey).applicationDao() - var latestNotification = dao.getLatestNotification() - if (latestNotification == null) latestNotification = Instant.now().toEpochMilli() / 1000 - - Client.sendFilter( - subscriptionNotificationId, - listOf( - TypedFilter( - types = COMMON_FEED_TYPES, - filter = SincePerRelayFilter( - kinds = listOf(1, 3, 4, 6, 7, 1059, 9735), - tags = mapOf("p" to listOf(hexKey)), - since = RelayPool.getAll().associate { it.url to EOSETime(latestNotification) }, - ), - ), - ), - ) - Client.sendFilterAndStopOnFirstResponse( - subscriptionReadId, - listOf( - TypedFilter( - types = EVENT_FINDER_TYPES, - filter = SincePerRelayFilter( - kinds = listOf(10002), - authors = listOf(hexKey), - ), - ), - ), - onResponse = { manageInboxRelays(it) }, - ) - Client.sendFilterAndStopOnFirstResponse( - subscriptionInboxId, - listOf( - TypedFilter( - types = EVENT_FINDER_TYPES, - filter = SincePerRelayFilter( - kinds = listOf(10050), - authors = listOf(hexKey), - ), - ), - ), - onResponse = { manageInboxRelays(it) }, - ) + if (!Client.isSubscribed(clientNotificationListener)) Client.subscribe(clientNotificationListener) + + CoroutineScope(Dispatchers.IO).launch { + NostrClient.start(this@NotificationsService) + } } private fun stopSubscription() { - Client.unsubscribe(clientListener) - RelayPool.unloadRelays() + Client.unsubscribe(clientNotificationListener) + NostrClient.stop() } private fun keepAlive() { timer.schedule( object : TimerTask() { override fun run() { - if (RelayPool.getAll().isEmpty()) { - connectRelays() - startSubscription() - } - RelayPool.getAll().forEach { - if (!it.isConnected()) { - Log.d( - "Pokey", - "Relay ${it.url} is not connected, reconnecting...", - ) - it.connectAndSendFiltersIfDisconnected() - } - } + NostrClient.checkRelaysHealth(this@NotificationsService) } }, 3000, @@ -314,48 +239,15 @@ class NotificationsService : Service() { return notificationBuilder.build() } - private fun manageInboxRelays(event: Event) { - CoroutineScope(Dispatchers.IO).launch { - val dao = AppDatabase.getDatabase(this@NotificationsService, Pokey.getInstance().getHexKey()).applicationDao() - val lastCreatedRelayAt = dao.getLatestRelaysByKind(event.kind) - - if (lastCreatedRelayAt == null || lastCreatedRelayAt < event.createdAt) { - RelayPool.unloadRelays() - dao.deleteRelaysByKind(event.kind) - event.tags - .filter { it.size > 1 && (it[0] == "relay" || it[0] == "r") } - .forEach { - var read = 1 - var write = 1 - if (event.kind == 10002 && it.size > 2) { - read = if (it[2] == "read") 1 else 0 - write = if (it[2] == "write") 1 else 0 - } - val entity = RelayEntity(id = 0, url = it[1], kind = event.kind, createdAt = event.createdAt, read = read, write = write) - dao.insertRelay(entity) - } - - connectRelays() - startSubscription() - } - - if (event.kind == 10050) { - Pokey.updateLoadingPrivateRelays(false) - } else { - Pokey.updateLoadingPublicRelays(false) - } - } - } - private fun createNoteNotification(event: Event) { CoroutineScope(Dispatchers.IO).launch { - val dao = AppDatabase.getDatabase(this@NotificationsService, Pokey.getInstance().getHexKey()).applicationDao() - val existsEvent = dao.existsNotification(event.id) + val db = AppDatabase.getDatabase(this@NotificationsService, Pokey.getInstance().getHexKey()) + val existsEvent = db.applicationDao().existsNotification(event.id) if (existsEvent > 0) return@launch if (!event.hasVerifiedSignature()) return@launch - dao.insertNotification(NotificationEntity(0, event.id, event.createdAt)) + db.applicationDao().insertNotification(NotificationEntity(0, event.id, event.createdAt)) var title = "" var text = "" @@ -470,27 +362,4 @@ class NotificationsService : Service() { notificationManager.notify(event.hashCode(), builder.build()) } - - private fun connectRelays() { - val dao = AppDatabase.getDatabase(this@NotificationsService, Pokey.getInstance().getHexKey()).applicationDao() - var relays = dao.getReadRelays() - if (relays.isEmpty()) { - relays = defaultRelayUrls.map { RelayEntity(id = 0, url = it, kind = 0, createdAt = 0, read = 1, write = 1) } - } - - relays.forEach { - Client.sendFilterOnlyIfDisconnected() - if (RelayPool.getRelays(it.url).isEmpty()) { - RelayPool.addRelay( - Relay( - it.url, - read = true, - write = false, - forceProxy = false, - activeTypes = COMMON_FEED_TYPES, - ), - ) - } - } - } } diff --git a/app/src/main/java/com/koalasat/pokey/ui/relays/RelayListAdapter.kt b/app/src/main/java/com/koalasat/pokey/ui/relays/RelayListAdapter.kt index 8219055..036e68a 100644 --- a/app/src/main/java/com/koalasat/pokey/ui/relays/RelayListAdapter.kt +++ b/app/src/main/java/com/koalasat/pokey/ui/relays/RelayListAdapter.kt @@ -7,12 +7,10 @@ import android.widget.ImageView import android.widget.TextView import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView -import com.koalasat.pokey.Pokey import com.koalasat.pokey.R -import com.koalasat.pokey.database.AppDatabase import com.koalasat.pokey.database.RelayEntity +import com.koalasat.pokey.models.NostrClient import com.koalasat.pokey.utils.isDarkThemeEnabled -import com.vitorpamplona.ammolite.relays.RelayPool import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -27,14 +25,7 @@ class RelayListAdapter( fun bind(relayEntity: RelayEntity, position: Int) { deleteIcon.setOnClickListener { CoroutineScope(Dispatchers.IO).launch { - val hexKey = Pokey.getInstance().getHexKey() - val dao = AppDatabase.getDatabase(itemView.context, hexKey).applicationDao() - dao.deleteRelayByUrl(relayEntity.url, relayEntity.kind) - val relayStillExists = dao.getReadRelays().any { it.url == relayEntity.url } - val relay = RelayPool.getRelay(relayEntity.url) - if (!relayStillExists && relay != null) { - RelayPool.removeRelay(relay) - } + NostrClient.deleteRelay(itemView.context, relayEntity.url, relayEntity.kind) withContext(Dispatchers.Main) { adapter.removeItem(position) } @@ -53,7 +44,7 @@ class RelayListAdapter( override fun onBindViewHolder(holder: ViewHolder, position: Int) { val relayEntity = relayList[position] holder.textView.text = relayEntity.url - val relay = RelayPool.getRelay(relayEntity.url) + val relay = NostrClient.getRelay(relayEntity.url) val color = if (relay == null) { if (isDarkThemeEnabled(holder.textView.context)) R.color.white else R.color.black diff --git a/app/src/main/java/com/koalasat/pokey/ui/relays/RelaysFragment.kt b/app/src/main/java/com/koalasat/pokey/ui/relays/RelaysFragment.kt index ccb1352..3b64a2f 100644 --- a/app/src/main/java/com/koalasat/pokey/ui/relays/RelaysFragment.kt +++ b/app/src/main/java/com/koalasat/pokey/ui/relays/RelaysFragment.kt @@ -20,14 +20,8 @@ import com.koalasat.pokey.R import com.koalasat.pokey.database.AppDatabase import com.koalasat.pokey.database.RelayEntity import com.koalasat.pokey.databinding.FragmentRelaysBinding -import com.koalasat.pokey.models.ExternalSigner -import com.vitorpamplona.ammolite.relays.COMMON_FEED_TYPES -import com.vitorpamplona.ammolite.relays.Client -import com.vitorpamplona.ammolite.relays.Relay -import com.vitorpamplona.ammolite.relays.RelayPool -import com.vitorpamplona.quartz.encoders.toHexKey -import com.vitorpamplona.quartz.events.Event -import com.vitorpamplona.quartz.utils.TimeUtils +import com.koalasat.pokey.models.NostrClient +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -88,7 +82,9 @@ class RelaysFragment : Fragment() { } } binding.publishPublicRelay.setOnClickListener { - publishPublicRelays() + CoroutineScope(Dispatchers.IO).launch { + context?.let { it1 -> NostrClient.publishPublicRelays(it1) } + } } binding.reloadPublicRelays.setOnClickListener { Pokey.updateLoadingPublicRelays(true) @@ -127,7 +123,9 @@ class RelaysFragment : Fragment() { } } binding.publishPrivateRelay.setOnClickListener { - publishPrivateRelays() + CoroutineScope(Dispatchers.IO).launch { + context?.let { it1 -> NostrClient.publishPrivateRelays(it1) } + } } binding.reloadPrivateRelay.setOnClickListener { Pokey.updateLoadingPrivateRelays(true) @@ -160,28 +158,8 @@ class RelaysFragment : Fragment() { private fun insertRelay(url: String, kind: Int) { lifecycleScope.launch { - val hexKey = Pokey.getInstance().getHexKey() - val dao = context?.let { AppDatabase.getDatabase(it, hexKey).applicationDao() } - if (dao != null && url.isNotEmpty()) { - val existsRelay = withContext(Dispatchers.IO) { dao.existsRelay(url, kind) } - if (existsRelay < 1) { - val entity = RelayEntity(id = 0, url, kind = kind, createdAt = 0, read = 1, write = 1) - withContext(Dispatchers.IO) { dao.insertRelay(entity) } - - val relay = RelayPool.getRelay(url) - if (Pokey.isEnabled.value == true && relay == null) { - RelayPool.addRelay( - Relay( - entity.url, - read = entity.read == 1, - write = entity.write == 1, - forceProxy = false, - activeTypes = COMMON_FEED_TYPES, - ), - ) - RelayPool.connectAndSendFiltersIfDisconnected() - } - } + CoroutineScope(Dispatchers.IO).launch { + context?.let { NostrClient.addRelay(it, url, kind) } loadRelays() } } @@ -189,12 +167,8 @@ class RelaysFragment : Fragment() { private fun reconnectRelays(kind: Int) { lifecycleScope.launch { - val hexKey = Pokey.getInstance().getHexKey() - val dao = context?.let { AppDatabase.getDatabase(it, hexKey).applicationDao() } - if (dao != null) { - Pokey.getInstance().stopService() - withContext(Dispatchers.IO) { dao.deleteRelaysByKind(kind) } - Pokey.getInstance().startService() + CoroutineScope(Dispatchers.IO).launch { + context?.let { NostrClient.reconnectInbox(it, kind) } } } } @@ -242,76 +216,4 @@ class RelaysFragment : Fragment() { } } } - - private fun publishPrivateRelays() { - val pubKey = Pokey.getInstance().getHexKey() - val createdAt = TimeUtils.now() - val kind = 10050 - val content = "" - val tags = privateList.map { arrayOf("relay", it.url) }.toTypedArray() - val id = Event.generateId(pubKey, createdAt, kind, tags, content).toHexKey() - val event = - Event( - id = id, - pubKey = pubKey, - createdAt = createdAt, - kind = kind, - tags = tags, - content = content, - sig = "", - ) - ExternalSigner.sign(event) { - val signeEvent = Event( - id = id, - pubKey = pubKey, - createdAt = createdAt, - kind = kind, - tags = tags, - content = content, - sig = it, - ) - Log.d("Pokey", "Relay private list : ${signeEvent.toJson()}") - Client.send(signeEvent) - } - } - - private fun publishPublicRelays() { - val pubKey = Pokey.getInstance().getHexKey() - val createdAt = TimeUtils.now() - val kind = 10002 - val content = "" - val tags = publicList.map { - var tag = arrayOf("r", it.url) - if (it.read == 1 && it.write == 0) { - tag += "read" - } else if (it.read == 0 && it.write == 1) { - tag += "write" - } - tag - }.toTypedArray() - val id = Event.generateId(pubKey, createdAt, kind, tags, content).toHexKey() - val event = - Event( - id = id, - pubKey = pubKey, - createdAt = createdAt, - kind = kind, - tags = tags, - content = content, - sig = "", - ) - ExternalSigner.sign(event) { - val signeEvent = Event( - id = id, - pubKey = pubKey, - createdAt = createdAt, - kind = kind, - tags = tags, - content = content, - sig = it, - ) - Log.d("Pokey", "Relay public list : ${signeEvent.toJson()}") - Client.send(signeEvent) - } - } }