2019-06-25 04:10:41 +03:00
|
|
|
module Vere.Serf where
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
import ClassyPrelude
|
|
|
|
import Control.Lens
|
|
|
|
import Data.Void
|
|
|
|
|
2019-07-02 05:51:26 +03:00
|
|
|
import Noun
|
|
|
|
import Noun.Atom
|
|
|
|
import Noun.Jam hiding (jam)
|
|
|
|
import Noun.Jam.Fast (jam, jamBS)
|
|
|
|
import Noun.Poet
|
|
|
|
import Noun.Pill
|
2019-06-01 01:55:21 +03:00
|
|
|
import Vere.Pier.Types
|
|
|
|
import System.Process
|
|
|
|
|
2019-06-25 23:58:07 +03:00
|
|
|
import Foreign.Marshal.Alloc (alloca)
|
|
|
|
import System.Exit (ExitCode)
|
2019-06-18 02:47:20 +03:00
|
|
|
import Data.ByteString (hGet)
|
|
|
|
import Data.ByteString.Unsafe (unsafeUseAsCString)
|
|
|
|
import Foreign.Ptr (castPtr)
|
2019-06-25 23:58:07 +03:00
|
|
|
import Foreign.Storable (poke, peek)
|
|
|
|
|
|
|
|
import qualified Data.ByteString.Unsafe as BS
|
|
|
|
import qualified Urbit.Time as Time
|
|
|
|
import qualified Vere.Log as Log
|
2019-06-18 02:47:20 +03:00
|
|
|
|
|
|
|
|
2019-06-25 23:58:07 +03:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
{-
|
|
|
|
TODO:
|
|
|
|
- getInput :: STM (Writ ())
|
|
|
|
- onComputed :: Writ [Effect] -> STM ()
|
|
|
|
- onExit :: Serf -> IO ()
|
|
|
|
- task :: Async ()
|
|
|
|
-}
|
2019-06-25 04:10:41 +03:00
|
|
|
data Serf = Serf
|
2019-06-01 01:55:21 +03:00
|
|
|
{ sendHandle :: Handle
|
|
|
|
, recvHandle :: Handle
|
|
|
|
, process :: ProcessHandle
|
|
|
|
}
|
|
|
|
|
2019-06-01 03:21:44 +03:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
{-
|
|
|
|
TODO Think about how to handle process exit
|
|
|
|
TODO Tear down subprocess on exit? (terminiteProcess)
|
|
|
|
TODO `config` is a stub, fill it in.
|
|
|
|
-}
|
|
|
|
startSerfProcess :: FilePath -> IO Serf
|
|
|
|
startSerfProcess pier =
|
2019-06-02 00:49:21 +03:00
|
|
|
do
|
|
|
|
(Just i, Just o, _, p) <- createProcess pSpec
|
2019-06-25 04:10:41 +03:00
|
|
|
pure (Serf i o p)
|
2019-06-02 00:49:21 +03:00
|
|
|
where
|
2019-06-25 04:10:41 +03:00
|
|
|
chkDir = traceShowId pier
|
|
|
|
diskKey = ""
|
|
|
|
config = "0"
|
|
|
|
args = [chkDir, diskKey, config]
|
|
|
|
pSpec = (proc "urbit-worker" args)
|
|
|
|
{ std_in = CreatePipe
|
|
|
|
, std_out = CreatePipe
|
|
|
|
}
|
|
|
|
|
|
|
|
kill :: Serf -> IO ExitCode
|
2019-06-01 03:21:44 +03:00
|
|
|
kill w = do
|
|
|
|
terminateProcess (process w)
|
|
|
|
waitForProcess (process w)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
work :: Word64 -> Jam -> Atom
|
|
|
|
work id (Jam a) = jam $ toNoun (Cord "work", id, a)
|
|
|
|
|
2019-06-02 00:07:40 +03:00
|
|
|
newtype Job = Job Void
|
|
|
|
deriving newtype (Eq, Show, ToNoun, FromNoun)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
type EventId = Word64
|
|
|
|
|
2019-06-01 03:21:44 +03:00
|
|
|
newtype Ship = Ship Word64 -- @p
|
2019-06-02 00:07:40 +03:00
|
|
|
deriving newtype (Eq, Ord, Show, ToNoun, FromNoun)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-02 00:07:40 +03:00
|
|
|
newtype ShipId = ShipId (Ship, Bool)
|
|
|
|
deriving newtype (Eq, Ord, Show, ToNoun, FromNoun)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-01 03:21:44 +03:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
type Play = Maybe (EventId, Mug, ShipId)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
data Plea
|
|
|
|
= Play Play
|
|
|
|
| Work EventId Mug Job
|
2019-06-28 00:28:58 +03:00
|
|
|
| Done EventId Mug [(Path, Eff)]
|
2019-06-01 01:55:21 +03:00
|
|
|
| Stdr EventId Cord
|
|
|
|
| Slog EventId Word32 Tank
|
2019-06-01 03:21:44 +03:00
|
|
|
deriving (Eq, Show)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-02 00:07:40 +03:00
|
|
|
instance ToNoun Plea where
|
|
|
|
toNoun = \case
|
|
|
|
Play p -> toNoun (Cord "play", p)
|
|
|
|
Work i m j -> toNoun (Cord "work", i, m, j)
|
2019-06-28 00:28:58 +03:00
|
|
|
Done i m o -> toNoun (Cord "done", i, m, o)
|
2019-06-02 00:07:40 +03:00
|
|
|
Stdr i msg -> toNoun (Cord "stdr", i, msg)
|
|
|
|
Slog i p t -> toNoun (Cord "slog", i, p, t)
|
|
|
|
|
2019-06-01 03:21:44 +03:00
|
|
|
instance FromNoun Plea where
|
2019-06-02 00:07:40 +03:00
|
|
|
parseNoun n =
|
|
|
|
parseNoun n >>= \case
|
|
|
|
(Cord "play", p) -> parseNoun p <&> \p -> Play p
|
|
|
|
(Cord "work", w) -> parseNoun w <&> \(i, m, j) -> Work i m j
|
|
|
|
(Cord "done", d) -> parseNoun d <&> \(i, m, o) -> Done i m o
|
|
|
|
(Cord "stdr", r) -> parseNoun r <&> \(i, msg) -> Stdr i msg
|
|
|
|
(Cord "slog", s) -> parseNoun s <&> \(i, p, t) -> Slog i p t
|
|
|
|
(Cord tag , s) -> fail ("Invalid plea tag: " <> unpack (decodeUtf8 tag))
|
2019-06-01 03:21:44 +03:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
type CompletedEventId = Word64
|
|
|
|
type NextEventId = Word64
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
type SerfState = (EventId, Mug)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-01 03:21:44 +03:00
|
|
|
type ReplacementEv = (EventId, Mug, Job)
|
2019-06-28 00:28:58 +03:00
|
|
|
type WorkResult = (EventId, Mug, [(Path, Eff)])
|
2019-06-25 04:10:41 +03:00
|
|
|
type SerfResp = (Either ReplacementEv WorkResult)
|
2019-06-01 03:21:44 +03:00
|
|
|
|
|
|
|
-- Exceptions ------------------------------------------------------------------
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
data SerfExn
|
2019-06-01 03:21:44 +03:00
|
|
|
= BadComputeId EventId WorkResult
|
|
|
|
| BadReplacementId EventId ReplacementEv
|
|
|
|
| UnexpectedPlay EventId Play
|
|
|
|
| BadPleaAtom Atom
|
2019-06-25 04:10:41 +03:00
|
|
|
| BadPleaNoun Noun Text
|
2019-06-18 02:47:20 +03:00
|
|
|
| ReplacedEventDuringReplay EventId ReplacementEv
|
2019-06-25 04:10:41 +03:00
|
|
|
| SerfConnectionClosed
|
2019-06-19 01:38:24 +03:00
|
|
|
| UnexpectedPleaOnNewShip Plea
|
|
|
|
| InvalidInitialPlea Plea
|
2019-06-01 03:21:44 +03:00
|
|
|
deriving (Show)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
instance Exception SerfExn
|
2019-06-01 03:21:44 +03:00
|
|
|
|
|
|
|
-- Utils -----------------------------------------------------------------------
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
printTank :: Word32 -> Tank -> IO ()
|
2019-06-25 23:58:07 +03:00
|
|
|
printTank pri t = print "[SERF] tank"
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-01 03:21:44 +03:00
|
|
|
guardExn :: Exception e => Bool -> e -> IO ()
|
|
|
|
guardExn ok = unless ok . throwIO
|
|
|
|
|
|
|
|
fromJustExn :: Exception e => Maybe a -> e -> IO a
|
|
|
|
fromJustExn Nothing exn = throwIO exn
|
|
|
|
fromJustExn (Just x) exn = pure x
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
fromRightExn :: Exception e => Either Text a -> (Text -> e) -> IO a
|
|
|
|
fromRightExn (Left m) exn = throwIO (exn m)
|
|
|
|
fromRightExn (Right x) _ = pure x
|
|
|
|
|
2019-06-01 03:21:44 +03:00
|
|
|
--------------------------------------------------------------------------------
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
sendAndRecv :: Serf -> EventId -> Atom -> IO SerfResp
|
2019-06-01 01:55:21 +03:00
|
|
|
sendAndRecv w eventId event =
|
|
|
|
do
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM ("sendAndRecv: " <> show eventId)
|
2019-07-01 07:47:21 +03:00
|
|
|
|
|
|
|
-- traceM ("<cue>")
|
|
|
|
-- traceM (maybe "bad cue" showNoun $ cue event)
|
|
|
|
-- traceM ("</cue>")
|
|
|
|
|
|
|
|
traceM ("<jam>")
|
|
|
|
wEv <- evaluate $ force $ work eventId (Jam event)
|
|
|
|
traceM ("</jam>")
|
|
|
|
|
|
|
|
sendAtom w wEv
|
2019-06-25 04:10:41 +03:00
|
|
|
res <- loop
|
2019-06-25 23:58:07 +03:00
|
|
|
traceM ("sendAndRecv.done " <> show res)
|
2019-06-25 04:10:41 +03:00
|
|
|
pure res
|
2019-06-01 01:55:21 +03:00
|
|
|
where
|
2019-06-25 04:10:41 +03:00
|
|
|
produce :: WorkResult -> IO SerfResp
|
2019-06-01 03:21:44 +03:00
|
|
|
produce (i, m, o) = do
|
2019-06-25 23:58:07 +03:00
|
|
|
guardExn (i == eventId) (BadComputeId eventId (i, m, o))
|
2019-06-01 03:21:44 +03:00
|
|
|
pure $ Right (i, m, o)
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
replace :: ReplacementEv -> IO SerfResp
|
2019-06-01 03:21:44 +03:00
|
|
|
replace (i, m, j) = do
|
2019-06-25 23:58:07 +03:00
|
|
|
guardExn (i == eventId) (BadReplacementId eventId (i, m, j))
|
2019-06-01 01:55:21 +03:00
|
|
|
pure (Left (i, m, j))
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
loop :: IO SerfResp
|
2019-06-01 03:21:44 +03:00
|
|
|
loop = recvPlea w >>= \case
|
|
|
|
Play p -> throwIO (UnexpectedPlay eventId p)
|
|
|
|
Done i m o -> produce (i, m, o)
|
|
|
|
Work i m j -> replace (i, m, j)
|
2019-06-25 23:58:07 +03:00
|
|
|
Stdr _ cord -> putStrLn (pack ("[SERF] " <> cordString cord)) >> loop
|
2019-06-01 03:21:44 +03:00
|
|
|
Slog _ pri t -> printTank pri t >> loop
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
sendBootEvent :: LogIdentity -> Serf -> IO ()
|
2019-06-19 01:38:24 +03:00
|
|
|
sendBootEvent id w = do
|
|
|
|
sendAtom w $ jam $ toNoun (Cord "boot", id)
|
2019-06-18 02:47:20 +03:00
|
|
|
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
-- the ship is booted, but it is behind. shove events to the worker until it is
|
|
|
|
-- caught up.
|
2019-06-25 04:10:41 +03:00
|
|
|
replayEvents :: Serf
|
|
|
|
-> SerfState
|
|
|
|
-> LogIdentity
|
|
|
|
-> EventId
|
|
|
|
-> (EventId -> Word64 -> IO (Vector (EventId, Atom)))
|
|
|
|
-> IO (EventId, Mug)
|
|
|
|
replayEvents w (wid, wmug) identity lastCommitedId getEvents = do
|
|
|
|
traceM ("replayEvents: " <> show wid <> " " <> show wmug)
|
|
|
|
|
2019-06-19 01:38:24 +03:00
|
|
|
when (wid == 1) (sendBootEvent identity w)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-19 03:04:57 +03:00
|
|
|
vLast <- newIORef (wid, wmug)
|
|
|
|
loop vLast wid
|
2019-06-25 04:10:41 +03:00
|
|
|
|
|
|
|
res <- readIORef vLast
|
|
|
|
traceM ("replayEvents.return " <> show res)
|
|
|
|
pure res
|
|
|
|
|
2019-06-18 02:47:20 +03:00
|
|
|
where
|
|
|
|
-- Replay events in batches of 1000.
|
2019-06-19 03:04:57 +03:00
|
|
|
loop vLast curEvent = do
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM ("replayEvents.loop: " <> show curEvent)
|
2019-06-18 02:47:20 +03:00
|
|
|
let toRead = min 1000 (1 + lastCommitedId - curEvent)
|
|
|
|
when (toRead > 0) do
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM ("replayEvents.loop.getEvents " <> show toRead)
|
|
|
|
|
2019-06-18 02:47:20 +03:00
|
|
|
events <- getEvents curEvent toRead
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM ("got events " <> show (length events))
|
|
|
|
|
2019-06-18 02:47:20 +03:00
|
|
|
for_ events $ \(eventId, event) -> do
|
|
|
|
sendAndRecv w eventId event >>= \case
|
2019-06-19 03:04:57 +03:00
|
|
|
Left ev -> throwIO (ReplacedEventDuringReplay eventId ev)
|
|
|
|
Right (id, mug, _) -> writeIORef vLast (id, mug)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-19 03:04:57 +03:00
|
|
|
loop vLast (curEvent + toRead)
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-19 01:38:24 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
bootSerf :: Serf -> LogIdentity -> Pill -> IO (EventId, Mug)
|
|
|
|
bootSerf w ident pill =
|
2019-06-19 01:38:24 +03:00
|
|
|
do
|
|
|
|
recvPlea w >>= \case
|
2019-06-25 04:10:41 +03:00
|
|
|
Play Nothing -> pure ()
|
|
|
|
x@(Play _) -> throwIO (UnexpectedPleaOnNewShip x)
|
|
|
|
x -> throwIO (InvalidInitialPlea x)
|
2019-06-19 01:38:24 +03:00
|
|
|
|
|
|
|
-- TODO: actually boot the pill
|
|
|
|
undefined
|
|
|
|
|
|
|
|
-- Maybe return the current event id ? But we'll have to figure that out
|
|
|
|
-- later.
|
2019-06-25 04:10:41 +03:00
|
|
|
pure undefined
|
2019-06-19 01:38:24 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
type GetEvents = EventId -> Word64 -> IO (Vector (EventId, Atom))
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
replay :: Serf -> LogIdentity -> EventId -> GetEvents -> IO (EventId, Mug)
|
|
|
|
replay w ident lastEv getEvents = do
|
|
|
|
ws@(eventId, mug) <- recvPlea w >>= \case
|
|
|
|
Play Nothing -> pure (1, Mug 0)
|
|
|
|
Play (Just (e, m, _)) -> pure (e, m)
|
|
|
|
x -> throwIO (InvalidInitialPlea x)
|
2019-06-18 02:47:20 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM ("got plea! " <> show eventId <> " " <> show mug)
|
2019-06-18 02:47:20 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
replayEvents w ws ident lastEv getEvents
|
2019-06-19 03:04:57 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
workerThread :: Serf -> STM Ovum -> (EventId, Mug) -> IO (Async ())
|
2019-06-19 03:04:57 +03:00
|
|
|
workerThread w getEvent (evendId, mug) = async $ forever do
|
|
|
|
ovum <- atomically $ getEvent
|
|
|
|
|
|
|
|
currentDate <- Time.now
|
|
|
|
|
|
|
|
let mat = jam (undefined (mug, currentDate, ovum))
|
2019-06-18 02:47:20 +03:00
|
|
|
|
2019-06-19 03:04:57 +03:00
|
|
|
undefined
|
2019-06-25 04:10:41 +03:00
|
|
|
|
2019-06-19 03:04:57 +03:00
|
|
|
-- Writ (eventId + 1) Nothing mat
|
|
|
|
-- -- assign a new event id.
|
|
|
|
-- -- assign a date
|
|
|
|
-- -- get current mug state
|
|
|
|
-- -- (jam [mug event])
|
2019-06-25 04:10:41 +03:00
|
|
|
-- sendAndRecv
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
requestSnapshot :: Serf -> IO ()
|
2019-06-18 02:47:20 +03:00
|
|
|
requestSnapshot w = undefined
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
-- The flow here is that we start the worker and then we receive a play event
|
|
|
|
-- with the current worker state:
|
|
|
|
--
|
|
|
|
-- <- [%play ...]
|
|
|
|
--
|
2019-06-25 04:10:41 +03:00
|
|
|
-- Base on this, the main flow is
|
2019-06-01 01:55:21 +03:00
|
|
|
--
|
|
|
|
|
|
|
|
-- [%work ] ->
|
|
|
|
-- <- [%slog]
|
|
|
|
-- <- [%slog]
|
|
|
|
-- <- [%slog]
|
|
|
|
-- <- [%work crash=tang]
|
|
|
|
-- [%work ] -> (replacement)
|
|
|
|
-- <- [%slog]
|
|
|
|
-- <- [%done]
|
2019-06-01 03:21:44 +03:00
|
|
|
-- [%work eventId mat]
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
-- response <- recvAtom w
|
|
|
|
|
|
|
|
|
2019-06-01 03:21:44 +03:00
|
|
|
-- Basic Send and Receive Operations -------------------------------------------
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-25 23:58:07 +03:00
|
|
|
withWord64AsByteString :: Word64 -> (ByteString -> IO a) -> IO a
|
|
|
|
withWord64AsByteString w k = do
|
|
|
|
alloca $ \wp -> do
|
|
|
|
poke wp w
|
|
|
|
bs <- BS.unsafePackCStringLen (castPtr wp, 8)
|
|
|
|
k bs
|
|
|
|
|
|
|
|
sendLen :: Serf -> Int -> IO ()
|
|
|
|
sendLen s i = do
|
|
|
|
traceM "sendLen.put"
|
|
|
|
w <- evaluate (fromIntegral i :: Word64)
|
|
|
|
withWord64AsByteString (fromIntegral i) (hPut (sendHandle s))
|
|
|
|
traceM "sendLen.done"
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
sendAtom :: Serf -> Atom -> IO ()
|
2019-06-25 23:58:07 +03:00
|
|
|
sendAtom s a = do
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM "sendAtom"
|
2019-06-25 23:58:07 +03:00
|
|
|
let bs = unpackAtom a
|
|
|
|
sendLen s (length bs)
|
|
|
|
hPut (sendHandle s) bs
|
|
|
|
hFlush (sendHandle s)
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM "sendAtom.return ()"
|
2019-06-01 01:55:21 +03:00
|
|
|
|
|
|
|
atomBytes :: Iso' Atom ByteString
|
|
|
|
atomBytes = pill . pillBS
|
|
|
|
|
|
|
|
packAtom = view (from atomBytes)
|
|
|
|
|
|
|
|
unpackAtom :: Atom -> ByteString
|
|
|
|
unpackAtom = view atomBytes
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
recvLen :: Serf -> IO Word64
|
2019-06-18 02:47:20 +03:00
|
|
|
recvLen w = do
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM "recvLen.wait"
|
2019-06-18 02:47:20 +03:00
|
|
|
bs <- hGet (recvHandle w) 8
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM "recvLen.got"
|
2019-06-18 02:47:20 +03:00
|
|
|
case length bs of
|
|
|
|
-- This is not big endian safe
|
|
|
|
8 -> unsafeUseAsCString bs (peek . castPtr)
|
2019-06-25 04:10:41 +03:00
|
|
|
_ -> throwIO SerfConnectionClosed
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
recvBytes :: Serf -> Word64 -> IO ByteString
|
|
|
|
recvBytes w = do
|
|
|
|
traceM "recvBytes"
|
|
|
|
hGet (recvHandle w) . fromIntegral
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
recvAtom :: Serf -> IO Atom
|
2019-06-01 01:55:21 +03:00
|
|
|
recvAtom w = do
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM "recvAtom"
|
2019-06-01 01:55:21 +03:00
|
|
|
len <- recvLen w
|
|
|
|
bs <- recvBytes w len
|
|
|
|
pure (packAtom bs)
|
|
|
|
|
2019-06-25 04:10:41 +03:00
|
|
|
cordString :: Cord -> String
|
|
|
|
cordString (Cord bs) = unpack $ decodeUtf8 bs
|
|
|
|
|
|
|
|
recvPlea :: Serf -> IO Plea
|
2019-06-01 01:55:21 +03:00
|
|
|
recvPlea w = do
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM "recvPlea"
|
|
|
|
|
2019-06-01 01:55:21 +03:00
|
|
|
a <- recvAtom w
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM ("recvPlea.cue " <> show (length $ a ^. atomBytes))
|
2019-06-01 03:21:44 +03:00
|
|
|
n <- fromJustExn (cue a) (BadPleaAtom a)
|
2019-06-25 04:10:41 +03:00
|
|
|
traceM "recvPlea.doneCue"
|
2019-07-01 07:47:21 +03:00
|
|
|
p <- fromRightExn (fromNounErr n) (BadPleaNoun (trace (showNoun n) n))
|
2019-06-25 04:10:41 +03:00
|
|
|
|
|
|
|
traceM "recvPlea.done"
|
|
|
|
|
|
|
|
-- TODO Hack!
|
|
|
|
case p of
|
2019-06-25 23:58:07 +03:00
|
|
|
Stdr e msg -> traceM ("[SERF] " <> cordString msg) >> recvPlea w
|
2019-06-25 04:10:41 +03:00
|
|
|
_ -> pure p
|