-
Notifications
You must be signed in to change notification settings - Fork 33
[WIP] Sequenced message request acceptance and message sending #583
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
base: dev
Are you sure you want to change the base?
[WIP] Sequenced message request acceptance and message sending #583
Conversation
mpretty-cyro
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So based on the comment about setting things up to support an array of Message objects there are a few things that would need to be updated:
- The
MessageSendJob.Detailsshould be updated to take/storemessages: [Message]andvariants: [Message.Variant]- Note: Since these are persisted we will need to keep the existing
message/variantvalues and add@deprecatedtags to them - the idea would be that we would remove them in a subsequent release (theMessageSendJobdoesn't stay in the database for too long so the backwards compatibility can probably be removed in the next release) - The decoding should be updated to load the single
message/variantvalues into themessages/variantsarray so that the backwards compatibility is localised intoMessageSendJob.Details
- Note: Since these are persisted we will need to keep the existing
- The
/sequenceand/batchAPIs have a limit of 20 requests, so we would need to handle that case (ie. if we try to send more than 20 messages at once then they should be split into multiple jobs - they would run into the race condition this is trying to solve, but with those numbers it's unlikely to actually be a problem) - The
messageTypevalue should be updated to just be a string of", "separated message types (shouldn't needupdatedMessageType) - The
attachmentStatelogic will need to check the state of attachments for each message and defer if any of them have pending uploads
| return nil | ||
| } | ||
|
|
||
| return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for this return nil as the code shouldn't be reachable due to the returns from the switch statement
| sentTimestampMs: UInt64(timestampMs) | ||
| ) | ||
|
|
||
| viewModel.dependencies[singleton: .storage] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are no longer returning a publisher, you should update both of these database queries so be synchronous (viewModel.dependencies[singleton: .storage].write { [dependencies = viewModel.dependencies] db in)
This would mostly be to avoid weird situations where something else in the code validates one of these changes has occurred before sending messages (I don't think there is a case like that at the moment, but one could be added in the future)
| else { return nil } | ||
|
|
||
| return viewModel.dependencies[singleton: .storage] | ||
| viewModel.dependencies[singleton: .storage] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably make the same change for the GroupUpdateInviteResponseMessage for consistency (I don't believe it has the same bug, but sending it as part of a /sequence is slightly more efficient and you already have the logic for it so it's not much more work) - will just need to update the function to return a generic Message instead of the MessageRequestResponse
| timestampMs: Int64 | ||
| ) -> AnyPublisher<Void, Never> { | ||
| timestampMs: Int64, | ||
| shouldSequenceMessageRequestResponse: Bool = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just thinking maybe it would be better to always return the MessageRequestResponse/GroupUpdateInviteResponseMessage and have the caller decide how to send it - ie. the sendMessage function would do the /sequence call, and in the acceptMessageRequest() function we would just call:
viewModel.dependencies[singleton: .storage].writeAsync { [dependencies = viewModel.dependencies] db in
try MessageSender.send(
db,
message: message,
interactionId: nil,
threadId: self.viewModel.threadData.threadId,
threadVariant: self.viewModel.threadData.threadVariant,
using: dependencies
)
}This would allow us to simplify the logic in approveMessageRequestIfNeeded because it would just always return a Message if one needed to be sent
| interactionId: Int64?, | ||
| to destination: Message.Destination, | ||
| isSyncMessage: Bool = false, | ||
| messageResponse: MessageRequestResponse? = nil, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just thinking - maybe it would be cleaner to make this function take an array of [(message: Message, interactionId: Int64?)] instead of an explicit messageResponse parameter (would make it more reusable for sending multiple messages at once)?
| threadId: String, | ||
| threadVariant: SessionThread.Variant, | ||
| isSyncMessage: Bool = false, | ||
| messageResponse: MessageRequestResponse? = nil, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the below comment this function would probably need to take additionalMessages: [(message: Message, interactionId: Int64?)]
Not ideal but would support the more generic "multi-sending" approach (you could also add a function which takes an array in Interaction but would still need the additionalMessages variant due to the MessageRequestResponse case 😞)
| let userSessionId: SessionId = dependencies[cache: .general].sessionId | ||
|
|
||
| // Convert and prepare the data for sending | ||
| let swarmPublicKey: String = { | ||
| switch details.destination { | ||
| case .contact(let publicKey): return publicKey | ||
| case .syncMessage: return userSessionId.hexString | ||
| case .closedGroup(let groupPublicKey): return groupPublicKey | ||
| case .openGroup, .openGroupInbox: preconditionFailure() | ||
| } | ||
| }() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is duplicating logic from the MessageSender, would be better to consolidate this to avoid the duplication (we have something similar in Authentication) you could add the following to Message.Destination and then just use try details.destination.swarmPublicKey(using: dependencies) both here and in MessageSender:
func swarmPublicKey(using dependencies Dependencies) throws -> String {
let userSessionId: SessionId = dependencies[cache: .general].sessionId
switch self {
case .contact(let publicKey): return publicKey
case .syncMessage: return userSessionId.hexString
case .closedGroup(let groupPublicKey): return groupPublicKey
case .openGroup, .openGroupInbox: throw MessageSenderError.invalidDestination
}
}Note: You will need to add a new MessageSenderError.invalidDestination error
Description