2020-01-23 07:16:09 +03:00
|
|
|
{-|
|
2020-05-11 01:27:02 +03:00
|
|
|
Eyre: Http Server Driver
|
2019-08-04 00:38:30 +03:00
|
|
|
-}
|
|
|
|
|
2020-05-08 21:29:18 +03:00
|
|
|
module Urbit.Vere.Eyre
|
|
|
|
( eyre
|
2020-06-10 22:22:45 +03:00
|
|
|
, eyre'
|
2020-05-08 02:35:49 +03:00
|
|
|
)
|
|
|
|
where
|
2019-05-16 03:00:10 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
import Urbit.Prelude hiding (Builder)
|
2020-05-08 02:35:49 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
import Urbit.Arvo hiding (ServerId, reqUrl, secure)
|
2020-06-10 22:22:45 +03:00
|
|
|
import Urbit.King.App (HasKingId(..), HasPierEnv(..))
|
2020-05-08 02:35:49 +03:00
|
|
|
import Urbit.King.Config
|
2020-05-13 22:35:57 +03:00
|
|
|
import Urbit.Vere.Eyre.Multi
|
2020-05-11 22:51:51 +03:00
|
|
|
import Urbit.Vere.Eyre.PortsFile
|
2020-05-11 01:27:02 +03:00
|
|
|
import Urbit.Vere.Eyre.Serv
|
2020-05-11 22:51:51 +03:00
|
|
|
import Urbit.Vere.Eyre.Service
|
|
|
|
import Urbit.Vere.Eyre.Wai
|
2020-01-24 08:28:38 +03:00
|
|
|
import Urbit.Vere.Pier.Types
|
2019-05-16 03:00:10 +03:00
|
|
|
|
2020-05-11 01:27:02 +03:00
|
|
|
import Data.List.NonEmpty (NonEmpty((:|)))
|
|
|
|
import Data.PEM (pemParseBS, pemWriteBS)
|
|
|
|
import RIO.Prelude (decodeUtf8Lenient)
|
|
|
|
import System.Random (randomIO)
|
|
|
|
import Urbit.Vere.Http (convertHeaders, unconvertHeaders)
|
2019-05-31 05:53:00 +03:00
|
|
|
|
2020-05-11 01:27:02 +03:00
|
|
|
import qualified Network.HTTP.Types as H
|
2019-05-24 02:58:18 +03:00
|
|
|
|
2019-08-02 09:56:42 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
-- Types -----------------------------------------------------------------------
|
2019-08-08 01:24:02 +03:00
|
|
|
|
2020-03-03 02:24:28 +03:00
|
|
|
type HasShipEnv e = (HasLogFunc e, HasNetworkConfig e, HasPierConfig e)
|
|
|
|
|
2019-12-19 22:30:09 +03:00
|
|
|
type ReqId = UD
|
2019-08-08 01:24:02 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
newtype Drv = Drv (MVar (Maybe Serv))
|
|
|
|
|
|
|
|
data SockOpts = SockOpts
|
|
|
|
{ soLocalhost :: Bool
|
|
|
|
, soWhich :: ServPort
|
2020-05-11 01:27:02 +03:00
|
|
|
}
|
2019-08-08 01:24:02 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
data PortsToTry = PortsToTry
|
|
|
|
{ pttSec :: SockOpts
|
|
|
|
, pttIns :: SockOpts
|
|
|
|
, pttLop :: SockOpts
|
|
|
|
}
|
2019-08-08 01:24:02 +03:00
|
|
|
|
|
|
|
data Serv = Serv
|
2020-05-11 01:27:02 +03:00
|
|
|
{ sServId :: ServId
|
|
|
|
, sConfig :: HttpServerConf
|
|
|
|
, sLop :: ServApi
|
|
|
|
, sIns :: ServApi
|
|
|
|
, sSec :: Maybe ServApi
|
|
|
|
, sPorts :: Ports
|
|
|
|
, sPortsFile :: FilePath
|
|
|
|
, sLiveReqs :: TVar LiveReqs
|
|
|
|
}
|
2019-08-08 01:24:02 +03:00
|
|
|
|
|
|
|
|
2019-08-02 09:56:42 +03:00
|
|
|
-- Utilities for Constructing Events -------------------------------------------
|
2019-08-02 08:07:20 +03:00
|
|
|
|
|
|
|
servEv :: HttpServerEv -> Ev
|
|
|
|
servEv = EvBlip . BlipEvHttpServer
|
|
|
|
|
|
|
|
bornEv :: KingId -> Ev
|
2020-05-11 22:51:51 +03:00
|
|
|
bornEv king = servEv $ HttpServerEvBorn (king, ()) ()
|
2019-08-02 08:07:20 +03:00
|
|
|
|
2019-08-08 01:24:02 +03:00
|
|
|
liveEv :: ServId -> Ports -> Ev
|
2020-05-11 22:51:51 +03:00
|
|
|
liveEv sId Ports {..} = servEv $ HttpServerEvLive (sId, ()) pHttp pHttps
|
2019-08-02 09:56:42 +03:00
|
|
|
|
2020-06-02 23:48:07 +03:00
|
|
|
cancelEv :: ServId -> ReqId -> EvErr
|
|
|
|
cancelEv sId reqId =
|
|
|
|
EvErr (servEv (HttpServerEvCancelRequest (sId, reqId, 1, ()) ())) cancelFailed
|
|
|
|
|
|
|
|
cancelFailed :: WorkError -> IO ()
|
|
|
|
cancelFailed _ = pure ()
|
2019-08-07 03:46:47 +03:00
|
|
|
|
2019-08-04 00:38:30 +03:00
|
|
|
reqEv :: ServId -> ReqId -> WhichServer -> Address -> HttpRequest -> Ev
|
2020-05-11 22:51:51 +03:00
|
|
|
reqEv sId reqId which addr req = case which of
|
|
|
|
Loopback -> servEv $ HttpServerEvRequestLocal (sId, reqId, 1, ())
|
|
|
|
$ HttpServerReq False addr req
|
|
|
|
_ -> servEv $ HttpServerEvRequest (sId, reqId, 1, ())
|
|
|
|
$ HttpServerReq (which == Secure) addr req
|
2019-05-25 02:03:46 +03:00
|
|
|
|
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
-- Based on Pier+Config, which ports should each server run? -------------------
|
2020-03-03 02:24:28 +03:00
|
|
|
|
|
|
|
httpServerPorts :: HasShipEnv e => Bool -> RIO e PortsToTry
|
|
|
|
httpServerPorts fak = do
|
|
|
|
ins <- view (networkConfigL . ncHttpPort . to (fmap fromIntegral))
|
|
|
|
sec <- view (networkConfigL . ncHttpsPort . to (fmap fromIntegral))
|
|
|
|
lop <- view (networkConfigL . ncLocalPort . to (fmap fromIntegral))
|
|
|
|
localMode <- view (networkConfigL . ncNetMode . to (== NMLocalhost))
|
|
|
|
|
|
|
|
let local = localMode || fak
|
|
|
|
|
|
|
|
let pttSec = case (sec, fak) of
|
2020-05-11 01:27:02 +03:00
|
|
|
(Just p , _ ) -> SockOpts local (SPChoices $ singleton p)
|
|
|
|
(Nothing, False) -> SockOpts local (SPChoices (443 :| [8443 .. 8453]))
|
|
|
|
(Nothing, True ) -> SockOpts local (SPChoices (8443 :| [8444 .. 8453]))
|
2020-03-03 02:24:28 +03:00
|
|
|
|
|
|
|
let pttIns = case (ins, fak) of
|
2020-05-11 01:27:02 +03:00
|
|
|
(Just p , _ ) -> SockOpts local (SPChoices $ singleton p)
|
|
|
|
(Nothing, False) -> SockOpts local (SPChoices (80 :| [8080 .. 8090]))
|
|
|
|
(Nothing, True ) -> SockOpts local (SPChoices (8080 :| [8081 .. 8090]))
|
2020-03-03 02:24:28 +03:00
|
|
|
|
|
|
|
let pttLop = case (lop, fak) of
|
2020-05-11 01:27:02 +03:00
|
|
|
(Just p , _) -> SockOpts local (SPChoices $ singleton p)
|
|
|
|
(Nothing, _) -> SockOpts local SPAnyPort
|
2020-03-03 02:24:28 +03:00
|
|
|
|
|
|
|
pure (PortsToTry { .. })
|
|
|
|
|
2020-04-30 22:13:14 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
-- Convert Between Urbit and WAI types. ----------------------------------------
|
|
|
|
|
|
|
|
parseTlsConfig :: (Key, Cert) -> Maybe TlsConfig
|
|
|
|
parseTlsConfig (PEM key, PEM certs) = do
|
|
|
|
let (cerByt, keyByt) = (wainBytes certs, wainBytes key)
|
|
|
|
pems <- pemParseBS cerByt & either (const Nothing) Just
|
|
|
|
(cert, chain) <- case pems of
|
|
|
|
[] -> Nothing
|
|
|
|
p : ps -> pure (pemWriteBS p, pemWriteBS <$> ps)
|
|
|
|
pure $ TlsConfig keyByt cert chain
|
|
|
|
where
|
|
|
|
wainBytes :: Wain -> ByteString
|
|
|
|
wainBytes = encodeUtf8 . unWain
|
2020-05-08 02:35:49 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
parseHttpEvent :: HttpEvent -> [RespAct]
|
|
|
|
parseHttpEvent = \case
|
2020-05-08 02:35:49 +03:00
|
|
|
Start h b True -> [RAFull (hSta h) (hHdr h) (fByt $ fromMaybe "" b)]
|
|
|
|
Start h b False -> [RAHead (hSta h) (hHdr h) (fByt $ fromMaybe "" b)]
|
|
|
|
Cancel () -> [RADone]
|
|
|
|
Continue b done -> toList (RABloc . fByt <$> b)
|
|
|
|
<> if done then [RADone] else []
|
|
|
|
where
|
|
|
|
hHdr :: ResponseHeader -> [H.Header]
|
|
|
|
hHdr = unconvertHeaders . headers
|
|
|
|
|
|
|
|
hSta :: ResponseHeader -> H.Status
|
|
|
|
hSta = toEnum . fromIntegral . statusCode
|
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
fByt :: File -> ByteString
|
|
|
|
fByt = unOcts . unFile
|
|
|
|
|
|
|
|
requestEvent :: ServId -> WhichServer -> Word64 -> ReqInfo -> Ev
|
|
|
|
requestEvent srvId which reqId ReqInfo{..} = reqEv srvId reqUd which riAdr evReq
|
|
|
|
where
|
|
|
|
evBod = bodFile riBod
|
|
|
|
evHdr = convertHeaders riHdr
|
|
|
|
evUrl = Cord (decodeUtf8Lenient riUrl)
|
|
|
|
evReq = HttpRequest riMet evUrl evHdr evBod
|
|
|
|
reqUd = fromIntegral reqId
|
|
|
|
|
|
|
|
bodFile :: ByteString -> Maybe File
|
|
|
|
bodFile "" = Nothing
|
|
|
|
bodFile bs = Just $ File $ Octs bs
|
|
|
|
|
|
|
|
|
|
|
|
-- Running Servers -------------------------------------------------------------
|
|
|
|
|
|
|
|
execRespActs :: HasLogFunc e => Drv -> Ship -> Word64 -> HttpEvent -> RIO e ()
|
|
|
|
execRespActs (Drv v) who reqId ev = readMVar v >>= \case
|
|
|
|
Nothing -> logError "Got a response to a request that does not exist."
|
|
|
|
Just sv -> do
|
|
|
|
logTrace $ displayShow ev
|
|
|
|
for_ (parseHttpEvent ev) $ \act -> do
|
|
|
|
atomically (routeRespAct who (sLiveReqs sv) reqId act)
|
|
|
|
|
|
|
|
startServ
|
|
|
|
:: (HasPierConfig e, HasLogFunc e, HasNetworkConfig e)
|
|
|
|
=> MultiEyreApi
|
|
|
|
-> Ship
|
|
|
|
-> Bool
|
|
|
|
-> HttpServerConf
|
2020-06-02 23:48:07 +03:00
|
|
|
-> (EvErr -> STM ())
|
2020-05-11 22:51:51 +03:00
|
|
|
-> RIO e Serv
|
|
|
|
startServ multi who isFake conf plan = do
|
2020-05-13 01:43:09 +03:00
|
|
|
logTrace (displayShow ("EYRE", "startServ"))
|
2019-08-08 01:24:02 +03:00
|
|
|
|
2020-05-12 22:45:39 +03:00
|
|
|
let vLive = meaLive multi
|
|
|
|
|
2020-05-11 01:27:02 +03:00
|
|
|
srvId <- io $ ServId . UV . fromIntegral <$> (randomIO :: IO Word32)
|
2019-08-02 08:07:20 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
let mTls = hscSecure conf >>= parseTlsConfig
|
2019-05-25 02:03:46 +03:00
|
|
|
|
2020-05-13 01:43:09 +03:00
|
|
|
mCre <- mTls & \case
|
|
|
|
Nothing -> pure Nothing
|
|
|
|
Just tc -> configCreds tc & \case
|
2020-05-13 03:07:30 +03:00
|
|
|
Right rs -> pure (Just (tc, rs))
|
2020-05-13 01:43:09 +03:00
|
|
|
Left err -> do
|
|
|
|
logError "Couldn't Load TLS Credentials."
|
|
|
|
pure Nothing
|
|
|
|
|
2020-03-03 02:24:28 +03:00
|
|
|
ptt <- httpServerPorts isFake
|
2019-12-20 00:20:31 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
{-
|
|
|
|
TODO If configuration requests a redirect, get the HTTPS port (if
|
|
|
|
configuration specifies a specific port, use that. Otherwise, wait
|
|
|
|
for the HTTPS server to start and then use the port that it chose).
|
|
|
|
and run an HTTP server that simply redirects to the HTTPS server.
|
|
|
|
-}
|
|
|
|
let secRedi = Nothing
|
2020-05-11 01:27:02 +03:00
|
|
|
|
|
|
|
let soHost :: SockOpts -> ServHost
|
|
|
|
soHost so = if soLocalhost so then SHLocalhost else SHAnyHostOk
|
2019-08-22 04:18:10 +03:00
|
|
|
|
2020-05-13 02:55:49 +03:00
|
|
|
noHttp <- view (networkConfigL . ncNoHttp)
|
|
|
|
noHttps <- view (networkConfigL . ncNoHttps)
|
|
|
|
|
2020-06-02 23:48:07 +03:00
|
|
|
let reqEvFailed _ = pure ()
|
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
let onReq :: WhichServer -> Ship -> Word64 -> ReqInfo -> STM ()
|
|
|
|
onReq which _ship reqId reqInfo =
|
2020-06-02 23:48:07 +03:00
|
|
|
plan $ EvErr (requestEvent srvId which reqId reqInfo) reqEvFailed
|
2019-05-25 02:03:46 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
let onKilReq :: Ship -> Word64 -> STM ()
|
|
|
|
onKilReq _ship = plan . cancelEv srvId . fromIntegral
|
2019-08-08 01:24:02 +03:00
|
|
|
|
2020-05-13 01:43:09 +03:00
|
|
|
logTrace (displayShow ("EYRE", "joinMultiEyre", who, mTls, mCre))
|
|
|
|
|
|
|
|
atomically (joinMultiEyre multi who mCre onReq onKilReq)
|
2019-05-25 02:03:46 +03:00
|
|
|
|
2020-05-13 01:43:09 +03:00
|
|
|
logTrace $ displayShow ("EYRE", "Starting loopback server")
|
2020-05-11 01:27:02 +03:00
|
|
|
lop <- serv vLive $ ServConf
|
|
|
|
{ scHost = soHost (pttLop ptt)
|
|
|
|
, scPort = soWhich (pttLop ptt)
|
|
|
|
, scRedi = Nothing
|
2020-05-13 02:55:49 +03:00
|
|
|
, scFake = False
|
2020-05-11 22:51:51 +03:00
|
|
|
, scType = STHttp who $ ReqApi
|
|
|
|
{ rcReq = onReq Loopback
|
2020-05-11 01:27:02 +03:00
|
|
|
, rcKil = onKilReq
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-13 01:43:09 +03:00
|
|
|
logTrace $ displayShow ("EYRE", "Starting insecure server")
|
2020-05-11 01:27:02 +03:00
|
|
|
ins <- serv vLive $ ServConf
|
|
|
|
{ scHost = soHost (pttIns ptt)
|
|
|
|
, scPort = soWhich (pttIns ptt)
|
|
|
|
, scRedi = secRedi
|
2020-05-13 02:55:49 +03:00
|
|
|
, scFake = noHttp
|
2020-05-11 22:51:51 +03:00
|
|
|
, scType = STHttp who $ ReqApi
|
|
|
|
{ rcReq = onReq Insecure
|
2020-05-11 01:27:02 +03:00
|
|
|
, rcKil = onKilReq
|
|
|
|
}
|
|
|
|
}
|
2019-08-29 03:26:59 +03:00
|
|
|
|
2020-05-11 01:27:02 +03:00
|
|
|
mSec <- for mTls $ \tls -> do
|
|
|
|
logTrace "Starting secure server"
|
|
|
|
serv vLive $ ServConf
|
|
|
|
{ scHost = soHost (pttSec ptt)
|
|
|
|
, scPort = soWhich (pttSec ptt)
|
|
|
|
, scRedi = Nothing
|
2020-05-13 02:55:49 +03:00
|
|
|
, scFake = noHttps
|
2020-05-11 22:51:51 +03:00
|
|
|
, scType = STHttps who tls $ ReqApi
|
|
|
|
{ rcReq = onReq Secure
|
2020-05-11 01:27:02 +03:00
|
|
|
, rcKil = onKilReq
|
|
|
|
}
|
|
|
|
}
|
2019-08-08 01:24:02 +03:00
|
|
|
|
2019-12-17 17:31:50 +03:00
|
|
|
pierPath <- view pierPathL
|
2019-08-08 01:24:02 +03:00
|
|
|
|
2020-05-11 01:27:02 +03:00
|
|
|
lopPor <- atomically (fmap fromIntegral $ saPor lop)
|
|
|
|
insPor <- atomically (fmap fromIntegral $ saPor ins)
|
|
|
|
secPor <- for mSec (fmap fromIntegral . atomically . saPor)
|
|
|
|
|
|
|
|
let por = Ports secPor insPor lopPor
|
|
|
|
fil = pierPath <> "/.http.ports"
|
2019-07-22 21:10:27 +03:00
|
|
|
|
2020-05-11 01:27:02 +03:00
|
|
|
logTrace $ displayShow ("EYRE", "All Servers Started.", srvId, por, fil)
|
2019-08-02 09:56:42 +03:00
|
|
|
|
2020-05-11 22:51:51 +03:00
|
|
|
pure (Serv srvId conf lop ins mSec por fil vLive)
|
|
|
|
|
|
|
|
|
|
|
|
-- Eyre Driver -----------------------------------------------------------------
|
|
|
|
|
2020-06-10 22:22:45 +03:00
|
|
|
_bornFailed :: e -> WorkError -> IO ()
|
|
|
|
_bornFailed env _ = runRIO env $ do
|
2020-06-02 23:48:07 +03:00
|
|
|
pure () -- TODO What should this do?
|
|
|
|
|
2020-06-10 22:22:45 +03:00
|
|
|
eyre'
|
|
|
|
:: HasPierEnv e
|
|
|
|
=> MultiEyreApi
|
|
|
|
-> Ship
|
|
|
|
-> Bool
|
|
|
|
-> RIO e ([Ev], RAcquire e (DriverApi HttpServerEf))
|
|
|
|
eyre' multi who isFake = do
|
|
|
|
ventQ :: TQueue EvErr <- newTQueueIO
|
|
|
|
env <- ask
|
|
|
|
|
|
|
|
let (bornEvs, startDriver) = eyre env multi who (writeTQueue ventQ) isFake
|
|
|
|
|
|
|
|
let runDriver = do
|
|
|
|
diOnEffect <- startDriver
|
|
|
|
let diEventSource = fmap RRWork <$> tryReadTQueue ventQ
|
|
|
|
pure (DriverApi {..})
|
|
|
|
|
|
|
|
pure (bornEvs, runDriver)
|
|
|
|
|
|
|
|
{-|
|
|
|
|
Eyre -- HTTP Server Driver
|
|
|
|
|
|
|
|
Inject born events.
|
|
|
|
Until born events succeeds, ignore effects.
|
|
|
|
Wait until born event callbacks invoked.
|
|
|
|
If success, signal success.
|
|
|
|
If failure, try again several times.
|
|
|
|
If still failure, bring down ship.
|
|
|
|
Once born event succeeds:
|
|
|
|
- Begin normal operation (start accepting requests)
|
|
|
|
-}
|
2020-05-11 22:51:51 +03:00
|
|
|
eyre
|
|
|
|
:: forall e
|
2020-06-10 22:22:45 +03:00
|
|
|
. (HasPierEnv e)
|
2020-05-13 22:35:57 +03:00
|
|
|
=> e
|
2020-05-11 22:51:51 +03:00
|
|
|
-> MultiEyreApi
|
|
|
|
-> Ship
|
2020-06-02 23:48:07 +03:00
|
|
|
-> (EvErr -> STM ())
|
2020-05-11 22:51:51 +03:00
|
|
|
-> Bool
|
2020-06-10 22:22:45 +03:00
|
|
|
-> ([Ev], RAcquire e (HttpServerEf -> IO ()))
|
2020-05-13 22:35:57 +03:00
|
|
|
eyre env multi who plan isFake = (initialEvents, runHttpServer)
|
2020-05-11 22:51:51 +03:00
|
|
|
where
|
2020-05-13 22:35:57 +03:00
|
|
|
king = fromIntegral (env ^. kingIdL)
|
|
|
|
|
2020-06-10 22:22:45 +03:00
|
|
|
initialEvents :: [Ev]
|
|
|
|
initialEvents = [bornEv king]
|
2020-05-11 22:51:51 +03:00
|
|
|
|
2020-06-07 02:34:27 +03:00
|
|
|
runHttpServer :: RAcquire e (HttpServerEf -> IO ())
|
2020-05-11 22:51:51 +03:00
|
|
|
runHttpServer = handleEf <$> mkRAcquire
|
|
|
|
(Drv <$> newMVar Nothing)
|
|
|
|
(\(Drv v) -> stopService v kill >>= fromEither)
|
|
|
|
|
|
|
|
kill :: HasLogFunc e => Serv -> RIO e ()
|
|
|
|
kill Serv{..} = do
|
|
|
|
atomically (leaveMultiEyre multi who)
|
|
|
|
atomically (saKil sLop)
|
|
|
|
atomically (saKil sIns)
|
|
|
|
for_ sSec (\sec -> atomically (saKil sec))
|
|
|
|
io (removePortsFile sPortsFile)
|
|
|
|
|
|
|
|
restart :: Drv -> HttpServerConf -> RIO e Serv
|
|
|
|
restart (Drv var) conf = do
|
|
|
|
logDebug "Restarting http server"
|
|
|
|
let startAct = startServ multi who isFake conf plan
|
|
|
|
res <- fromEither =<< restartService var startAct kill
|
|
|
|
logDebug "Done restating http server"
|
|
|
|
pure res
|
|
|
|
|
2020-06-02 23:48:07 +03:00
|
|
|
liveFailed _ = pure ()
|
|
|
|
|
2020-06-07 02:34:27 +03:00
|
|
|
handleEf :: Drv -> HttpServerEf -> IO ()
|
|
|
|
handleEf drv = runRIO env . \case
|
2020-05-11 22:51:51 +03:00
|
|
|
HSESetConfig (i, ()) conf -> do
|
|
|
|
logDebug (displayShow ("EYRE", "%set-config"))
|
|
|
|
Serv {..} <- restart drv conf
|
|
|
|
logDebug (displayShow ("EYRE", "%set-config", "Sending %live"))
|
2020-06-02 23:48:07 +03:00
|
|
|
atomically $ plan (EvErr (liveEv sServId sPorts) liveFailed)
|
2020-05-11 22:51:51 +03:00
|
|
|
logDebug "Write ports file"
|
|
|
|
io (writePortsFile sPortsFile sPorts)
|
|
|
|
HSEResponse (i, req, _seq, ()) ev -> do
|
|
|
|
logDebug (displayShow ("EYRE", "%response"))
|
|
|
|
execRespActs drv who (fromIntegral req) ev
|