capnp-0.17.0.0: lib/Capnp/Rpc/Revoke.hs
{-# LANGUAGE OverloadedStrings #-}
-- | Module: Capnp.Rpc.Revoke
-- Description: support for revocable capababilities
module Capnp.Rpc.Revoke
( makeRevocable,
)
where
import Capnp.Rpc.Errors (eFailed)
import qualified Capnp.Rpc.Membrane as Membrane
import Capnp.Rpc.Promise (breakPromise)
import qualified Capnp.Rpc.Server as Server
import Capnp.Rpc.Untyped (IsClient)
import Control.Concurrent.STM
import Control.Monad.STM.Class (MonadSTM, liftSTM)
import Supervisors (Supervisor)
-- | @'makeRevocable' sup cap@ returns a pair @(wrappedCap, revoke)@, such that
-- @wrappedCap@ is @cap@ wrapped by a membrane which forwards all method invocations
-- along until @revoke@ is executed, after which all methods that cross the membrane
-- (in either direction) will return errors.
--
-- Note that, as per usual with membranes, the membrane will wrap any objects returned
-- by method calls. So revoke cuts off access to the entire object graph reached through
-- @cap@.
makeRevocable :: (MonadSTM m, IsClient c) => Supervisor -> c -> m (c, STM ())
makeRevocable sup client = liftSTM $ do
isRevoked <- newTVar False
wrappedClient <- Membrane.enclose sup client (revokerPolicy isRevoked)
pure (wrappedClient, writeTVar isRevoked True)
revokerPolicy :: TVar Bool -> Membrane.Policy
revokerPolicy isRevoked _call = do
revoked <- readTVar isRevoked
pure $
if revoked
then Membrane.Handle revokedHandler
else Membrane.Forward
revokedHandler :: Server.UntypedMethodHandler
revokedHandler = Server.untypedHandler $ \_ response -> breakPromise response (eFailed "revoked")