From 4d187d58eea91cc9bd4c00364264ab46dccf9169 Mon Sep 17 00:00:00 2001 From: Jens Nolte <git@queezle.net> Date: Sat, 23 Apr 2022 22:14:26 +0200 Subject: [PATCH] Change NetworkObject and NetworkReference types Splits value- and reference type behavior; reference types can now be initialized without sending data. --- src/Quasar/Network/Runtime.hs | 33 +++++----- src/Quasar/Network/Runtime/Observable.hs | 81 ++++++++++++++++++------ 2 files changed, 77 insertions(+), 37 deletions(-) diff --git a/src/Quasar/Network/Runtime.hs b/src/Quasar/Network/Runtime.hs index 887c15d..9c4f91e 100644 --- a/src/Quasar/Network/Runtime.hs +++ b/src/Quasar/Network/Runtime.hs @@ -80,41 +80,36 @@ instance IsChannel (Stream up down) where -- | Describes how a typeclass is used to send- and receive `NetworkObject`s. -class IsNetworkStrategy (s :: (Type -> Constraint)) where +type IsNetworkStrategy :: (Type -> Constraint) -> Constraint +class IsNetworkStrategy s where type ChannelIsRequired s :: Bool - sendObject :: forall a. (NetworkObject a, NetworkStrategy a ~ s) => a -> (Put, Maybe (Channel -> QuasarIO ())) - receiveObject :: forall a. (NetworkObject a, NetworkStrategy a ~ s) => Get (Either a (Channel -> QuasarIO a)) + sendObject :: forall a. (NetworkObject a, NetworkStrategy a ~ s) => a -> Either Put (Channel -> QuasarIO ()) + receiveObject :: forall a. (NetworkObject a, NetworkStrategy a ~ s) => Either (Get a) (Future Channel -> QuasarIO a) instance IsNetworkStrategy Binary where -- Copy by value by using `Binary` type ChannelIsRequired Binary = 'False - sendObject x = (put x, Nothing) - receiveObject = Left <$> get + sendObject x = Left (put x) + receiveObject = Left get instance IsNetworkStrategy NetworkReference where -- Send an object by reference with the `NetworkReference` class type ChannelIsRequired NetworkReference = 'True - sendObject :: forall a. (NetworkObject a, NetworkStrategy a ~ NetworkReference) => a -> (Put, Maybe (Channel -> QuasarIO ())) - sendObject x = (put cdata, Just (\channel -> fn (castChannel channel))) - where - (cdata, fn) = sendReference x + sendObject :: forall a. (NetworkObject a, NetworkStrategy a ~ NetworkReference) => a -> Either Put (Channel -> QuasarIO ()) + sendObject x = Right (\channel -> sendReference x (castChannel channel)) - receiveObject :: forall a. (NetworkObject a, NetworkStrategy a ~ NetworkReference) => Get (Either a (Channel -> QuasarIO a)) - receiveObject = Right . fn <$> get - where - fn :: ConstructorData a -> Channel -> QuasarIO a - fn cdata channel = receiveReference cdata (castChannel channel) + receiveObject :: forall a. (NetworkObject a, NetworkStrategy a ~ NetworkReference) => Either (Get a) (Future Channel -> QuasarIO a) + receiveObject = Right (\channel -> receiveReference (castChannel <$> channel)) class (IsNetworkStrategy (NetworkStrategy a), (NetworkStrategy a) a) => NetworkObject a where type NetworkStrategy a :: (Type -> Constraint) -class (Binary (ConstructorData a), IsChannel (NetworkReferenceChannel a)) => NetworkReference a where - type ConstructorData a +class IsChannel (NetworkReferenceChannel a) => NetworkReference a where type NetworkReferenceChannel a - sendReference :: a -> (ConstructorData a, NetworkReferenceChannel a -> QuasarIO ()) - receiveReference :: (ConstructorData a -> ReverseChannelType (NetworkReferenceChannel a) -> QuasarIO a) + sendReference :: a -> (NetworkReferenceChannel a -> QuasarIO ()) + receiveReference :: (Future (ReverseChannelType (NetworkReferenceChannel a)) -> QuasarIO a) instance NetworkObject Bool where @@ -132,6 +127,8 @@ instance NetworkObject Double where instance NetworkObject String where type NetworkStrategy String = Binary + + -- * Old internal RPC types class (Binary (ProtocolRequest p), Binary (ProtocolResponse p)) => RpcProtocol p where diff --git a/src/Quasar/Network/Runtime/Observable.hs b/src/Quasar/Network/Runtime/Observable.hs index 46217e4..805fe9c 100644 --- a/src/Quasar/Network/Runtime/Observable.hs +++ b/src/Quasar/Network/Runtime/Observable.hs @@ -1,3 +1,4 @@ +-- Contains the network instances for `Observable` (from the same family of libraries) {-# OPTIONS_GHC -Wno-orphans #-} module Quasar.Network.Runtime.Observable ( @@ -12,43 +13,85 @@ import Quasar.Network.Runtime import Quasar.Prelude -instance NetworkObject a => NetworkReference (Observable a) where - type ConstructorData (Observable a) = () - type NetworkReferenceChannel (Observable a) = Stream a Bool - sendReference :: Observable a -> ((), Stream a Bool -> QuasarIO ()) - sendReference observable = ((), undefined) - receiveReference :: ConstructorData (Observable a) -> Stream Bool a -> QuasarIO (Observable a) - receiveReference () channel = undefined - -instance NetworkObject a => NetworkObject (Observable a) where - type NetworkStrategy (Observable a) = NetworkReference +data ObservableRequest + = Start + | Stop - -data PackedObservableState a +data ObservableResponse a = PackedObservableValue a | PackedObservableLoading | PackedObservableNotAvailable PackedException deriving stock (Eq, Show, Generic) deriving anyclass (Binary) -packObservableState :: ObservableState r -> PackedObservableState r +packObservableState :: ObservableState r -> ObservableResponse r packObservableState (ObservableValue x) = PackedObservableValue x packObservableState ObservableLoading = PackedObservableLoading packObservableState (ObservableNotAvailable ex) = PackedObservableNotAvailable (packException ex) -unpackObservableState :: PackedObservableState r -> ObservableState r +unpackObservableState :: ObservableResponse r -> ObservableState r unpackObservableState (PackedObservableValue x) = ObservableValue x unpackObservableState PackedObservableLoading = ObservableLoading unpackObservableState (PackedObservableNotAvailable ex) = ObservableNotAvailable (unpackException ex) +instance NetworkObject a => NetworkReference (Observable a) where + type NetworkReferenceChannel (Observable a) = Stream (ObservableResponse a) ObservableRequest + sendReference = sendObservableReference + receiveReference = receiveObservableReference + +instance NetworkObject a => NetworkObject (Observable a) where + type NetworkStrategy (Observable a) = NetworkReference + + +data ProxyState + = Stopped + | Started + | StartRequestedWaitingForChannel + +data ObservableProxy a = + ObservableProxy { + channelFuture :: Future (Stream ObservableRequest (ObservableResponse a)), + proxyState :: TVar ProxyState, + prim :: ObservablePrim a + } + +sendObservableReference :: NetworkObject a => Observable a -> Stream (ObservableResponse a) ObservableRequest -> QuasarIO () +sendObservableReference observable = undefined + +receiveObservableReference :: NetworkObject a => Future (Stream ObservableRequest (ObservableResponse a)) -> QuasarIO (Observable a) +receiveObservableReference channelFuture = liftIO do + proxyState <- newTVarIO Stopped + prim <- newObservablePrimIO ObservableLoading + pure $ toObservable $ + ObservableProxy { + channelFuture, + proxyState, + prim + } + +instance NetworkObject a => IsRetrievable a (ObservableProxy a) where + retrieve proxy = undefined + + +instance NetworkObject a => IsObservable a (ObservableProxy a) where + observe proxy = undefined + pingObservable proxy = undefined + + + + + + +-- * Old code + data ObservableClient a = ObservableClient { quasar :: Quasar, beginRetrieve :: IO (Future a), - createObservableStream :: IO (Stream Void (PackedObservableState a)), + createObservableStream :: IO (Stream Void (ObservableResponse a)), observablePrim :: ObservablePrim a, - activeStreamVar :: TVar (Maybe (Stream Void (PackedObservableState a))) + activeStreamVar :: TVar (Maybe (Stream Void (ObservableResponse a))) } instance IsRetrievable a (ObservableClient a) where @@ -68,7 +111,7 @@ instance IsObservable a (ObservableClient a) where newObservableClient :: forall a. Binary a => IO (Future a) - -> IO (Stream Void (PackedObservableState a)) + -> IO (Stream Void (ObservableResponse a)) -> QuasarIO (Observable a) newObservableClient beginRetrieve createObservableStream = do quasar <- askQuasar @@ -104,7 +147,7 @@ callRetrieve :: Observable a -> QuasarIO (Future a) callRetrieve x = toFuture <$> async (retrieve x) -- | Used in generated code to call `observe`. -observeToStream :: forall a. Binary a => Observable a -> Stream (PackedObservableState a) Void -> QuasarIO () +observeToStream :: forall a. Binary a => Observable a -> Stream (ObservableResponse a) Void -> QuasarIO () observeToStream observable stream = do runQuasarIO (streamQuasar stream) do -- Initial state is defined as loading, no extra message has to be sent @@ -128,7 +171,7 @@ observeToStream observable stream = do (streamSendDeferred stream payloadHook) \ChannelNotConnected -> pure () where - payloadHook :: STM (PackedObservableState a) + payloadHook :: STM (ObservableResponse a) payloadHook = do writeTVar isLoading False swapTVar outbox Nothing >>= \case -- GitLab