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.Class.Msgpack.Error (DecodeError)
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 DecodeError 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 DecodeError 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 DecodeError 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 ->
      (DecodeError -> RpcError) -> Either DecodeError a -> Sem r a
forall err' (r :: EffectRow) err a.
Member (Stop err') r =>
(err -> err') -> Either err a -> Sem r a
stopEitherWith DecodeError -> RpcError
RpcError.Decode (Object -> Either DecodeError 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 DecodeError a) -> Sem r a) ->
  Sem r a
handleCall :: forall a (r :: EffectRow).
RpcCall a
-> (Request -> (Object -> Either DecodeError a) -> Sem r a)
-> Sem r a
handleCall RpcCall a
call Request -> (Object -> Either DecodeError a) -> Sem r a
handle =
  RpcCall a -> Either a (Request, Object -> Either DecodeError a)
forall a.
RpcCall a -> Either a (Request, Object -> Either DecodeError a)
RpcCall.cata RpcCall a
call Either a (Request, Object -> Either DecodeError a)
-> (Either a (Request, Object -> Either DecodeError a) -> Sem r a)
-> Sem r a
forall a b. a -> (a -> b) -> b
& \case
    Right (Request
req, Object -> Either DecodeError a
decode) -> do
      Request -> (Object -> Either DecodeError a) -> Sem r a
handle Request
req Object -> Either DecodeError 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 DecodeError (ChannelId, ()))
    -> Sem r (ChannelId, ()))
-> Sem r (ChannelId, ())
forall a (r :: EffectRow).
RpcCall a
-> (Request -> (Object -> Either DecodeError 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 DecodeError (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 DecodeError 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 DecodeError 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 DecodeError a) -> Sem r a)
-> Sem r a
handleCall RpcCall x
call (Text
-> Request
-> (Object -> Either DecodeError 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 DecodeError 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 DecodeError 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 DecodeError a) -> Sem r a)
-> Sem r a
handleCall RpcCall a1
call (Text
-> Request
-> (Object -> Either DecodeError 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 DecodeError 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 DecodeError ())
    -> 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 DecodeError 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 DecodeError ()
_ -> 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