Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create MailboxLocalValues class to stop forgetting to pass values in initLocalValues() #2058

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

KevinBoulongne
Copy link
Contributor

@KevinBoulongne KevinBoulongne commented Sep 30, 2024

Depends on #2059

@KevinBoulongne KevinBoulongne changed the base branch from master to simplify-code September 30, 2024 12:47
@github-actions github-actions bot added the dependent This MR depends on another PR label Sep 30, 2024
@LunarX LunarX self-requested a review September 30, 2024 13:00
@LunarX LunarX marked this pull request as ready for review September 30, 2024 13:01
Comment on lines +95 to +122
fun setFeatureFlags(featureFlags: List<String>) {
mailboxLocalValues = local.copyFromRealm().also {
it.featureFlags.setFeatureFlags(featureFlags)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change isBimiEnabledLiveData's query so it directly queries the feature flags? This way we might be able to avoid the copyFromRealm in this setFeatureFlags method if it's only used to trigger the live data that observes the realm query

Copy link
Contributor Author

@KevinBoulongne KevinBoulongne Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't, it's an EmbeddedObject, we need to use its parent (ie. the Mailbox).

Comment on lines 380 to 381
it.local.externalMailFlagEnabled = externalMailInfo.externalMailFlagEnabled
it.local.trustedDomains = externalMailInfo.trustedDomains.toRealmList()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth bothering to only update the local values' object rather than updating all of the mailbox object in realm? Because here the only values we updates are inside the local values, not inside the whole mailbox.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this part of the code we have multiple spot where we modify the realm object the same way we do it for the local.featureFlags where we needed a copyFromRealm(). If we cannot remove the copyFromRealm() will we also need it in these places here?

Copy link
Contributor Author

@KevinBoulongne KevinBoulongne Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating like it's done here will correctly update data in Realm, but won't trigger any Flow if it's listening to the Mailbox, because the Mailbox itself won't be updated, only it's embeddedObject.

If we want to immediately broadcast this change to any Flow listening to this Mailbox, we need to update the data like we did in the other places, with the copyFromRealm() method.

Maybe it's better to always update it with copyFromRealm(), to be sure we don't miss it.
But I don't really like this idea. It will complicate the code everywhere (remember that we need to do this change for every Realm object that has a initLocalValues() function).

I'm starting to think it's better to drop this PR instead of complicating the code and risking to forget to update correctly.
The issue was that we could forget some parameters in initLocalValues(), and now the issue is that we can forget to correctly broadcast values updates.
The issue is the same, but somewhere else and with more code complexity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this doesn't work, it indeed introduces a new equivalent problem. It'd be even worse at that.

But I'd be very surprised if Realm didn't create a way to listen to items in a DB and get notified when they change even in this situation. We should talk about it in person and maybe even talk about it with @sirambd

@@ -31,7 +31,7 @@ class SignatureController @Inject constructor(

//region Get data
fun getSignaturesAsync(mailboxObjectId: String): Flow<RealmList<Signature>> {
return mailboxController.getMailboxAsync(mailboxObjectId).mapNotNull { it.obj?.signatures }
return mailboxController.getMailboxAsync(mailboxObjectId).mapNotNull { it.obj?.local?.signatures }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth it to query the whole mailbox when we only need the local values' object? (This pattern appears in other controllers as well)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an EmbeddedObject, we can't query it directly.

Copy link
Contributor

@LunarX LunarX Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What? I asked @sirambd because I feared this exact situation and he told me we could. Maybe he did not understand what I meant

Copy link
Contributor Author

@KevinBoulongne KevinBoulongne Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can query it, but not directly.
There is no PrimaryKey to search for since it's an EmbeddedObject.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as we can query it indirectly by checking its parent's primary key, it should be enough. But I don't know to what extent this is feasible

@@ -99,19 +101,10 @@ class MailboxController @Inject constructor(
val remoteMailboxesIds = remoteMailboxes.map { remoteMailbox ->

SentryLog.d(RealmDatabase.TAG, "Mailboxes: Get current data")
val localMailbox = getMailbox(userId, remoteMailbox.mailboxId, realm = this)
val previousLocalValues = getMailbox(userId, remoteMailbox.mailboxId, realm = this)?.local?.copyFromRealm()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason that makes this copyFromRealm() required? How does it fix the bimi issue? Because I'm not sure I understand correctly how copyFromRealm() should properly be used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are replacing the mailboxLocalValues with another one that's coming from Realm.
We need to copyFromRealm() it if we want it to work.

Copy link
Contributor

@LunarX LunarX Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I figured we update the value here and apparently copyFromRealm() seems to be needed, but why? How does it work? What does it bring to the table? Why does it work? What's missing if we don't use it? How does it fix the bimi issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to copy the value from Realm to be able to put it back in Realm later.
If we don't, Realm crashes, that's all.

@@ -204,7 +204,7 @@ class NewMessageAiManager @Inject constructor(

fun observeAiFeatureFlagUpdates() {
newMessageViewModel.currentMailboxLive.observeNotNull(viewLifecycleOwner) { mailbox ->
val isAiEnabled = mailbox.featureFlags.contains(FeatureFlag.AI)
val isAiEnabled = mailbox.local.featureFlags.contains(FeatureFlag.AI)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This live data is only ever used to get the current mailbox to now if its local values has the ai flag, would it make sens to replace it with a live data that only returns ai's enabled status? You can still keep the currentMailboxLive as a private live data and map it in a second public isAiEnabled live data or something I guess. Or directly query the local values from realm without querying the whole mailbox if it makes sens

Copy link
Contributor Author

@KevinBoulongne KevinBoulongne Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an EmbeddedObject, we can't query it directly.

We can expose a LiveData that's named about the AI and not the Mailbox, if you want.
But that's not relevant for this PR.

@KevinBoulongne KevinBoulongne marked this pull request as draft October 1, 2024 07:31
@KevinBoulongne KevinBoulongne marked this pull request as ready for review October 1, 2024 07:47
@KevinBoulongne KevinBoulongne marked this pull request as draft October 1, 2024 08:52
@KevinBoulongne KevinBoulongne force-pushed the stop-forgetting-local-values branch 3 times, most recently from b1657cb to a96b542 Compare October 1, 2024 12:38
@KevinBoulongne KevinBoulongne force-pushed the simplify-code branch 2 times, most recently from 7d716d7 to cde8f48 Compare October 2, 2024 11:45
Base automatically changed from simplify-code to master October 4, 2024 07:18
@github-actions github-actions bot removed the dependent This MR depends on another PR label Oct 4, 2024
Copy link

github-actions bot commented Oct 4, 2024

This PR/issue depends on:

@KevinBoulongne KevinBoulongne force-pushed the stop-forgetting-local-values branch 4 times, most recently from 98d549c to 13066e0 Compare October 8, 2024 13:47
Copy link

sonarcloud bot commented Oct 10, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants