From 070122683d0c9a11f9221ede93df0590bc28494d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Smr=C5=BE?= <roman.smrz@seznam.cz> Date: Sun, 19 Dec 2021 22:23:41 +0100 Subject: Service attributes --- erebos.cabal | 1 + src/Main.hs | 10 +++++----- src/Network.hs | 59 +++++++++++++++++++++++++++++++--------------------------- src/Service.hs | 33 ++++++++++++++++++++++---------- 4 files changed, 61 insertions(+), 42 deletions(-) diff --git a/erebos.cabal b/erebos.cabal index fd1db20..06d96eb 100644 --- a/erebos.cabal +++ b/erebos.cabal @@ -53,6 +53,7 @@ executable erebos TupleSections, TypeApplications, TypeFamilies + TypeFamilyDependencies -- other-extensions: build-depends: aeson >=1.4 && <1.6, diff --git a/src/Main.hs b/src/Main.hs index fcdb2c5..9dcbae9 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -129,11 +129,11 @@ interactiveLoop st opts = runInputT defaultSettings $ do _ -> str ++ "\n"; server <- liftIO $ do startServer (optServer opts) erebosHead extPrintLn - [ SomeService @AttachService Proxy - , SomeService @SyncService Proxy - , SomeService @ContactService Proxy - , SomeService @DirectMessage Proxy - , SomeService @DiscoveryService Proxy + [ someService @AttachService Proxy + , someService @SyncService Proxy + , someService @ContactService Proxy + , someService @DirectMessage Proxy + , someService @DiscoveryService Proxy ] peers <- liftIO $ newMVar [] diff --git a/src/Network.hs b/src/Network.hs index 5f7d823..6ace27b 100644 --- a/src/Network.hs +++ b/src/Network.hs @@ -365,33 +365,38 @@ startServer opt origHead logd' services = do (global, svcs) <- atomically $ (,) <$> takeTMVar svcStates <*> takeTMVar (peerServiceState peer) - case (maybe (someServiceEmptyState <$> find ((svc ==) . someServiceID) services) Just $ M.lookup svc svcs, - maybe (someServiceEmptyGlobalState <$> find ((svc ==) . someServiceID) services) Just $ M.lookup svc global) of - (Just (SomeServiceState (proxy :: Proxy s) s), - Just (SomeServiceGlobalState (_ :: Proxy gs) gs)) - | Just (Refl :: s :~: gs) <- eqT -> do - let inp = ServiceInput - { svcPeer = peer - , svcPeerIdentity = peerId - , svcServer = server - , svcPrintOp = atomically . logd - } - reloadHead origHead >>= \case - Nothing -> atomically $ do - logd $ "current head deleted" - putTMVar (peerServiceState peer) svcs - putTMVar svcStates global - Just h -> do - (rsp, (s', gs')) <- handleServicePacket h inp s gs (wrappedLoad ref :: Stored s) - when (not (null rsp)) $ do - sendToPeerList peer rsp - atomically $ do - putTMVar (peerServiceState peer) $ M.insert svc (SomeServiceState proxy s') svcs - putTMVar svcStates $ M.insert svc (SomeServiceGlobalState proxy gs') global - _ -> atomically $ do - logd $ "unhandled service '" ++ show (toUUID svc) ++ "'" - putTMVar (peerServiceState peer) svcs - putTMVar svcStates global + case find ((svc ==) . someServiceID) services of + Just service@(SomeService (proxy :: Proxy s) attr) -> + case (fromMaybe (someServiceEmptyState service) $ M.lookup svc svcs, + fromMaybe (someServiceEmptyGlobalState service) $ M.lookup svc global) of + ((SomeServiceState (_ :: Proxy ps) ps), + (SomeServiceGlobalState (_ :: Proxy gs) gs)) -> do + Just (Refl :: s :~: ps) <- return $ eqT + Just (Refl :: s :~: gs) <- return $ eqT + + let inp = ServiceInput + { svcAttributes = attr + , svcPeer = peer + , svcPeerIdentity = peerId + , svcServer = server + , svcPrintOp = atomically . logd + } + reloadHead origHead >>= \case + Nothing -> atomically $ do + logd $ "current head deleted" + putTMVar (peerServiceState peer) svcs + putTMVar svcStates global + Just h -> do + (rsp, (s', gs')) <- handleServicePacket h inp ps gs (wrappedLoad ref :: Stored s) + when (not (null rsp)) $ do + sendToPeerList peer rsp + atomically $ do + putTMVar (peerServiceState peer) $ M.insert svc (SomeServiceState proxy s') svcs + putTMVar svcStates $ M.insert svc (SomeServiceGlobalState proxy gs') global + _ -> atomically $ do + logd $ "unhandled service '" ++ show (toUUID svc) ++ "'" + putTMVar (peerServiceState peer) svcs + putTMVar svcStates global _ -> do atomically $ logd $ "service packet from peer with incomplete identity " ++ show (peerAddress peer) diff --git a/src/Service.hs b/src/Service.hs index eae43ec..90fd34a 100644 --- a/src/Service.hs +++ b/src/Service.hs @@ -1,6 +1,6 @@ module Service ( Service(..), - SomeService(..), someServiceID, + SomeService(..), someService, someServiceAttr, someServiceID, SomeServiceState(..), fromServiceState, someServiceEmptyState, SomeServiceGlobalState(..), fromServiceGlobalState, someServiceEmptyGlobalState, ServiceID, mkServiceID, @@ -38,6 +38,12 @@ class (Typeable s, Storable s, Typeable (ServiceState s), Typeable (ServiceGloba serviceID :: proxy s -> ServiceID serviceHandler :: Stored s -> ServiceHandler s () + type ServiceAttributes s = attr | attr -> s + type ServiceAttributes s = Proxy s + defaultServiceAttributes :: proxy s -> ServiceAttributes s + default defaultServiceAttributes :: ServiceAttributes s ~ Proxy s => proxy s -> ServiceAttributes s + defaultServiceAttributes _ = Proxy + type ServiceState s :: * type ServiceState s = () emptyServiceState :: proxy s -> ServiceState s @@ -51,10 +57,16 @@ class (Typeable s, Storable s, Typeable (ServiceState s), Typeable (ServiceGloba emptyServiceGlobalState _ = () -data SomeService = forall s. Service s => SomeService (Proxy s) +data SomeService = forall s. Service s => SomeService (Proxy s) (ServiceAttributes s) + +someService :: forall s proxy. Service s => proxy s -> SomeService +someService _ = SomeService @s Proxy (defaultServiceAttributes @s Proxy) + +someServiceAttr :: forall s. Service s => ServiceAttributes s -> SomeService +someServiceAttr attr = SomeService @s Proxy attr someServiceID :: SomeService -> ServiceID -someServiceID (SomeService s) = serviceID s +someServiceID (SomeService s _) = serviceID s data SomeServiceState = forall s. Service s => SomeServiceState (Proxy s) (ServiceState s) @@ -62,7 +74,7 @@ fromServiceState :: Service s => proxy s -> SomeServiceState -> Maybe (ServiceSt fromServiceState _ (SomeServiceState _ s) = cast s someServiceEmptyState :: SomeService -> SomeServiceState -someServiceEmptyState (SomeService p) = SomeServiceState p (emptyServiceState p) +someServiceEmptyState (SomeService p _) = SomeServiceState p (emptyServiceState p) data SomeServiceGlobalState = forall s. Service s => SomeServiceGlobalState (Proxy s) (ServiceGlobalState s) @@ -70,7 +82,7 @@ fromServiceGlobalState :: Service s => proxy s -> SomeServiceGlobalState -> Mayb fromServiceGlobalState _ (SomeServiceGlobalState _ s) = cast s someServiceEmptyGlobalState :: SomeService -> SomeServiceGlobalState -someServiceEmptyGlobalState (SomeService p) = SomeServiceGlobalState p (emptyServiceGlobalState p) +someServiceEmptyGlobalState (SomeService p _) = SomeServiceGlobalState p (emptyServiceGlobalState p) newtype ServiceID = ServiceID UUID @@ -79,8 +91,9 @@ newtype ServiceID = ServiceID UUID mkServiceID :: String -> ServiceID mkServiceID = maybe (error "Invalid service ID") ServiceID . U.fromString -data ServiceInput = ServiceInput - { svcPeer :: Peer +data ServiceInput s = ServiceInput + { svcAttributes :: ServiceAttributes s + , svcPeer :: Peer , svcPeerIdentity :: UnifiedIdentity , svcServer :: Server , svcPrintOp :: String -> IO () @@ -94,10 +107,10 @@ data ServiceHandlerState s = ServiceHandlerState , svcLocal :: Stored LocalState } -newtype ServiceHandler s a = ServiceHandler (ReaderT ServiceInput (WriterT [ServiceReply s] (StateT (ServiceHandlerState s) (ExceptT String IO))) a) - deriving (Functor, Applicative, Monad, MonadReader ServiceInput, MonadWriter [ServiceReply s], MonadState (ServiceHandlerState s), MonadError String, MonadIO) +newtype ServiceHandler s a = ServiceHandler (ReaderT (ServiceInput s) (WriterT [ServiceReply s] (StateT (ServiceHandlerState s) (ExceptT String IO))) a) + deriving (Functor, Applicative, Monad, MonadReader (ServiceInput s), MonadWriter [ServiceReply s], MonadState (ServiceHandlerState s), MonadError String, MonadIO) -handleServicePacket :: Service s => Head LocalState -> ServiceInput -> ServiceState s -> ServiceGlobalState s -> Stored s -> IO ([ServiceReply s], (ServiceState s, ServiceGlobalState s)) +handleServicePacket :: Service s => Head LocalState -> ServiceInput s -> ServiceState s -> ServiceGlobalState s -> Stored s -> IO ([ServiceReply s], (ServiceState s, ServiceGlobalState s)) handleServicePacket h input svc global packet = do let sstate = ServiceHandlerState { svcValue = svc, svcGlobal = global, svcLocal = headStoredObject h } ServiceHandler handler = serviceHandler packet -- cgit v1.2.3