WPB-21964: move conversation creation to wire-subsystems#4977
WPB-21964: move conversation creation to wire-subsystems#4977blackheaven wants to merge 39 commits intodevelopfrom
Conversation
1e8e214 to
e7b9141
Compare
There was a problem hiding this comment.
Pull request overview
This PR refactors conversation creation logic by moving it from Galley to the wire-subsystems library, aligning with the architectural goal of separating concerns into reusable subsystems.
Changes:
- Moved conversation creation logic from
Galley.API.CreatetoWire.ConversationSubsystem.Interpreter - Relocated utility modules:
Galley.API.Error→Galley.Types.Error,Galley.API.One2One→Wire.ConversationSubsystem.One2One,Galley.API.Util→Wire.ConversationSubsystem.Util,Galley.Effects.ClientStore→Wire.Effects.ClientStore - Removed
Galley.Validationmodule (functionality moved to interpreter) - Updated background-worker to include new dependencies and error handlers
- Updated imports across numerous files to reflect module movements
Reviewed changes
Copilot reviewed 63 out of 64 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| services/galley/src/Galley/API/Create.hs | Simplified to delegate conversation creation to subsystem |
| libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs | New implementation containing conversation creation logic |
| libs/wire-subsystems/src/Wire/ConversationSubsystem/Util.hs | Utility functions moved from Galley |
| libs/wire-subsystems/src/Wire/ConversationSubsystem/Federation.hs | New module for federation-related conversation logic |
| libs/wire-subsystems/src/Wire/ConversationSubsystem/Types.hs | Configuration types for conversation subsystem |
| services/background-worker/src/Wire/BackgroundWorker/Jobs/Registry.hs | Updated to support new conversation subsystem dependencies |
| libs/galley-types/src/Galley/Types/Error.hs | Error types moved to galley-types library |
| services/galley/src/Galley/Effects.hs | Reordered effect stack and added new error types |
| Multiple import updates | Updated imports across ~30 files to reflect module movements |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
services/background-worker/src/Wire/BackgroundWorker/Jobs/Registry.hs
Outdated
Show resolved
Hide resolved
services/background-worker/src/Wire/BackgroundWorker/Jobs/Registry.hs
Outdated
Show resolved
Hide resolved
services/background-worker/src/Wire/BackgroundWorker/Jobs/Registry.hs
Outdated
Show resolved
Hide resolved
libs/wire-subsystems/src/Wire/ConversationSubsystem/Federation.hs
Outdated
Show resolved
Hide resolved
libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs
Outdated
Show resolved
Hide resolved
libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs
Outdated
Show resolved
Hide resolved
libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs
Outdated
Show resolved
Hide resolved
| . mapError (const ("Invalid input" :: Text) :: InvalidInput -> Text) | ||
| . mapError @MigrationError (T.pack . show) | ||
| . mapError @InternalError (TL.toStrict . internalErrorDescription) | ||
| . mapError @UnreachableBackends (T.pack . show) | ||
| . mapError @NonFederatingBackends (T.pack . show) | ||
| . mapError @TeamCollaboratorsError (const ("Team collaborators error" :: Text)) | ||
| . mapError @TeamFeatureStoreError (const ("Team feature store error" :: Text)) | ||
| . mapError @(Tagged OperationDenied ()) (const ("Operation denied" :: Text)) | ||
| . mapError @(Tagged 'NotATeamMember ()) (const ("Not a team member" :: Text)) | ||
| . mapError @(Tagged 'ConvAccessDenied ()) (const ("Conversation access denied" :: Text)) | ||
| . mapError @(Tagged 'NotConnected ()) (const ("Not connected" :: Text)) | ||
| . mapError @(Tagged 'MLSNotEnabled ()) (const ("MLS not enabled" :: Text)) | ||
| . mapError @(Tagged 'MLSNonEmptyMemberList ()) (const ("MLS non-empty member list" :: Text)) | ||
| . mapError @(Tagged 'MissingLegalholdConsent ()) (const ("Missing legalhold consent" :: Text)) | ||
| . mapError @(Tagged 'NonBindingTeam ()) (const ("Non-binding team" :: Text)) | ||
| . mapError @(Tagged 'NoBindingTeamMembers ()) (const ("No binding team members" :: Text)) | ||
| . mapError @(Tagged 'TeamNotFound ()) (const ("Team not found" :: Text)) | ||
| . mapError @(Tagged 'InvalidOperation ()) (const ("Invalid operation" :: Text)) | ||
| . mapError @(Tagged 'ConvNotFound ()) (const ("Conversation not found" :: Text)) | ||
| . mapError @(Tagged 'ChannelsNotEnabled ()) (const ("Channels not enabled" :: Text)) | ||
| . mapError @(Tagged 'NotAnMlsConversation ()) (const ("Not an MLS conversation" :: Text)) |
There was a problem hiding this comment.
This seems verbose and like some duplication. Don't we have instances for these somewhere. Can we reuse them? Or can this be extracted into a singel mapping function?
There was a problem hiding this comment.
in galley they are converted to http errors, should we somehow group them?
| let remoteDomains = void <$> snd (partitionQualified lusr $ newConv.newConvQualifiedUsers) | ||
| enforceFederationProtocol (baseProtocolToProtocol newConv.newConvProtocol) remoteDomains | ||
| checkFederationStatus (RemoteDomains $ Set.fromList remoteDomains) |
There was a problem hiding this comment.
I wonder if checking the federation status should be implemented in a Federation subsystem, and if the conversation subsystem interpreter should be using it instead of having this here? Should that be part of this PR, too?
There was a problem hiding this comment.
Does the new design answers your questions?
There was a problem hiding this comment.
I like the FederationSubsystem, however here we still have code that integrates conversation and federation subsystems, my understanding is that we want to remove this responsibility from the services (galley in this case).
There was a problem hiding this comment.
I strongly agree, but there are places we use it directly:
services/galley/src/Galley/API/Internal.hs:188:getFederationStatusservices/galley/src/Galley/API/Action.hs:585:enforceFederationProtocolservices/galley/src/Galley/API/Action.hs:607:checkFederationStatus
What should I do then?
7b92819 to
c7b2a42
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 79 out of 80 changed files in this pull request and generated 9 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| testInternalGetConfiguredFeatureFlags :: (HasCallStack) => App () | ||
| testInternalGetConfiguredFeatureFlags = do | ||
| response <- Internal.getConfiguredFeatureFlags | ||
| response.status `shouldMatchInt` 200 |
There was a problem hiding this comment.
Missing test implementation: The test case testInternalGetConfiguredFeatureFlags is added but there's no verification of the response content beyond the status code. Consider adding assertions to verify the structure and content of the returned feature flags to ensure the endpoint returns valid data.
libs/wire-subsystems/src/Wire/FederationSubsystem/Interpreter.hs
Outdated
Show resolved
Hide resolved
libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs
Outdated
Show resolved
Hide resolved
libs/wire-subsystems/src/Wire/ConversationSubsystem/Interpreter.hs
Outdated
Show resolved
Hide resolved
| let remoteDomains = void <$> snd (partitionQualified lusr $ newConv.newConvQualifiedUsers) | ||
| enforceFederationProtocol (baseProtocolToProtocol newConv.newConvProtocol) remoteDomains | ||
| checkFederationStatus (RemoteDomains $ Set.fromList remoteDomains) |
There was a problem hiding this comment.
I like the FederationSubsystem, however here we still have code that integrates conversation and federation subsystems, my understanding is that we want to remove this responsibility from the services (galley in this case).
|
@blackheaven some compilation error slipped in: (https://concourse.ops.zinfra.io/builds/118785733#L696f7b80:14799) |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sven Tennie <sven.tennie@wire.com>
Co-authored-by: Sven Tennie <sven.tennie@wire.com>
4d46c23 to
5d9b4f7
Compare
fisx
left a comment
There was a problem hiding this comment.
i'm not done, but i have read all the easy parts, and i'll keep reading for a little longer.
there are some types in wire-api that weren't there now, or that didn't have aeson instances. maybe add roundtrip tests, and possibly golden tests for those? especially if they are not fully implemented in schema-profunctor.
feel free to fix all my comments in separate PRs, or ignore them if they are not worth the trouble! :)
There was a problem hiding this comment.
shouldn't you say something about moving conversation stuff to wire-subsystems here?
| gundeck: | ||
| host: gundeck | ||
| port: 8080 | ||
| spar: |
There was a problem hiding this comment.
should this also be mentioned in the changelog?
| class FeatureFlagsToPair f cfgs where | ||
| featureFlagsToPair :: NP f cfgs -> [A.Pair] |
There was a problem hiding this comment.
| class FeatureFlagsToPair f cfgs where | |
| featureFlagsToPair :: NP f cfgs -> [A.Pair] | |
| class FeatureFlagsToPairs f cfgs where | |
| featureFlagsToPairs :: NP f cfgs -> [A.Pair] |
| firstConflictOrFullyConnected :: [Remote NonConnectedBackends] -> FederationStatus | ||
| firstConflictOrFullyConnected = |
There was a problem hiding this comment.
| firstConflictOrFullyConnected :: [Remote NonConnectedBackends] -> FederationStatus | |
| firstConflictOrFullyConnected = | |
| firstMissingConnectionOrFullyConnected :: [Remote NonConnectedBackends] -> FederationStatus | |
| firstMissingConnectionOrFullyConnected = |
this would make the explanation in the comment redundant.
| zusrMembership <- join <$> forM storedConv.metadata.cnvmTeam (TeamSubsystem.internalGetTeamMember (qUnqualified origUser)) | ||
| for_ zusrMembership $ \tm -> unless (tm `hasPermission` ModifyConvName) $ throwS @'InvalidOperation | ||
| cn <- rangeChecked (cupName action) | ||
| cn <- either (throw . InvalidRange . fromString) pure $ checkedEither (cupName action) |
| . runInputConst (e ^. cstate) | ||
| . mapError toResponse | ||
| . mapError toResponse | ||
| . mapError toResponse |
There was a problem hiding this comment.
maybe this is a good reason to invent callNTimesConscutively? :)
There was a problem hiding this comment.
These are various types, it can be a fun challenge to make a piece of code for this.
| NotConnectedDomains dom1 dom2 -> throw (NonFederatingBackends dom1 dom2) | ||
| GetFederationStatus req -> getFederationStatus' req | ||
| where | ||
| getFederationStatus' :: |
There was a problem hiding this comment.
the pattern in many other places in wire-subsystems is to call it getFederationStatusImpl and declare it at the top level of the module.
| GetFeatureConfigForTeam tid -> pure $ getFeatureConfigForTeamImpl configs tid | ||
| GetConfiguredFeatureFlags -> | ||
| pure $ | ||
| FeatureLegalHoldDisabledByDefault |
There was a problem hiding this comment.
isn't this the Default instance from Wire.API.Team.Feature? if not: why? could one be defined there, or just a defaultThing, without the type class complicating things?
|
I'll have a look, thanks for the review! |
fisx
left a comment
There was a problem hiding this comment.
still happy with everything, but i need to go. i'll continue reading later.
thoughts for next time: this PR was way too big (yes, i know, i'm no better :). i think some changes could have easily been factored out (federation subsystem?), and i'm tempted to that we need a rule to separate refactoring PRs from PRs that change semantics, and not mix both in one.
|
|
||
| ---------------------------------------------------------------------------- | ||
| -- Notifications | ||
| notifyConversationUpdated :: |
There was a problem hiding this comment.
| notifyConversationUpdated :: | |
| notifyConversationUpdated :: |
| let remoteDomains = void <$> snd (partitionQualified lusr $ newConv.newConvQualifiedUsers) | ||
| enforceFederationProtocol (baseProtocolToProtocol newConv.newConvProtocol) remoteDomains | ||
| checkFederationStatus (RemoteDomains $ Set.fromList remoteDomains) |
I know, I'm down the rabbit hole, it's an excerpt, of an excerpt, of an excerpt, of an excerpt, of a PR (not kidding). |
https://wearezeta.atlassian.net/browse/WPB-21964
Checklist
changelog.d