Skip to content
This repository has been archived by the owner on Apr 14, 2024. It is now read-only.

Multi account #33

Merged
merged 35 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2417632
Make drawer scrollable
dluvian Oct 18, 2023
a525620
Make accounts expandable
dluvian Oct 18, 2023
e2c667e
Interpret empty reaction as like-reaction
dluvian Oct 18, 2023
445fdba
Publish edited nip65 to defaultRelays
dluvian Oct 18, 2023
2665841
Don't cancel follow process when following someone else
dluvian Oct 19, 2023
602fcc6
Navigate to add-acc-screen
dluvian Oct 20, 2023
31cc04a
Move vm state classes to separate files
dluvian Oct 20, 2023
ae37287
Add account database table
dluvian Oct 20, 2023
8f4d44d
Normalize hashtags before inserting into db
dluvian Oct 23, 2023
50814f6
Handle multiple private keys
dluvian Oct 23, 2023
22a39e4
Simplify KeyManager
dluvian Oct 24, 2023
3a7a02a
Use account flow in drawer
dluvian Oct 24, 2023
b3c4866
Add account
dluvian Oct 25, 2023
ded8db8
Allow hex key for adding accounts
dluvian Oct 25, 2023
e1ad271
Indicate active account
dluvian Oct 25, 2023
45a3595
Activate and delete account
dluvian Oct 26, 2023
d0649b8
Fix index tracking
dluvian Oct 26, 2023
e78edf4
Simplify code by using account table
dluvian Oct 26, 2023
f9498bd
Merge branch 'master' into multi-account
dluvian Oct 27, 2023
d288613
Fix foreign key problems
dluvian Oct 27, 2023
c6ed2fa
Subscribe all account profiles
dluvian Oct 27, 2023
cbd5aa2
Get active pubkey via flow
dluvian Oct 27, 2023
73b728d
Shuffle autopilot relays
dluvian Oct 27, 2023
b99ed9a
Refresh feed after pubkey change
dluvian Oct 27, 2023
a9dfd61
Open feed after adding account
dluvian Oct 27, 2023
fd3ed15
Don't save contacts-only-setting
dluvian Oct 27, 2023
a01967c
Fix text input
dluvian Oct 27, 2023
eeb900e
Refactor writing posts and replies
dluvian Oct 28, 2023
5aa7cd9
Format code
dluvian Oct 28, 2023
ad542f1
Subscribe profile after log in
dluvian Oct 28, 2023
d62c48c
Clear ID cache
dluvian Oct 28, 2023
d43667e
Prevent subscribing feed two times on start up
dluvian Oct 28, 2023
ec8805b
Remove unused function
dluvian Oct 28, 2023
d0ec66e
Adjust layout
dluvian Oct 29, 2023
9d96d87
Use main dispatcher for switching and deleting accounts
dluvian Oct 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions app/src/main/java/com/dluvian/nozzle/AppContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.dluvian.nozzle.data.preferences.IFeedSettingsPreferences
import com.dluvian.nozzle.data.preferences.NozzlePreferences
import com.dluvian.nozzle.data.profileFollower.IProfileFollower
import com.dluvian.nozzle.data.profileFollower.ProfileFollower
import com.dluvian.nozzle.data.provider.IAccountProvider
import com.dluvian.nozzle.data.provider.IAutopilotProvider
import com.dluvian.nozzle.data.provider.IContactListProvider
import com.dluvian.nozzle.data.provider.IFeedProvider
Expand All @@ -38,6 +39,7 @@ import com.dluvian.nozzle.data.provider.IPostWithMetaProvider
import com.dluvian.nozzle.data.provider.IProfileWithMetaProvider
import com.dluvian.nozzle.data.provider.IRelayProvider
import com.dluvian.nozzle.data.provider.IThreadProvider
import com.dluvian.nozzle.data.provider.impl.AccountProvider
import com.dluvian.nozzle.data.provider.impl.AutopilotProvider
import com.dluvian.nozzle.data.provider.impl.ContactListProvider
import com.dluvian.nozzle.data.provider.impl.FeedProvider
Expand All @@ -58,10 +60,9 @@ class AppContainer(context: Context) {
name = "nozzle_database",
).fallbackToDestructiveMigration().build()

val keyManager: IKeyManager = KeyManager(context = context)
val keyManager: IKeyManager = KeyManager(context = context, accountDao = roomDb.accountDao())

val contactListProvider: IContactListProvider = ContactListProvider(
pubkeyProvider = keyManager,
contactDao = roomDb.contactDao()
)

Expand Down Expand Up @@ -89,15 +90,17 @@ class AppContainer(context: Context) {
private val nostrSubscriber: INostrSubscriber = NostrSubscriber(nostrService = nostrService)

val relayProvider: IRelayProvider = RelayProvider(
pubkeyProvider = keyManager,
contactListProvider = contactListProvider,
nip65Dao = roomDb.nip65Dao(),
)

val accountProvider: IAccountProvider = AccountProvider(accountDao = roomDb.accountDao())

val nozzleSubscriber: INozzleSubscriber = NozzleSubscriber(
nostrSubscriber = nostrSubscriber,
relayProvider = relayProvider,
pubkeyProvider = keyManager,
accountProvider = accountProvider,
idCache = dbSweepExcludingCache,
database = roomDb,
)
Expand Down Expand Up @@ -161,6 +164,8 @@ class AppContainer(context: Context) {

val personalProfileManager: IPersonalProfileManager = PersonalProfileManager(
pubkeyProvider = keyManager,
relayProvider = relayProvider,
nostrService = nostrService,
profileDao = roomDb.profileDao()
)

Expand All @@ -172,16 +177,14 @@ class AppContainer(context: Context) {

val databaseSweeper: IDatabaseSweeper = DatabaseSweeper(
keepPosts = SWEEP_THRESHOLD,
pubkeyProvider = keyManager,
contactListProvider = contactListProvider,
dbSweepExcludingCache = dbSweepExcludingCache,
database = roomDb,
)

val postPreparer: IPostPreparer = PostPreparer()

val inboxFeedProvider: IInboxFeedProvider = InboxFeedProvider(
nozzleSubscriber = nozzleSubscriber,
pubkeyProvider = keyManager,
postWithMetaProvider = postWithMetaProvider,
postDao = roomDb.postDao()
)
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/java/com/dluvian/nozzle/data/cache/IIdCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ package com.dluvian.nozzle.data.cache

interface IIdCache {
fun addPostId(id: String): Boolean
fun containsPostId(id: String): Boolean
fun getPostIds(): Set<String>
fun clearPostIds()

fun addPubkey(pubkey: String): Boolean
fun getPubkeys(): Set<String>
fun clearPubkeys()

fun addNip65Author(pubkey: String): Boolean
fun getNip65Authors(): Set<String>
fun clearNip65Authors()

fun addContactListAuthor(pubkey: String): Boolean
fun getContactListAuthors(): Set<String>

fun removePostId(postId: String)
fun clearContactListAuthors()
}
51 changes: 16 additions & 35 deletions app/src/main/java/com/dluvian/nozzle/data/cache/IdCache.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,20 @@ class IdCache : IIdCache {
private val nip65Pubkeys = Collections.synchronizedSet(mutableSetOf<String>())
private val contactListAuthors = Collections.synchronizedSet(mutableSetOf<String>())

override fun addPostId(id: String): Boolean {
return postIds.add(id)
}

override fun getPostIds(): Set<String> {
return postIds.toSet()
}

override fun addPubkey(pubkey: String): Boolean {
return pubkeys.add(pubkey)
}

override fun getPubkeys(): Set<String> {
return pubkeys.toSet()
}

override fun addNip65Author(pubkey: String): Boolean {
return nip65Pubkeys.add(pubkey)
}

override fun getNip65Authors(): Set<String> {
return nip65Pubkeys.toSet()
}

override fun addContactListAuthor(pubkey: String): Boolean {
return contactListAuthors.add(pubkey)
}

override fun getContactListAuthors(): Set<String> {
return contactListAuthors.toSet()
}

override fun removePostId(postId: String) {
postIds.remove(postId)
}
override fun addPostId(id: String): Boolean = postIds.add(id)
override fun containsPostId(id: String): Boolean = postIds.contains(id)
override fun getPostIds(): Set<String> = postIds.toSet()
override fun clearPostIds() = postIds.clear()

override fun addPubkey(pubkey: String): Boolean = pubkeys.add(pubkey)
override fun getPubkeys(): Set<String> = pubkeys.toSet()
override fun clearPubkeys() = pubkeys.clear()

override fun addNip65Author(pubkey: String): Boolean = nip65Pubkeys.add(pubkey)
override fun getNip65Authors(): Set<String> = nip65Pubkeys.toSet()
override fun clearNip65Authors() = nip65Pubkeys.clear()

override fun addContactListAuthor(pubkey: String): Boolean = contactListAuthors.add(pubkey)
override fun getContactListAuthors(): Set<String> = contactListAuthors.toSet()
override fun clearContactListAuthors() = contactListAuthors.clear()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package com.dluvian.nozzle.data.databaseSweeper

import android.util.Log
import com.dluvian.nozzle.data.cache.IIdCache
import com.dluvian.nozzle.data.provider.IContactListProvider
import com.dluvian.nozzle.data.provider.IPubkeyProvider
import com.dluvian.nozzle.data.room.AppDatabase
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.random.Random
Expand All @@ -12,8 +10,6 @@ private const val TAG = "DatabaseSweeper"

class DatabaseSweeper(
private val keepPosts: Int,
private val pubkeyProvider: IPubkeyProvider,
private val contactListProvider: IContactListProvider,
private val dbSweepExcludingCache: IIdCache,
private val database: AppDatabase
) : IDatabaseSweeper {
Expand All @@ -24,42 +20,47 @@ class DatabaseSweeper(
return
}
Log.i(TAG, "Sweep database")
val excludePubkeys = dbSweepExcludingCache.getPubkeys() +
contactListProvider.listPersonalContactPubkeys() +
pubkeyProvider.getPubkey()

when (Random.nextInt(until = 4)) {
0 -> deletePosts()
1 -> deleteProfiles(excludePubkeys = excludePubkeys)
2 -> deleteContactLists(excludePubkeys = excludePubkeys)
3 -> deleteNip65(excludePubkeys = excludePubkeys)
1 -> deleteProfiles()
2 -> deleteContactLists()
3 -> deleteNip65()
else -> Log.w(TAG, "Delete case not covered")
}
isSweeping.set(false)
}

private suspend fun deletePosts() {
// TODO: Exclude author via db table of user acc
val deletePostCount = database.postDao().deleteAllExceptNewest(
amountToKeep = keepPosts,
exclude = dbSweepExcludingCache.getPostIds(),
excludeAuthor = pubkeyProvider.getPubkey()
)
dbSweepExcludingCache.clearPostIds()
Log.i(TAG, "Deleted $deletePostCount posts")
}

private suspend fun deleteProfiles(excludePubkeys: Collection<String>) {
val deleteProfileCount = database.profileDao().deleteOrphaned(exclude = excludePubkeys)
private suspend fun deleteProfiles() {
val deleteProfileCount = database
.profileDao()
.deleteOrphaned(exclude = dbSweepExcludingCache.getPubkeys())
dbSweepExcludingCache.clearPubkeys()
Log.i(TAG, "Deleted $deleteProfileCount profiles")
}

private suspend fun deleteContactLists(excludePubkeys: Collection<String>) {
val deleteContactCount = database.contactDao().deleteOrphaned(exclude = excludePubkeys)
private suspend fun deleteContactLists() {
val deleteContactCount = database
.contactDao()
.deleteOrphaned(exclude = dbSweepExcludingCache.getContactListAuthors())
dbSweepExcludingCache.clearContactListAuthors()
Log.i(TAG, "Deleted $deleteContactCount contact entries")
}

private suspend fun deleteNip65(excludePubkeys: Collection<String>) {
val deleteNip65Count = database.nip65Dao().deleteOrphaned(excludePubkeys = excludePubkeys)
private suspend fun deleteNip65() {
val deleteNip65Count = database
.nip65Dao()
.deleteOrphaned(dbSweepExcludingCache.getNip65Authors())
dbSweepExcludingCache.clearNip65Authors()
Log.i(TAG, "Deleted $deleteNip65Count nip65 entries")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ class EventProcessor(
private fun processPost(event: Event, relayUrl: String?) {
if (!verify(event)) return

val isNew = dbSweepExcludingCache.addPostId(event.id)
if (!isNew) {
val isPresent = dbSweepExcludingCache.containsPostId(event.id)
if (isPresent) {
insertEventRelay(eventId = event.id, relayUrl = relayUrl)
return
}
Expand All @@ -76,11 +76,11 @@ class EventProcessor(
)
}.invokeOnCompletion {
if (it == null) {
dbSweepExcludingCache.addPostId(event.id)
insertEventRelay(eventId = event.id, relayUrl = relayUrl)
return@invokeOnCompletion
}
Log.w(TAG, "Failed to process post ${event.id} from ${event.pubkey}", it)
dbSweepExcludingCache.removePostId(event.id)
}
}

Expand Down Expand Up @@ -175,7 +175,7 @@ class EventProcessor(
}

private fun processReaction(event: Event) {
if (event.content != "+") return
if (event.content != "+" && event.content.isNotEmpty()) return
if (otherIdsCache.contains(event.id)) return
if (!verify(event)) return

Expand Down
10 changes: 6 additions & 4 deletions app/src/main/java/com/dluvian/nozzle/data/manager/IKeyManager.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.dluvian.nozzle.data.manager

import com.dluvian.nozzle.data.provider.IPubkeyProvider
import com.dluvian.nozzle.model.Pubkey
import com.dluvian.nozzle.model.nostr.Keys

interface IKeyManager : IPubkeyProvider {
fun getPrivkey(): String
fun getNsec(): String
fun setPrivkey(privkey: String)
fun getKeys(): Keys
fun getActiveNsec(): String
suspend fun activatePubkey(pubkey: Pubkey)
suspend fun addPrivkey(privkey: String)
suspend fun deletePubkey(pubkey: Pubkey)
fun getActiveKeys(): Keys
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.dluvian.nozzle.data.manager

import com.dluvian.nozzle.data.provider.IPersonalProfileProvider
import com.dluvian.nozzle.model.nostr.Metadata

interface IPersonalProfileManager : IPersonalProfileProvider {
suspend fun setMeta(name: String, about: String, picture: String, nip05: String, lud16: String)
suspend fun upsertMetadata(metadata: Metadata)
}
Loading