feat(chat): group chat RPCs and roster updates - #779
Merged
Merged
Conversation
Add service-layer support for the four new group-chat RPCs added to the Chat proto service: GetGroupChatFeed, StartChat, JoinChat, and LeaveChat. Each follows ChatService's existing plain Int-rawValue error pattern (ErrorGetGroupChatFeed/ErrorStartChat/ErrorJoinChat/ ErrorLeaveChat), with async FlipClient+Chat wrappers and TransportClassificationTests coverage. ErrorStartChat can't carry the server's flaggedCategory detail on .titleModerated since it stays a plain Int-rawValue enum for consistency with its ChatService siblings — callers only learn the title was rejected, not why. StartChat's group parameters need a wire form for ConversationRules, so add the domain-to-proto direction (ConversationRules, ConversationListenerRule, ConversationSpeakerRule, MinimumBalanceRequirement) alongside the existing proto-to-domain init. Wire the new RosterUpdate/RosterUpdateBatch messages into the event stream: decode them into DecodedRosterUpdate/RosterChange, apply them in ConversationStore by RosterSummary.version (drop if not greater), and handle self-join/self-leave in ConversationController — a join with an embedded chat snapshot inserts it into the feed directly, a leave naming the signed-in user removes it and deletes the local row via the new Database+Conversations.deleteConversation. ChatUpdate.new_messages (field 2) is unused on this client already, so its removal (now reserved) needs no changes here.
ErrorStartChat dropped the moderation category the server reports on TITLE_MODERATED, so a rejected title could only be reported as "rejected," not why. Android already surfaces this as StartChatError.TitleModerated(flaggedCategory); dropping it on iOS diverges from a contract both clients consume. Convert ErrorStartChat to an associated-value enum modelled on ErrorProfile, which already carries a FlaggedCategory the same way for ProfileService's moderation cases. .titleModerated(category) replaces the payload-less case; the plain-Int siblings (ErrorGetGroupChatFeed/ErrorJoinChat/ErrorLeaveChat) are unchanged since they have no payload to carry. ChatService.startChat now switches on the response result explicitly instead of rebuilding it via rawValue, through a new ErrorStartChat.init(_:flaggedCategory:) that maps StartChatResponse's proto Result to the domain error. Keeping this mapping as a pure, synchronous init (rather than inlining the switch in the async Task body) makes it unit-testable on its own, and means a case inserted upstream can no longer silently renumber this enum the way rawValue mapping could.
Group chat RPCs and roster updates need the 0.7.0 contract. The tag does not exist yet, so the exact requirement cannot resolve until it publishes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the client side of the flipcash2 group chat contract, and pins
flipcash2-client-protocolto0.7.0.Blocked on code-payments/flipcash2-client-protocol#13.
The
0.7.0tag does not exist yet, so theexact:requirement inFlipcashAPI/Package.swiftcannotresolve until that PR merges and publishes. Draft until then. The work was written and built against
the contract checkout through
FLIPCASH_PROTO_LOCAL, which CI never sees.What this adds
Four RPCs on
ChatServicewith matchingFlipClient+Chatwrappers:getGroupChatFeed,startChat,joinChat,leaveChat.ConversationRulesgained domain→proto mapping sostartChattakes a domain
ConversationRules?without leaking generated types across theFlipClientboundary.Roster updates —
ConversationStreamEventdecodesRosterUpdate/RosterUpdateBatch, andConversationStoreapplies them gated onRosterSummary.version, dropping anything not strictlygreater than the version it holds.
ConversationControllerhandles the two cases that concern thelocal user: joining inserts the conversation from the metadata snapshot the update carries, and
leaving removes it, which is what the new
ConversationStore.remove(_:)andDatabase+Conversations.deleteConversationare for.ChatUpdate.new_messagesmoving toreservedneeds nothing here — this client never read it.One note for review
ErrorStartChatis an associated-value enum carryingtitleModerated(Flipcash_Moderation_V1_FlaggedCategory),following
ErrorProfilerather than the plain-Int-rawValue shape of its three sibling enums in thisfile. The category is the only thing that says why a title was rejected, Android surfaces it too,
and flattening it would have left this client able to report only that the title was refused. A
ErrorStartChat.init(_:flaggedCategory:)does the mapping from the proto result, which also meansthis enum no longer reconstructs itself positionally from
rawValue— an upstream case insertioncan't silently renumber it.
Tested
Full
FlipcashCoresuite passes (950 tests, 125 suites) and./Scripts/build.shgives** BUILD SUCCEEDED **, both against the local contract checkout.