-- |HTTP API of the Daemon, Internal
module Helic.Net.Api where

import Servant (Get, JSON, NoContent (NoContent), PostCreated, PutAccepted, ReqBody, type (:<|>) ((:<|>)), type (:>))
import Servant.Server (Context (EmptyContext), ServerT)

import Helic.Data.Event (Event)
import qualified Helic.Data.NetConfig as NetConfig
import Helic.Data.NetConfig (NetConfig)
import qualified Helic.Effect.History as History
import Helic.Effect.History (History)
import Helic.Net.Server (ServerReady, runServerWithContext)

-- |The Servant API of the daemon, providing endpoints for getting all events and creating one.
type Api =
  "event" :> (
    Get '[JSON] [Event]
    :<|>
    ReqBody '[JSON] Event :> PostCreated '[JSON] NoContent
    :<|>
    ReqBody '[JSON] Int :> PutAccepted '[JSON] (Maybe Event)
  )

-- |The server implementation.
server ::
  Member History r =>
  ServerT Api (Sem r)
server :: ServerT Api (Sem r)
server =
  Sem r [Event]
forall (r :: EffectRow). Member History r => Sem r [Event]
History.get
  Sem r [Event]
-> ((Event -> Sem r NoContent) :<|> (Int -> Sem r (Maybe Event)))
-> Sem r [Event]
   :<|> ((Event -> Sem r NoContent) :<|> (Int -> Sem r (Maybe Event)))
forall a b. a -> b -> a :<|> b
:<|>
  (NoContent
NoContent NoContent -> Sem r () -> Sem r NoContent
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$) (Sem r () -> Sem r NoContent)
-> (Event -> Sem r ()) -> Event -> Sem r NoContent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Event -> Sem r ()
forall (r :: EffectRow). Member History r => Event -> Sem r ()
History.receive
  (Event -> Sem r NoContent)
-> (Int -> Sem r (Maybe Event))
-> (Event -> Sem r NoContent) :<|> (Int -> Sem r (Maybe Event))
forall a b. a -> b -> a :<|> b
:<|>
  Int -> Sem r (Maybe Event)
forall (r :: EffectRow).
Member History r =>
Int -> Sem r (Maybe Event)
History.load

-- |The default port, 9500.
defaultPort :: Int
defaultPort :: Int
defaultPort =
  Int
9500

-- |Run the daemon API.
serve ::
  Members [History, Reader NetConfig, Sync ServerReady, Log, Interrupt, Final IO] r =>
  Sem r ()
serve :: Sem r ()
serve = do
  Maybe Int
port <- (NetConfig -> Maybe Int) -> Sem r (Maybe Int)
forall i j (r :: EffectRow).
Member (Reader i) r =>
(i -> j) -> Sem r j
asks NetConfig -> Maybe Int
NetConfig.port
  ServerT Api (Sem r) -> Context '[] -> Int -> Sem r ()
forall api (context :: [*]) (r :: EffectRow).
(HasServer api context,
 HasContextEntry
   (context .++ DefaultErrorFormatters) ErrorFormatters,
 Members '[Sync ServerReady, Log, Interrupt, Final IO] r) =>
ServerT api (Sem r) -> Context context -> Int -> Sem r ()
runServerWithContext @Api ServerT Api (Sem r)
forall (r :: EffectRow). Member History r => ServerT Api (Sem r)
server Context '[]
EmptyContext (Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
defaultPort Maybe Int
port)