module Ribosome.Host.Interpreter.Rpc where

import Data.MessagePack (Object)
import Exon (exon)
import qualified Polysemy.Log as Log
import qualified Polysemy.Process as Process
import Polysemy.Process (Process)

import Ribosome.Host.Data.ChannelId (ChannelId)
import Ribosome.Host.Data.Request (
  Request (Request, method),
  RequestId,
  TrackedRequest (TrackedRequest),
  arguments,
  formatReq,
  formatTrackedReq,
  )
import qualified Ribosome.Host.Data.Response as Response
import Ribosome.Host.Data.Response (Response)
import Ribosome.Host.Data.RpcCall (RpcCall (RpcCallRequest))
import qualified Ribosome.Host.Data.RpcError as RpcError
import Ribosome.Host.Data.RpcError (RpcError)
import qualified Ribosome.Host.Data.RpcMessage as RpcMessage
import Ribosome.Host.Data.RpcMessage (RpcMessage)
import qualified Ribosome.Host.Effect.Responses as Responses
import Ribosome.Host.Effect.Responses (Responses)
import qualified Ribosome.Host.Effect.Rpc as Rpc
import Ribosome.Host.Effect.Rpc (Rpc)
import qualified Ribosome.Host.RpcCall as RpcCall

request ::
   a o r .
  Members [Process RpcMessage o, Responses RequestId Response !! RpcError, Log, Stop RpcError] r =>
  Text ->
  Request ->
  (Object -> Either Text a) ->
  Sem r a
request :: forall a o (r :: EffectRow).
Members
  '[Process RpcMessage o, Responses RequestId Response !! RpcError,
    Log, Stop RpcError]
  r =>
Text -> Request -> (Object -> Either Text a) -> Sem r a
request Text
exec req :: Request
req@Request {RpcMethod
method :: RpcMethod
$sel:method:Request :: Request -> RpcMethod
method, [Object]
arguments :: [Object]
$sel:arguments:Request :: Request -> [Object]
arguments} Object -> Either Text a
decode = do
  RequestId
reqId <- Sem (Responses RequestId Response : r) RequestId -> Sem r RequestId
forall err (eff :: (* -> *) -> * -> *) (r :: EffectRow).
Members '[Resumable err eff, Stop err] r =>
InterpreterFor eff r
restop Sem (Responses RequestId Response : r) RequestId
forall k v (r :: EffectRow). Member (Responses k v) r => Sem r k
Responses.add
  let treq :: TrackedRequest
treq = RequestId -> Request -> TrackedRequest
TrackedRequest RequestId
reqId (Request -> Request
coerce Request
req)
  Text -> Sem r ()
forall (r :: EffectRow).
(HasCallStack, Member Log r) =>
Text -> Sem r ()
Log.trace [exon|#{exec} rpc: #{formatTrackedReq treq}|]
  RpcMessage -> Sem r ()
forall i o (r :: EffectRow).
Member (Process i o) r =>
i -> Sem r ()
Process.send (TrackedRequest -> RpcMessage
RpcMessage.Request TrackedRequest
treq)
  Sem (Responses RequestId Response : r) Response -> Sem r Response
forall err (eff :: (* -> *) -> * -> *) (r :: EffectRow).
Members '[Resumable err eff, Stop err] r =>
InterpreterFor eff r
restop (RequestId -> Sem (Responses RequestId Response : r) Response
forall k v (r :: EffectRow).
Member (Responses k v) r =>
k -> Sem r v
Responses.wait RequestId
reqId) Sem r Response -> (Response -> Sem r a) -> Sem r a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Response.Success Object
a ->
      (Text -> RpcError) -> Either Text a -> Sem r a
forall err' (r :: EffectRow) err a.
Member (Stop err') r =>
(err -> err') -> Either err a -> Sem r a
stopEitherWith Text -> RpcError
RpcError.Decode (Object -> Either Text a
decode Object
a)
    Response.Error Text
e ->
      RpcError -> Sem r a
forall e (r :: EffectRow) a. Member (Stop e) r => e -> Sem r a
stop (RpcMethod -> [Object] -> Text -> RpcError
RpcError.Api RpcMethod
method [Object]
arguments Text
e)

handleCall ::
  RpcCall a ->
  (Request -> (Object -> Either Text a) -> Sem r a) ->
  Sem r a
handleCall :: forall a (r :: EffectRow).
RpcCall a
-> (Request -> (Object -> Either Text a) -> Sem r a) -> Sem r a
handleCall RpcCall a
call Request -> (Object -> Either Text a) -> Sem r a
handle =
  RpcCall a -> Either a (Request, Object -> Either Text a)
forall a. RpcCall a -> Either a (Request, Object -> Either Text a)
RpcCall.cata RpcCall a
call Either a (Request, Object -> Either Text a)
-> (Either a (Request, Object -> Either Text a) -> Sem r a)
-> Sem r a
forall a b. a -> (a -> b) -> b
& \case
    Right (Request
req, Object -> Either Text a
decode) -> do
      Request -> (Object -> Either Text a) -> Sem r a
handle Request
req Object -> Either Text a
decode
    Left a
a ->
      a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a

fetchChannelId ::
  Member (AtomicState (Maybe ChannelId)) r =>
  Members [Process RpcMessage o, Responses RequestId Response !! RpcError, Log, Stop RpcError] r =>
  Sem r ChannelId
fetchChannelId :: forall (r :: EffectRow) o.
(Member (AtomicState (Maybe ChannelId)) r,
 Members
   '[Process RpcMessage o, Responses RequestId Response !! RpcError,
     Log, Stop RpcError]
   r) =>
Sem r ChannelId
fetchChannelId = do
  (ChannelId
cid, ()) <- RpcCall (ChannelId, ())
-> (Request
    -> (Object -> Either Text (ChannelId, ()))
    -> Sem r (ChannelId, ()))
-> Sem r (ChannelId, ())
forall a (r :: EffectRow).
RpcCall a
-> (Request -> (Object -> Either Text a) -> Sem r a) -> Sem r a
handleCall (Request -> RpcCall (ChannelId, ())
forall a. MsgpackDecode a => Request -> RpcCall a
RpcCallRequest (RpcMethod -> [Object] -> Request
Request RpcMethod
"nvim_get_api_info" [])) (Text
-> Request
-> (Object -> Either Text (ChannelId, ()))
-> Sem r (ChannelId, ())
forall a o (r :: EffectRow).
Members
  '[Process RpcMessage o, Responses RequestId Response !! RpcError,
    Log, Stop RpcError]
  r =>
Text -> Request -> (Object -> Either Text a) -> Sem r a
request Text
"sync")
  ChannelId
cid ChannelId -> Sem r () -> Sem r ChannelId
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ Maybe ChannelId -> Sem r ()
forall s (r :: EffectRow).
Member (AtomicState s) r =>
s -> Sem r ()
atomicPut (ChannelId -> Maybe ChannelId
forall a. a -> Maybe a
Just ChannelId
cid)

cachedChannelId ::
  Member (AtomicState (Maybe ChannelId)) r =>
  Members [Process RpcMessage o, Responses RequestId Response !! RpcError, Log, Stop RpcError] r =>
  Sem r ChannelId
cachedChannelId :: forall (r :: EffectRow) o.
(Member (AtomicState (Maybe ChannelId)) r,
 Members
   '[Process RpcMessage o, Responses RequestId Response !! RpcError,
     Log, Stop RpcError]
   r) =>
Sem r ChannelId
cachedChannelId =
  Sem r ChannelId
-> (ChannelId -> Sem r ChannelId)
-> Maybe ChannelId
-> Sem r ChannelId
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Sem r ChannelId
forall (r :: EffectRow) o.
(Member (AtomicState (Maybe ChannelId)) r,
 Members
   '[Process RpcMessage o, Responses RequestId Response !! RpcError,
     Log, Stop RpcError]
   r) =>
Sem r ChannelId
fetchChannelId ChannelId -> Sem r ChannelId
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe ChannelId -> Sem r ChannelId)
-> Sem r (Maybe ChannelId) -> Sem r ChannelId
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Sem r (Maybe ChannelId)
forall s (r :: EffectRow). Member (AtomicState s) r => Sem r s
atomicGet

interpretRpc ::
   o r .
  Member (AtomicState (Maybe ChannelId)) r =>
  Members [Responses RequestId Response !! RpcError, Process RpcMessage o, Log, Async] r =>
  InterpreterFor (Rpc !! RpcError) r
interpretRpc :: forall o (r :: EffectRow).
(Member (AtomicState (Maybe ChannelId)) r,
 Members
   '[Responses RequestId Response !! RpcError, Process RpcMessage o,
     Log, Async]
   r) =>
InterpreterFor (Rpc !! RpcError) r
interpretRpc =
  (forall x (r0 :: EffectRow).
 Rpc (Sem r0) x
 -> Tactical (Rpc !! RpcError) (Sem r0) (Stop RpcError : r) x)
-> InterpreterFor (Rpc !! RpcError) r
forall err (eff :: (* -> *) -> * -> *) (r :: EffectRow).
(forall x (r0 :: EffectRow).
 eff (Sem r0) x
 -> Tactical (Resumable err eff) (Sem r0) (Stop err : r) x)
-> InterpreterFor (Resumable err eff) r
interpretResumableH \case
    Rpc.Sync RpcCall x
call ->
      x
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
     (f x)
forall (f :: * -> *) a (e :: (* -> *) -> * -> *) (m :: * -> *)
       (r :: EffectRow).
Functor f =>
a -> Sem (WithTactics e f m r) (f a)
pureT (x
 -> Sem
      (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
      (f x))
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) x
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
     (f x)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< RpcCall x
-> (Request
    -> (Object -> Either Text x)
    -> Sem
         (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) x)
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) x
forall a (r :: EffectRow).
RpcCall a
-> (Request -> (Object -> Either Text a) -> Sem r a) -> Sem r a
handleCall RpcCall x
call (Text
-> Request
-> (Object -> Either Text x)
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) x
forall a o (r :: EffectRow).
Members
  '[Process RpcMessage o, Responses RequestId Response !! RpcError,
    Log, Stop RpcError]
  r =>
Text -> Request -> (Object -> Either Text a) -> Sem r a
request Text
"sync")
    Rpc.Async RpcCall a1
call Either RpcError a1 -> Sem r0 ()
use -> do
      Sem
  (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
  (Async (Maybe (f ())))
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Sem
   (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
   (Async (Maybe (f ())))
 -> Sem
      (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) ())
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
     (Async (Maybe (f ())))
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) ()
forall a b. (a -> b) -> a -> b
$ Sem
  (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
  (f ())
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
     (Async (Maybe (f ())))
forall (r :: EffectRow) a.
Member Async r =>
Sem r a -> Sem r (Async (Maybe a))
async do
        Either RpcError a1
a <- forall e (r :: EffectRow) a.
Sem (Stop e : r) a -> Sem r (Either e a)
runStop @RpcError (RpcCall a1
-> (Request
    -> (Object -> Either Text a1)
    -> Sem
         (Stop RpcError
            : WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
         a1)
-> Sem
     (Stop RpcError
        : WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
     a1
forall a (r :: EffectRow).
RpcCall a
-> (Request -> (Object -> Either Text a) -> Sem r a) -> Sem r a
handleCall RpcCall a1
call (Text
-> Request
-> (Object -> Either Text a1)
-> Sem
     (Stop RpcError
        : WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
     a1
forall a o (r :: EffectRow).
Members
  '[Process RpcMessage o, Responses RequestId Response !! RpcError,
    Log, Stop RpcError]
  r =>
Text -> Request -> (Object -> Either Text a) -> Sem r a
request Text
"async"))
        Sem r0 ()
-> Tactical (Rpc !! RpcError) (Sem r0) (Stop RpcError : r) ()
forall (m :: * -> *) a (e :: (* -> *) -> * -> *) (r :: EffectRow).
m a -> Tactical e m r a
runTSimple (Either RpcError a1 -> Sem r0 ()
use Either RpcError a1
a)
      Sem
  (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
  (f x)
forall (f :: * -> *) (e :: (* -> *) -> * -> *) (m :: * -> *)
       (r :: EffectRow).
Functor f =>
Sem (WithTactics e f m r) (f ())
unitT
    Rpc.Notify RpcCall a1
call -> do
      RpcCall ()
-> (Request
    -> (Object -> Either Text ())
    -> Sem
         (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) ())
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) ()
forall a (r :: EffectRow).
RpcCall a
-> (Request -> (Object -> Either Text a) -> Sem r a) -> Sem r a
handleCall (RpcCall a1 -> RpcCall ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void RpcCall a1
call) \ Request
req Object -> Either Text ()
_ -> do
        Text
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) ()
forall (r :: EffectRow).
(HasCallStack, Member Log r) =>
Text -> Sem r ()
Log.trace [exon|notify rpc: #{formatReq req}|]
        RpcMessage
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r)) ()
forall i o (r :: EffectRow).
Member (Process i o) r =>
i -> Sem r ()
Process.send (Request -> RpcMessage
RpcMessage.Notification Request
req)
      Sem
  (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
  (f x)
forall (f :: * -> *) (e :: (* -> *) -> * -> *) (m :: * -> *)
       (r :: EffectRow).
Functor f =>
Sem (WithTactics e f m r) (f ())
unitT
    Rpc (Sem r0) x
Rpc.ChannelId ->
      ChannelId
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
     (f ChannelId)
forall (f :: * -> *) a (e :: (* -> *) -> * -> *) (m :: * -> *)
       (r :: EffectRow).
Functor f =>
a -> Sem (WithTactics e f m r) (f a)
pureT (ChannelId
 -> Sem
      (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
      (f ChannelId))
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
     ChannelId
-> Sem
     (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
     (f ChannelId)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Sem
  (WithTactics (Rpc !! RpcError) f (Sem r0) (Stop RpcError : r))
  ChannelId
forall (r :: EffectRow) o.
(Member (AtomicState (Maybe ChannelId)) r,
 Members
   '[Process RpcMessage o, Responses RequestId Response !! RpcError,
     Log, Stop RpcError]
   r) =>
Sem r ChannelId
cachedChannelId