This commit implements a new layer called NostrNetworkManager, responsible for managing interactions with the Nostr network, and providing a higher level API that is easier and more secure to use for the layer above it. It also integrates it with the rest of the app, by moving RelayPool and PostBox into NostrNetworkManager, along with all their usages. Changelog-Added: Added NIP-65 relay list support Changelog-Changed: Improved robustness of relay list handling Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
227 lines
8.2 KiB
Swift
227 lines
8.2 KiB
Swift
//
|
|
// DamusState.swift
|
|
// damus
|
|
//
|
|
// Created by William Casarin on 2022-04-30.
|
|
//
|
|
|
|
import Foundation
|
|
import LinkPresentation
|
|
import EmojiPicker
|
|
|
|
class DamusState: HeadlessDamusState {
|
|
let keypair: Keypair
|
|
let likes: EventCounter
|
|
let boosts: EventCounter
|
|
let quote_reposts: EventCounter
|
|
let contacts: Contacts
|
|
let mutelist_manager: MutelistManager
|
|
let profiles: Profiles
|
|
let dms: DirectMessagesModel
|
|
let previews: PreviewCache
|
|
let zaps: Zaps
|
|
let lnurls: LNUrls
|
|
let settings: UserSettingsStore
|
|
let relay_filters: RelayFilters
|
|
let relay_model_cache: RelayModelCache
|
|
let drafts: Drafts
|
|
let events: EventCache
|
|
let bookmarks: BookmarksManager
|
|
let replies: ReplyCounter
|
|
let wallet: WalletModel
|
|
let nav: NavigationCoordinator
|
|
let music: MusicController?
|
|
let video: DamusVideoCoordinator
|
|
let ndb: Ndb
|
|
var purple: DamusPurple
|
|
var push_notification_client: PushNotificationClient
|
|
let emoji_provider: EmojiProvider
|
|
private(set) var nostrNetwork: NostrNetworkManager
|
|
|
|
init(keypair: Keypair, likes: EventCounter, boosts: EventCounter, contacts: Contacts, mutelist_manager: MutelistManager, profiles: Profiles, dms: DirectMessagesModel, previews: PreviewCache, zaps: Zaps, lnurls: LNUrls, settings: UserSettingsStore, relay_filters: RelayFilters, relay_model_cache: RelayModelCache, drafts: Drafts, events: EventCache, bookmarks: BookmarksManager, replies: ReplyCounter, wallet: WalletModel, nav: NavigationCoordinator, music: MusicController?, video: DamusVideoCoordinator, ndb: Ndb, purple: DamusPurple? = nil, quote_reposts: EventCounter, emoji_provider: EmojiProvider) {
|
|
self.keypair = keypair
|
|
self.likes = likes
|
|
self.boosts = boosts
|
|
self.contacts = contacts
|
|
self.mutelist_manager = mutelist_manager
|
|
self.profiles = profiles
|
|
self.dms = dms
|
|
self.previews = previews
|
|
self.zaps = zaps
|
|
self.lnurls = lnurls
|
|
self.settings = settings
|
|
self.relay_filters = relay_filters
|
|
self.relay_model_cache = relay_model_cache
|
|
self.drafts = drafts
|
|
self.events = events
|
|
self.bookmarks = bookmarks
|
|
self.replies = replies
|
|
self.wallet = wallet
|
|
self.nav = nav
|
|
self.music = music
|
|
self.video = video
|
|
self.ndb = ndb
|
|
self.purple = purple ?? DamusPurple(
|
|
settings: settings,
|
|
keypair: keypair
|
|
)
|
|
self.quote_reposts = quote_reposts
|
|
self.push_notification_client = PushNotificationClient(keypair: keypair, settings: settings)
|
|
self.emoji_provider = emoji_provider
|
|
|
|
let networkManagerDelegate = NostrNetworkManagerDelegate(settings: settings, contacts: contacts, ndb: ndb, keypair: keypair, relayModelCache: relay_model_cache, relayFilters: relay_filters)
|
|
self.nostrNetwork = NostrNetworkManager(delegate: networkManagerDelegate)
|
|
}
|
|
|
|
@MainActor
|
|
convenience init?(keypair: Keypair) {
|
|
// nostrdb
|
|
var mndb = Ndb()
|
|
if mndb == nil {
|
|
// try recovery
|
|
print("DB ISSUE! RECOVERING")
|
|
mndb = Ndb.safemode()
|
|
|
|
// out of space or something?? maybe we need a in-memory fallback
|
|
if mndb == nil {
|
|
logout(nil)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
let navigationCoordinator: NavigationCoordinator = NavigationCoordinator()
|
|
let home: HomeModel = HomeModel()
|
|
let sub_id = UUID().uuidString
|
|
|
|
guard let ndb = mndb else { return nil }
|
|
let pubkey = keypair.pubkey
|
|
|
|
let model_cache = RelayModelCache()
|
|
let relay_filters = RelayFilters(our_pubkey: pubkey)
|
|
let bootstrap_relays = load_bootstrap_relays(pubkey: pubkey)
|
|
|
|
let settings = UserSettingsStore.globally_load_for(pubkey: pubkey)
|
|
|
|
self.init(
|
|
keypair: keypair,
|
|
likes: EventCounter(our_pubkey: pubkey),
|
|
boosts: EventCounter(our_pubkey: pubkey),
|
|
contacts: Contacts(our_pubkey: pubkey),
|
|
mutelist_manager: MutelistManager(user_keypair: keypair),
|
|
profiles: Profiles(ndb: ndb),
|
|
dms: home.dms,
|
|
previews: PreviewCache(),
|
|
zaps: Zaps(our_pubkey: pubkey),
|
|
lnurls: LNUrls(),
|
|
settings: settings,
|
|
relay_filters: relay_filters,
|
|
relay_model_cache: model_cache,
|
|
drafts: Drafts(),
|
|
events: EventCache(ndb: ndb),
|
|
bookmarks: BookmarksManager(pubkey: pubkey),
|
|
replies: ReplyCounter(our_pubkey: pubkey),
|
|
wallet: WalletModel(settings: settings),
|
|
nav: navigationCoordinator,
|
|
music: MusicController(onChange: { _ in }),
|
|
video: DamusVideoCoordinator(),
|
|
ndb: ndb,
|
|
quote_reposts: .init(our_pubkey: pubkey),
|
|
emoji_provider: DefaultEmojiProvider(showAllVariations: true)
|
|
)
|
|
}
|
|
|
|
@discardableResult
|
|
func add_zap(zap: Zapping) -> Bool {
|
|
// store generic zap mapping
|
|
self.zaps.add_zap(zap: zap)
|
|
let stored = self.events.store_zap(zap: zap)
|
|
|
|
// thread zaps
|
|
if let ev = zap.event, !settings.nozaps, zap.is_in_thread {
|
|
// [nozaps]: thread zaps are only available outside of the app store
|
|
replies.count_replies(ev, keypair: self.keypair)
|
|
events.add_replies(ev: ev, keypair: self.keypair)
|
|
}
|
|
|
|
// associate with events as well
|
|
return stored
|
|
}
|
|
|
|
var pubkey: Pubkey {
|
|
return keypair.pubkey
|
|
}
|
|
|
|
var is_privkey_user: Bool {
|
|
keypair.privkey != nil
|
|
}
|
|
|
|
func close() {
|
|
print("txn: damus close")
|
|
Task {
|
|
try await self.push_notification_client.revoke_token()
|
|
}
|
|
wallet.disconnect()
|
|
nostrNetwork.pool.close()
|
|
ndb.close()
|
|
}
|
|
|
|
static var empty: DamusState {
|
|
let empty_pub: Pubkey = .empty
|
|
let empty_sec: Privkey = .empty
|
|
let kp = Keypair(pubkey: empty_pub, privkey: nil)
|
|
|
|
return DamusState.init(
|
|
keypair: Keypair(pubkey: empty_pub, privkey: empty_sec),
|
|
likes: EventCounter(our_pubkey: empty_pub),
|
|
boosts: EventCounter(our_pubkey: empty_pub),
|
|
contacts: Contacts(our_pubkey: empty_pub),
|
|
mutelist_manager: MutelistManager(user_keypair: kp),
|
|
profiles: Profiles(ndb: .empty),
|
|
dms: DirectMessagesModel(our_pubkey: empty_pub),
|
|
previews: PreviewCache(),
|
|
zaps: Zaps(our_pubkey: empty_pub),
|
|
lnurls: LNUrls(),
|
|
settings: UserSettingsStore(),
|
|
relay_filters: RelayFilters(our_pubkey: empty_pub),
|
|
relay_model_cache: RelayModelCache(),
|
|
drafts: Drafts(),
|
|
events: EventCache(ndb: .empty),
|
|
bookmarks: BookmarksManager(pubkey: empty_pub),
|
|
replies: ReplyCounter(our_pubkey: empty_pub),
|
|
wallet: WalletModel(settings: UserSettingsStore()),
|
|
nav: NavigationCoordinator(),
|
|
music: nil,
|
|
video: DamusVideoCoordinator(),
|
|
ndb: .empty,
|
|
quote_reposts: .init(our_pubkey: empty_pub),
|
|
emoji_provider: DefaultEmojiProvider(showAllVariations: true)
|
|
)
|
|
}
|
|
}
|
|
|
|
fileprivate extension DamusState {
|
|
struct NostrNetworkManagerDelegate: NostrNetworkManager.Delegate {
|
|
let settings: UserSettingsStore
|
|
let contacts: Contacts
|
|
|
|
var ndb: Ndb
|
|
var keypair: Keypair
|
|
|
|
var latestRelayListEventIdHex: String? {
|
|
get { self.settings.latestRelayListEventIdHex }
|
|
set { self.settings.latestRelayListEventIdHex = newValue }
|
|
}
|
|
|
|
var latestContactListEvent: NostrEvent? { self.contacts.event }
|
|
var bootstrapRelays: [RelayURL] { get_default_bootstrap_relays() }
|
|
var developerMode: Bool { self.settings.developer_mode }
|
|
var relayModelCache: RelayModelCache
|
|
var relayFilters: RelayFilters
|
|
|
|
var nwcWallet: WalletConnectURL? {
|
|
guard let nwcString = self.settings.nostr_wallet_connect else { return nil }
|
|
return WalletConnectURL(str: nwcString)
|
|
}
|
|
}
|
|
}
|