diff --git a/services/federator/federator.cabal b/services/federator/federator.cabal index 0b26b11d71a..308f6966089 100644 --- a/services/federator/federator.cabal +++ b/services/federator/federator.cabal @@ -1,10 +1,10 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.2. +-- This file has been generated from package.yaml by hpack version 0.33.0. -- -- see: https://github.com/sol/hpack -- --- hash: 05e45399becaef2bbecfa958ec4d5633900e2e1d8e1c1a2e7ecd2afbdbc2404f +-- hash: 72597caf8878551b0609bfdc790852575f38db429ea5c83935a399c676ee3c2c name: federator version: 1.0.0 @@ -20,10 +20,10 @@ library exposed-modules: Federator.API Federator.App + Federator.Impl Federator.Options Federator.Run Federator.Types - Federator.Util other-modules: Paths_federator hs-source-dirs: @@ -35,14 +35,12 @@ library , aeson , base , bilge - , brig-types , bytestring-conversion , data-default , email-validate , errors , exceptions , extended - , galley-types , imports , lens , metrics-core @@ -60,6 +58,8 @@ library , wai , wai-utilities , warp + , wire-api + , wire-api-federation default-language: Haskell2010 executable federator @@ -75,7 +75,6 @@ executable federator , aeson , base , bilge - , brig-types , bytestring-conversion , data-default , email-validate @@ -83,7 +82,6 @@ executable federator , exceptions , extended , federator - , galley-types , imports , lens , metrics-core @@ -101,4 +99,6 @@ executable federator , wai , wai-utilities , warp + , wire-api + , wire-api-federation default-language: Haskell2010 diff --git a/services/federator/package.yaml b/services/federator/package.yaml index 892fe7194c8..6035999778c 100644 --- a/services/federator/package.yaml +++ b/services/federator/package.yaml @@ -12,14 +12,12 @@ dependencies: - aeson - base - bilge -- brig-types - bytestring-conversion - data-default - email-validate - errors - exceptions - extended -- galley-types - imports - lens - metrics-core @@ -38,6 +36,8 @@ dependencies: - wai - wai-utilities - warp +- wire-api +- wire-api-federation library: source-dirs: src executables: diff --git a/services/federator/src/Federator/API.hs b/services/federator/src/Federator/API.hs index 1ea46ddd105..ba5026aee23 100644 --- a/services/federator/src/Federator/API.hs +++ b/services/federator/src/Federator/API.hs @@ -17,53 +17,42 @@ -- You should have received a copy of the GNU Affero General Public License along -- with this program. If not, see . -module Federator.API where - -import Brig.Types.Client.Prekey -import Brig.Types.Test.Arbitrary () -import Data.Aeson.TH (deriveJSON) -import Data.Handle (Handle (..)) -import Data.Id (UserId) -import Data.Qualified -import Federator.Util +module Federator.API + ( Api (..), + module Fed, + ) +where + +import Data.Id (ConvId, UserId) +import Data.Qualified (Qualified) import Imports import Servant.API import Servant.API.Generic -import Test.QuickCheck +import Wire.API.Federation.API.Conversation as Fed hiding (Api) +import Wire.API.Federation.Event as Fed +import Wire.API.User.Client.Prekey (PrekeyBundle) -data API route = API - { _gapiSearch :: - route - :- "i" - :> "search" - -- QUESTION: what exactly should the query be? text + domain? - :> QueryParam' [Required, Strict] "q" (Qualified Handle) - :> Get '[JSON] FUser, - _gapiPrekeys :: +data Api route = Api + { _gapiPrekeys :: route :- "i" :> "users" - :> Capture "fqu" (Qualified UserId) + :> Capture "id" (Qualified UserId) :> "prekeys" - :> Get '[JSON] PrekeyBundle + -- FUTUREWORK(federation): + -- this should return a version of PrekeyBundle with qualified UserId, + -- defined in wire-api-federation + :> Get '[JSON] PrekeyBundle, + _gapiJoinConversationById :: + route + :- "i" + :> "conversations" + :> Capture "cnv" (Qualified ConvId) + :> "join" + :> ReqBody '[JSON] Fed.JoinConversationByIdRequest + :> Post '[JSON] (Fed.ConversationUpdateResult Fed.MemberJoin) } deriving (Generic) --- curl http://localhost:8097/i/search?q=wef@a.com; curl http://localhost:8097/i/users/`uuid`@example.com/prekeys - ---------------------------------------------------------------------- --- TODO: add roundtrip tests for *HttpApiData, *JSON, ... --- --- TODO: the client ids in the 'PrekeyBundle' aren't really needed here. do we want to make a --- new type for that, then? - -data FUser = FUser - { _fuGlobalHandle :: !(Qualified Handle), - _fuFQU :: !(Qualified UserId) - } - deriving (Eq, Show, Generic) - -deriveJSON (wireJsonOptions "_fu") ''FUser - -instance Arbitrary FUser where - arbitrary = FUser <$> arbitrary <*> arbitrary +-- FUTUREWORK: add roundtrip tests for *HttpApiData, *JSON, ... diff --git a/services/federator/src/Federator/App.hs b/services/federator/src/Federator/App.hs index 2c375802d91..f6dcd763ab2 100644 --- a/services/federator/src/Federator/App.hs +++ b/services/federator/src/Federator/App.hs @@ -1,5 +1,5 @@ +{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE RecordWildCards #-} -- This file is part of the Wire Server implementation. -- @@ -19,19 +19,66 @@ -- with this program. If not, see . module Federator.App - ( app, + ( AppT, + AppIO, + runAppT, + runAppResourceT, ) where -import Data.Proxy -import qualified Federator.API as API -import Federator.Types -import Network.Wai -import Servant.API.Generic -import Servant.Mock -import Servant.Server - -app :: Env -> Application -app _ = serve api (mock api Proxy) - where - api = Proxy @(ToServantApi API.API) +import Bilge (RequestId (unRequestId)) +import Bilge.RPC (HasRequestId (..)) +import Control.Error (ExceptT) +import Control.Lens (view) +import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow) +import Control.Monad.Trans.Resource (MonadUnliftIO, ResourceT, runResourceT, transResourceT) +import Federator.Types (Env, applog, requestId) +import Imports +import Servant.API.Generic () +import Servant.Server () +import System.Logger.Class as LC +import qualified System.Logger.Extended as Log + +-- FUTUREWORK: this code re-occurs in every service. introduce 'MkAppT' in types-common that +-- takes 'Env' as one more argument. +newtype AppT m a = AppT + { unAppT :: ReaderT Env m a + } + deriving newtype + ( Functor, + Applicative, + Monad, + MonadIO, + MonadThrow, + MonadCatch, + MonadMask, + MonadReader Env + ) + +type AppIO = AppT IO + +instance MonadIO m => LC.MonadLogger (AppT m) where + log l m = do + g <- view applog + r <- view requestId + Log.log g l $ field "request" (unRequestId r) ~~ m + +instance MonadIO m => LC.MonadLogger (ExceptT err (AppT m)) where + log l m = lift (LC.log l m) + +instance Monad m => HasRequestId (AppT m) where + getRequestId = view requestId + +instance MonadUnliftIO m => MonadUnliftIO (AppT m) where + withRunInIO inner = + AppT . ReaderT $ \r -> + withRunInIO $ \runner -> + inner (runner . flip runReaderT r . unAppT) + +runAppT :: Env -> AppT m a -> m a +runAppT e (AppT ma) = runReaderT ma e + +runAppResourceT :: ResourceT AppIO a -> AppIO a +runAppResourceT ma = do + e <- ask + liftIO . runResourceT $ transResourceT (runAppT e) ma diff --git a/services/federator/src/Federator/Util.hs b/services/federator/src/Federator/Impl.hs similarity index 57% rename from services/federator/src/Federator/Util.hs rename to services/federator/src/Federator/Impl.hs index c947f0e0e46..75a01c5c800 100644 --- a/services/federator/src/Federator/Util.hs +++ b/services/federator/src/Federator/Impl.hs @@ -1,3 +1,6 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE RecordWildCards #-} + -- This file is part of the Wire Server implementation. -- -- Copyright (C) 2020 Wire Swiss GmbH @@ -15,25 +18,20 @@ -- You should have received a copy of the GNU Affero General Public License along -- with this program. If not, see . -module Federator.Util - ( wireJsonOptions, +module Federator.Impl + ( app, ) where -import Data.Aeson as Aeson -import Imports - -dropPrefix :: String -> String -> Maybe String -dropPrefix pfx str = - if length pfx > length str - then Nothing - else case splitAt (length pfx) str of - (pfx', sfx) -> - if pfx' /= pfx - then Nothing - else Just sfx +import Data.Proxy +import qualified Federator.API as API +import Federator.Types +import Network.Wai +import Servant.API.Generic +import Servant.Mock +import Servant.Server --- | This is a partial function; totality of all calls must be verified by roundtrip tests on --- the aeson instances involved. -wireJsonOptions :: String -> Options -wireJsonOptions pfx = defaultOptions {fieldLabelModifier = fromJust . dropPrefix pfx . fmap toLower} +app :: Env -> Application +app _ = serve api (mock api Proxy) + where + api = Proxy @(ToServantApi API.Api) diff --git a/services/federator/src/Federator/Run.hs b/services/federator/src/Federator/Run.hs index 1744745e1f6..023bbd0956a 100644 --- a/services/federator/src/Federator/Run.hs +++ b/services/federator/src/Federator/Run.hs @@ -25,32 +25,20 @@ module Federator.Run -- * App Environment newEnv, closeEnv, - - -- * App Monad - AppT, - AppIO, - runAppT, - runAppResourceT, ) where -import Bilge (RequestId (unRequestId)) -import Bilge.RPC (HasRequestId (..)) -import Control.Error -import Control.Lens (view, (^.)) -import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow) -import Control.Monad.Trans.Resource +import Control.Lens ((^.)) import Data.Default (def) import qualified Data.Metrics.Middleware as Metrics import Data.Text (unpack) -import qualified Federator.App as App +import qualified Federator.Impl as Impl import Federator.Options as Opt import Federator.Types import Imports import Network.Wai (Application) import qualified Network.Wai.Handler.Warp as Warp import Network.Wai.Utilities.Server as Server -import System.Logger.Class as LC import qualified System.Logger.Extended as Log import Util.Options @@ -66,7 +54,7 @@ run opts = do mkApp :: Opts -> IO (Application, Env) mkApp opts = do env <- newEnv opts - pure (App.app env, env) + pure (Impl.app env, env) ------------------------------------------------------------------------------- -- Environment @@ -82,50 +70,3 @@ closeEnv :: Env -> IO () closeEnv e = do Log.flush $ e ^. applog Log.close $ e ^. applog - -------------------------------------------------------------------------------- --- App Monad - --- FUTUREWORK: this code re-occurs in every service. introduce 'MkAppT' in types-common that --- takes 'Env' as one more argument. -newtype AppT m a = AppT - { unAppT :: ReaderT Env m a - } - deriving - ( Functor, - Applicative, - Monad, - MonadIO, - MonadThrow, - MonadCatch, - MonadMask, - MonadReader Env - ) - -type AppIO = AppT IO - -instance MonadIO m => LC.MonadLogger (AppT m) where - log l m = do - g <- view applog - r <- view requestId - Log.log g l $ field "request" (unRequestId r) ~~ m - -instance MonadIO m => LC.MonadLogger (ExceptT err (AppT m)) where - log l m = lift (LC.log l m) - -instance Monad m => HasRequestId (AppT m) where - getRequestId = view requestId - -instance MonadUnliftIO m => MonadUnliftIO (AppT m) where - withRunInIO inner = - AppT . ReaderT $ \r -> - withRunInIO $ \runner -> - inner (runner . flip runReaderT r . unAppT) - -runAppT :: Env -> AppT m a -> m a -runAppT e (AppT ma) = runReaderT ma e - -runAppResourceT :: ResourceT AppIO a -> AppIO a -runAppResourceT ma = do - e <- ask - liftIO . runResourceT $ transResourceT (runAppT e) ma