ndb/txn: make transactions failable
Since there may be situations where we close and re-open the database,
we need to make sure transactions fail when the database is not open.
Make NdbTxn an init?() constructor and check for ndb.closed. If it's
closed, then fail transaction construction.
This fixes crashes during high database activity when switching from
background to foreground and vice-versa.
Fixes: da2bdad18d ("nostrdb: close database when backgrounded")
This commit is contained in:
@@ -66,7 +66,9 @@ class EventsModel: ObservableObject {
|
||||
case .auth:
|
||||
break
|
||||
case .eose:
|
||||
let txn = NdbTxn(ndb: self.state.ndb)
|
||||
guard let txn = NdbTxn(ndb: self.state.ndb) else {
|
||||
return
|
||||
}
|
||||
load_profiles(context: "events_model", profiles_subid: profiles_id, relay_id: relay_id, load: .from_events(events), damus_state: state, txn: txn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ class FollowersModel: ObservableObject {
|
||||
|
||||
case .eose(let sub_id):
|
||||
if sub_id == self.sub_id {
|
||||
let txn = NdbTxn(ndb: self.damus_state.ndb)
|
||||
guard let txn = NdbTxn(ndb: self.damus_state.ndb) else { return }
|
||||
load_profiles(relay_id: relay_id, txn: txn)
|
||||
} else if sub_id == self.profiles_id {
|
||||
damus_state.pool.unsubscribe(sub_id: profiles_id, to: [relay_id])
|
||||
|
||||
@@ -414,8 +414,10 @@ class HomeModel {
|
||||
print(msg)
|
||||
|
||||
case .eose(let sub_id):
|
||||
|
||||
let txn = NdbTxn(ndb: damus_state.ndb)
|
||||
guard let txn = NdbTxn(ndb: damus_state.ndb) else {
|
||||
return
|
||||
}
|
||||
|
||||
if sub_id == dms_subid {
|
||||
var dms = dms.dms.flatMap { $0.events }
|
||||
dms.append(contentsOf: incoming_dms)
|
||||
|
||||
@@ -187,7 +187,7 @@ func mention_str(_ m: Mention<MentionRef>, profiles: Profiles) -> CompatibleText
|
||||
case .pubkey(let pk):
|
||||
let npub = bech32_pubkey(pk)
|
||||
let profile_txn = profiles.lookup(id: pk)
|
||||
let profile = profile_txn.unsafeUnownedValue
|
||||
let profile = profile_txn?.unsafeUnownedValue
|
||||
let disp = Profile.displayName(profile: profile, pubkey: pk).username.truncate(maxLength: 50)
|
||||
var attributedString = AttributedString(stringLiteral: "@\(disp)")
|
||||
attributedString.link = URL(string: "damus:nostr:\(npub)")
|
||||
|
||||
@@ -21,6 +21,7 @@ func process_local_notification(state: HeadlessDamusState, event ev: NostrEvent)
|
||||
guard let local_notification = generate_local_notification_object(from: ev, state: state) else {
|
||||
return
|
||||
}
|
||||
|
||||
create_local_notification(profiles: state.profiles, notify: local_notification)
|
||||
}
|
||||
|
||||
@@ -76,7 +77,8 @@ func generate_local_notification_object(from ev: NostrEvent, state: HeadlessDamu
|
||||
} else if type == .like,
|
||||
state.settings.like_notification,
|
||||
let evid = ev.referenced_ids.last,
|
||||
let liked_event = state.ndb.lookup_note(evid).unsafeUnownedValue // We are only accessing it temporarily to generate notification content
|
||||
let txn = state.ndb.lookup_note(evid),
|
||||
let liked_event = txn.unsafeUnownedValue // We are only accessing it temporarily to generate notification content
|
||||
{
|
||||
let content_preview = render_notification_content_preview(ev: liked_event, profiles: state.profiles, keypair: state.keypair)
|
||||
return LocalNotification(type: .like, event: ev, target: liked_event, content: content_preview)
|
||||
@@ -135,9 +137,9 @@ func render_notification_content_preview(ev: NostrEvent, profiles: Profiles, key
|
||||
}
|
||||
|
||||
func event_author_name(profiles: Profiles, pubkey: Pubkey) -> String {
|
||||
return profiles.lookup(id: pubkey).map({ profile in
|
||||
Profile.displayName(profile: profile, pubkey: pubkey).username.truncate(maxLength: 50)
|
||||
}).value
|
||||
let profile_txn = profiles.lookup(id: pubkey)
|
||||
let profile = profile_txn?.unsafeUnownedValue
|
||||
return Profile.displayName(profile: profile, pubkey: pubkey).username.truncate(maxLength: 50)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@@ -173,8 +175,8 @@ func process_zap_event(state: HeadlessDamusState, ev: NostrEvent, completion: @e
|
||||
return
|
||||
}
|
||||
|
||||
guard let lnurl = state.profiles.lookup_with_timestamp(ptag)
|
||||
.map({ pr in pr?.lnurl }).value else {
|
||||
guard let txn = state.profiles.lookup_with_timestamp(ptag),
|
||||
let lnurl = txn.map({ pr in pr?.lnurl }).value else {
|
||||
completion(.failed)
|
||||
return
|
||||
}
|
||||
@@ -221,7 +223,8 @@ func get_zap_target_pubkey(ev: NostrEvent, ndb: Ndb) -> Pubkey? {
|
||||
}
|
||||
|
||||
// we can't trust the p tag on note zaps because they can be faked
|
||||
guard let pk = ndb.lookup_note(etag).unsafeUnownedValue?.pubkey else {
|
||||
guard let txn = ndb.lookup_note(etag),
|
||||
let pk = txn.unsafeUnownedValue?.pubkey else {
|
||||
// We don't have the event in cache so we can't check the pubkey.
|
||||
|
||||
// We could return this as an invalid zap but that wouldn't be correct
|
||||
|
||||
@@ -128,7 +128,7 @@ class ProfileModel: ObservableObject, Equatable {
|
||||
break
|
||||
//notify(.notice, notice)
|
||||
case .eose:
|
||||
let txn = NdbTxn(ndb: damus.ndb)
|
||||
guard let txn = NdbTxn(ndb: damus.ndb) else { return }
|
||||
if resp.subid == sub_id {
|
||||
load_profiles(context: "profile", profiles_subid: prof_subid, relay_id: relay_id, load: .from_events(events.events), damus_state: damus, txn: txn)
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ class SearchHomeModel: ObservableObject {
|
||||
// global events are not realtime
|
||||
unsubscribe(to: relay_id)
|
||||
|
||||
let txn = NdbTxn(ndb: damus_state.ndb)
|
||||
guard let txn = NdbTxn(ndb: damus_state.ndb) else { return }
|
||||
load_profiles(context: "universe", profiles_subid: profiles_subid, relay_id: relay_id, load: .from_events(events.all_events), damus_state: damus_state, txn: txn)
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ class SearchModel: ObservableObject {
|
||||
self.loading = false
|
||||
|
||||
if sub_id == self.sub_id {
|
||||
let txn = NdbTxn(ndb: state.ndb)
|
||||
guard let txn = NdbTxn(ndb: state.ndb) else { return }
|
||||
load_profiles(context: "search", profiles_subid: self.profiles_subid, relay_id: relay_id, load: .from_events(self.events.all_events), damus_state: state, txn: txn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ class ThreadModel: ObservableObject {
|
||||
}
|
||||
|
||||
if sub_id == self.base_subid {
|
||||
let txn = NdbTxn(ndb: damus_state.ndb)
|
||||
guard let txn = NdbTxn(ndb: damus_state.ndb) else { return }
|
||||
load_profiles(context: "thread", profiles_subid: self.profiles_subid, relay_id: relay_id, load: .from_events(Array(event_map)), damus_state: damus_state, txn: txn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ class ZapsModel: ObservableObject {
|
||||
break
|
||||
case .eose:
|
||||
let events = state.events.lookup_zaps(target: target).map { $0.request.ev }
|
||||
let txn = NdbTxn(ndb: state.ndb)
|
||||
guard let txn = NdbTxn(ndb: state.ndb) else { return }
|
||||
load_profiles(context: "zaps_model", profiles_subid: profiles_subid, relay_id: relay_id, load: .from_events(events), damus_state: state, txn: txn)
|
||||
case .event(_, let ev):
|
||||
guard ev.kind == 9735,
|
||||
|
||||
Reference in New Issue
Block a user