packages feed

grapesy-1.0.0: kvstore/KVStore/API/Protobuf.hs

{-# OPTIONS_GHC -Wno-orphans #-}

module KVStore.API.Protobuf (client, server) where

import Network.GRPC.Client (rpc)
import Network.GRPC.Client qualified as Client
import Network.GRPC.Client.StreamType.IO qualified as Client
import Network.GRPC.Common
import Network.GRPC.Common.Protobuf
import Network.GRPC.Server qualified as Server
import Network.GRPC.Server.StreamType (Services(..), Methods(..))
import Network.GRPC.Server.StreamType qualified as Server
import Network.GRPC.Server.Protobuf qualified as Server

import Proto.Kvstore

import KVStore.API
import KVStore.Util.Profiling

{-------------------------------------------------------------------------------
  API
-------------------------------------------------------------------------------}

type Create   = Protobuf KeyValueService "create"
type Delete   = Protobuf KeyValueService "delete"
type Retrieve = Protobuf KeyValueService "retrieve"
type Update   = Protobuf KeyValueService "update"

{-------------------------------------------------------------------------------
  Metadata
-------------------------------------------------------------------------------}

type instance RequestMetadata          (Protobuf KeyValueService meth) = NoMetadata
type instance ResponseInitialMetadata  (Protobuf KeyValueService meth) = NoMetadata
type instance ResponseTrailingMetadata (Protobuf KeyValueService meth) = NoMetadata

{-------------------------------------------------------------------------------
  Client
-------------------------------------------------------------------------------}

client :: Client.Connection -> KVStore
client conn = KVStore {
      create   = fmap fromCreateResponse   . Client.nonStreaming conn (rpc @Create)   . createRequest
    , retrieve = fmap fromRetrieveResponse . Client.nonStreaming conn (rpc @Retrieve) . retrieveRequest
    , update   = fmap fromUpdateResponse   . Client.nonStreaming conn (rpc @Update)   . updateRequest
    , delete   = fmap fromDeleteResponse   . Client.nonStreaming conn (rpc @Delete)   . deleteRequest
    }

{-------------------------------------------------------------------------------
  Server
-------------------------------------------------------------------------------}

server :: KVStore -> [Server.SomeRpcHandler IO]
server kvstore =
    Server.fromServices $ Service methods NoMoreServices
  where
   methods :: Methods IO (Server.ProtobufMethodsOf KeyValueService)
   methods =
         Method (markNonStreaming "create"   $ fmap createResponse   . create   kvstore . fromCreateRequest)
       $ Method (markNonStreaming "delete"   $ fmap deleteResponse   . delete   kvstore . fromDeleteRequest)
       $ Method (markNonStreaming "retrieve" $ fmap retrieveResponse . retrieve kvstore . fromRetrieveRequest)
       $ Method (markNonStreaming "update"   $ fmap updateResponse   . update   kvstore . fromUpdateRequest)
       $ NoMoreMethods

{-------------------------------------------------------------------------------
  Marshalling
-------------------------------------------------------------------------------}

createRequest :: (Key, Value) -> Input Create
createRequest (Key key, Value value)  =
    defMessage
      & #key   .~ key
      & #value .~ value

fromCreateRequest :: Input Create -> (Key, Value)
fromCreateRequest req = (
      Key   $ req ^. #key
    , Value $ req ^. #value
    )

createResponse :: () -> Output Create
createResponse _ = defMessage

fromCreateResponse :: Output Create -> ()
fromCreateResponse _ = ()

retrieveRequest :: Key -> Input Retrieve
retrieveRequest (Key key) = defMessage & #key .~ key

fromRetrieveRequest :: Input Retrieve -> Key
fromRetrieveRequest req = Key $ req ^. #key

retrieveResponse :: Value -> Output Retrieve
retrieveResponse (Value value) = defMessage & #value .~ value

fromRetrieveResponse :: Output Retrieve -> Value
fromRetrieveResponse resp = Value $ resp ^. #value

updateRequest :: (Key, Value) -> Input Update
updateRequest (Key key, Value value) =
    defMessage
      & #key   .~ key
      & #value .~ value

fromUpdateRequest :: Input Update -> (Key, Value)
fromUpdateRequest req = (
      Key   $ req ^. #key
    , Value $ req ^. #value
    )

updateResponse :: () -> Output Update
updateResponse _ = defMessage

fromUpdateResponse :: Output Update -> ()
fromUpdateResponse _ = ()

deleteRequest :: Key -> Input Delete
deleteRequest (Key key) = defMessage & #key .~ key

fromDeleteRequest :: Input Delete -> Key
fromDeleteRequest req = Key $ req ^. #key

deleteResponse :: () -> Output Delete
deleteResponse _ = defMessage

fromDeleteResponse :: Output Delete -> ()
fromDeleteResponse _ = ()