This commit redesigns the Ndb.swift interface with a focus on build-time
safety against crashes.
It removes the external usage of NdbTxn and SafeNdbTxn, restricting it
to be used only in NostrDB internal code.
This prevents dangerous and crash prone usages throughout the app, such
as holding transactions in a variable in an async function (which can
cause thread-based reference counting to incorrectly deinit inherited
transactions in use by separate callers), as well as holding unsafe
unowned values longer than the lifetime of their corresponding
transactions.
Closes: https://github.com/damus-io/damus/issues/3364
Changelog-Fixed: Fixed several crashes throughout the app
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
We have mechanisms in place to close NostrDB streams when the database needs to
close; however, there is a short time window where those streams are
closing down but the database still has its "open" property set to `true`,
which means that new NostrDB streams may open. If that happens, those
new streams will still be active when NostrDB gets closed down,
potentially causing memory crashes.
This was found by inspecting several crash logs and noticing that:
- most of the `ndb.close` calls are coming from the general
backgrounding task (not the last resort backgrounding task),
where all old tasks are guaranteed to have closed (we wait for all of
them to close before proceeding to closing NostrDB).
- the stack traces of the crashed threads show that, in most cases, the
stream crashes while they are in the query stage (which means that
those must have been very recently opened).
The issue was mitigated by signalling that NostrDB has closed (without
actually closing it) before cancelling any streaming tasks and officially
closing NostrDB. This way, new NostrDB streaming tasks will notice that
the database is closed and will wait for it to reopen.
No changelog entry is needed as this issue was introduced after our last public
release.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Since 991a4a8, the `make_actionbar_model` function introduced an async
call to populate the action bar data.
This surfaced a pre-existing problem where the action bar model would
reinstantiate in any SwiftUI render pass for the chat bubbles in
`ChatroomThreadView`. This issue was not visible before because the whole
computation happened directly on the main actor during the render,
maintaining the illusion of a stable entity. Since the computation was
moved to an async task (for performance and concurrency design reasons),
it caused the action bar items to reload in each render pass, causing
multiple re-renders and the jumpiness witnessed in the ticket.
The issue was addressed by making the action bar model initialization
happen within ChatEventView itself, and wrapping it on `StateObject` to
make that entity stable across re-renders.
This fixes an issue for an unreleased change, so no changelog entry is
necessary.
Changelog-None
Fixes: 991a4a8
Closes: https://github.com/damus-io/damus/issues/3270
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This fixes a crash that would occasionally occur when visiting profiles.
NdbTxn objects were being deinitialized on different threads from their
initialization, causing incorrect reference count decrements in thread-local
transaction dictionaries. This led to premature destruction of shared ndb_txn
C objects still in use by other tasks, resulting in use-after-free crashes.
The root cause is that Swift does not guarantee tasks resume on the same
thread after await suspension points, while NdbTxn's init/deinit rely on
thread-local storage to track inherited transaction reference counts.
This means that `NdbTxn` objects cannot be used in async functions, as
that may cause the garbage collector to deinitialize `NdbTxn` at the end
of such function, which may be running on a different thread at that
point, causing the issue explained above.
The fix in this case is to eliminate the `async` version of the
`NdbNoteLender.borrow` method, and update usages to utilize other
available methods.
Note: This is a rewrite of the fix in https://github.com/damus-io/damus/pull/3329
Note 2: This relates to the fix of an unreleased feature, so therefore no
changelog is needed.
Changelog-None
Co-authored-by: alltheseas <64376233+alltheseas@users.noreply.github.com>
Closes: https://github.com/damus-io/damus/issues/3327
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This PR simply replaces the purple ostrich in the side view with the Damus Logo.
As well as adding a gradient to the Purple text.
I think this better represents Damus Purple.
Changelog-Changed: Changed Damus Purple Side View logo and text
Signed-off-by: ericholguin <ericholguin@apache.org>
Note: This is an improvement on an unreleased feature, so no changelog
entry is needed.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
No changelog is needed because we already have changelog messages for
the features added.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This PR adds Live Streaming and Live Chat to Damus via Damus Labs.
Changelog-Added: Added live stream timeline
Changelog-Added: Added live chat timeline
Changelog-Added: Added ability to create live chat event
Changelog-Added: Damus Labs Toggle
Signed-off-by: ericholguin <ericholguin@apache.org>
`seen_event` set was not isolated, which lead to occasional race
conditions between different actors accessing it simultaneously, leading
to crashes.
Closes: https://github.com/damus-io/damus/issues/3311
Changelog-Fixed: Fixed an occasional random crash related to viewing profiles
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit adds a new event subscription task in HomeModel, one which
streams low volume but important filters from NostrDB.
This was done to address an issue where the contact filters in the
general handler task could yield too many notes from NostrDB, hitting
its limits and clipping off important events such as mute-lists, leading
to downstream issues such as unintended mute-list overrides.
This issue was not present since the last public release, therefore no
changelog entry is needed.
Changelog-None
Closes: https://github.com/damus-io/damus/issues/3256
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Some issues were encountered with this feature. Disabling it for now.
Once we have the full Damus Labs UI, we will add the feature there.
Changelog-Changed: Placed the Favorites feature behind a feature flag
Closes: https://github.com/damus-io/damus/issues/3304
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
It was noticed that occasionally the profile name at the event view
would not load to the user's display name.
The issue was fixed by adding a missing profile observer.
Issue introduced after our last public release, no need for changelog
entries.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Previously, the note content rendering logic would wait for the note
and its blocks to be available in NostrDB before displaying the parsed
version of the note to the user.
However, it is now possible to parse those on demand, and there are code
paths to ensure that it will do so if those parsed blocks are not
readily available from NostrDB.
Therefore, the wait is not necessary, and removing it fixes the delay we
have been experiencing.
The issue was likely introduced after the last public release, so no
changelog item is needed
Changelog-None
Closes: https://github.com/damus-io/damus/issues/3296
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This PR makes sure to not show the onboarding screens
when a user is logged in with an npub as it doesn't
make sense for them to see that.
Changelog-Fixes: Fixes issue where onboarding views are shown to npub users
Signed-off-by: ericholguin <ericholguin@apache.org>
This PR adds the new Damus Labs view.
This will allow us to make the new things we work on more prominent.
Any new features we want to iterate fast on and get to our users a lot faster
are perfect for Damus Labs. This will be exclusive to Damus Purple Subscribers.
Changelog-Added: Added Damus Labs
Signed-off-by: ericholguin <ericholguin@apache.org>
A race condition was identified where notes would get dropped if they
get indexed in the time window between when a query is made and the subscription is made.
The issue was fixed by making the subscribe call before making the query
call, to ensure we get all notes from that time when we perform the
query.
This dropped the failure rate for ndb subscription tests from about 20%
down to about 4%.
Local relay model issue was not publicly released, which is why the
changelog entry is "none".
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This attempts to reduce race conditions coming from Ndb streaming
functions that could lead to lost notes or crashes.
It does so by making two improvements:
1. Instead of callbacks, now the callback handler uses async streams,
which reduces the chances of a callback being called before the last
item was processed by the consumer.
2. The callback handler will now queue up received notes if there are
no listeners yet. This is helpful because we need to issue the
subscribe call to nostrdb before getting the subscription id and
setting up a listener, but in between that time nostrdb may still
send notes which would effectively get dropped without this queuing
mechanism.
Changelog-Fixed: Improved robustness in the part of the code that streams notes from nostrdb
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This may negatively impact performance, but improves accuracy and
prevents profile loading issues
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This fixes a hang during sign-up, which was caused by a change in
RelayPool handling code that would only send data to handlers with
matching subscription IDs.
It so happens that some handlers want to receive all notes, and they set
the filters to `nil` to achieve that.
Furthermore, some sign-up networking code was moved to prevent race conditions.
No changelog entry because the behaviour was not changed since the last
public release.
Changelog-None
Closes: https://github.com/damus-io/damus/issues/3254
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This is a large refactor that aims to improve performance by offloading
RelayPool computations into a separate actor outside the main thread.
This should reduce congestion on the main thread and thus improve UI
performance.
Also, the internal subscription callback mechanism was changed to use
AsyncStreams to prevent race conditions newly found in that area of the
code.
Changelog-Fixed: Added performance improvements to timeline scrolling
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This attempts to improve the performance of InnerTimelineView by
performing event filtering computations on "EventHolder.insert" instead
of on each view body re-render, to improve SwiftUI performance.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>