packages feed

helic-0.1.0.0: lib/Helic/Net/Api.hs

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

import qualified Polysemy.Conc as Conc
import Polysemy.Conc (Events, Interrupt, Sync)
import Polysemy.Log (Log)
import Servant (Get, JSON, PostCreated, ReqBody, type (:<|>) ((:<|>)), type (:>))
import Servant.Server (Context (EmptyContext), ServerT)

import Helic.Data.Event (Event (Event, sender, source))
import Helic.Data.InstanceName (InstanceName)
import qualified Helic.Data.NetConfig as NetConfig
import Helic.Data.NetConfig (NetConfig)
import Helic.Effect.Agent (agentIdNet)
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] (Seq Event)
    :<|>
    ReqBody '[JSON] Event :> PostCreated '[JSON] ()
  )

-- |Publish a received event unless it was sent by the network agent of this instance.
receiveEvent ::
  Members [Events resource Event, Reader InstanceName] r =>
  Event ->
  Sem r ()
receiveEvent e@Event {sender, source} = do
  name <- ask
  unless (name == sender && source == agentIdNet) do
    Conc.publish e

-- |The server implementation.
server ::
  Members [Events resource Event, AtomicState (Seq Event), Reader InstanceName] r =>
  ServerT Api (Sem r)
server =
  atomicGet
  :<|>
  receiveEvent

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

-- |Run the daemon API.
serve ::
  Members [Events resource Event, Reader NetConfig] r =>
  Members [AtomicState (Seq Event), Reader InstanceName, Sync ServerReady, Log, Interrupt, Final IO] r =>
  Sem r ()
serve = do
  port <- asks NetConfig.port
  runServerWithContext @Api server EmptyContext (fromMaybe defaultPort port)