aboutsummaryrefslogtreecommitdiff
path: root/hsm-status
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2025-01-16 18:26:16 -0800
committerPaul Oliver <contact@pauloliver.dev>2025-01-17 19:16:43 -0800
commitdc6bf1472c930ff1448c419d3205148bce1b787e (patch)
treebe6c1e0544d1e9800b5f65a4e37017f505918f0c /hsm-status
parente3ea039428545e185b38c5633fe3576ab32f1f8e (diff)
Adds error and dummy-fail service
Diffstat (limited to 'hsm-status')
-rw-r--r--hsm-status/Hsm/Status/Error.hs13
-rw-r--r--hsm-status/Main.hs86
-rw-r--r--hsm-status/hsm-status.cabal39
3 files changed, 138 insertions, 0 deletions
diff --git a/hsm-status/Hsm/Status/Error.hs b/hsm-status/Hsm/Status/Error.hs
new file mode 100644
index 0000000..2853d6b
--- /dev/null
+++ b/hsm-status/Hsm/Status/Error.hs
@@ -0,0 +1,13 @@
+{-# LANGUAGE DeriveAnyClass #-}
+
+module Hsm.Status.Error
+ ( Error(Error)
+ ) where
+
+import Data.Binary (Binary)
+import Data.Text (Text)
+import GHC.Generics (Generic)
+
+data Error =
+ Error Int Text
+ deriving (Binary, Generic, Show)
diff --git a/hsm-status/Main.hs b/hsm-status/Main.hs
new file mode 100644
index 0000000..6220474
--- /dev/null
+++ b/hsm-status/Main.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE OverloadedRecordDot #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+import Data.Function ((&))
+import Data.Set (Set, singleton)
+import Data.Text (Text, pack)
+import Effectful (Eff, (:>), runEff)
+import Effectful.Log (Log, LogLevel(LogAttention), runLog)
+import Effectful.Reader.Static (Reader, ask, runReader)
+import Effectful.Resource (runResource)
+import Effectful.State.Static.Local (evalState)
+import Hsm.Core.App (launch)
+import Hsm.Core.Env (deriveFromYaml)
+import Hsm.Core.Fsm qualified as F
+import Hsm.Core.Zmq.Client (poll, runClient)
+import Hsm.GPIO (GPIO, GPIOEffect, runGPIO, toggle)
+import Hsm.Status.Error (Error(Error))
+import Streamly.Data.Fold qualified as S (drain)
+import Streamly.Data.Stream qualified as S (Stream, fold, mapM)
+import System.IO.Echo (withoutInputEcho)
+
+data Env = Env
+ { name :: Text
+ , gpioOk :: GPIO
+ , gpioError :: GPIO
+ , period :: Int
+ , subEps :: [Text]
+ , topics :: [Text]
+ }
+
+$(deriveFromYaml ''Env)
+
+result ::
+ Bool
+ -> F.FsmState [Error] Bool Env ()
+ -> [Error]
+ -> F.FsmOutput [Error] Bool Env ()
+result sta next es =
+ F.FsmOutput (Just $ F.FsmResult sta () next) (logError <$> es)
+ where
+ logError (Error code msg) =
+ ( LogAttention
+ , "Error received with code "
+ <> pack (show code)
+ <> " and message: "
+ <> msg)
+
+stateOk :: F.FsmState [Error] Bool Env ()
+stateOk =
+ F.FsmState "ok" $ \msg _ _ ->
+ if null msg
+ then result True stateOk msg
+ else result False stateError msg
+
+stateError :: F.FsmState [Error] Bool Env ()
+stateError = F.FsmState "error" $ \msg _ _ -> result False stateError msg
+
+handle ::
+ (GPIOEffect Bool :> es, Log :> es, Reader Env :> es)
+ => S.Stream (Eff es) Bool
+ -> Eff es ()
+handle = S.fold S.drain . S.mapM handler
+ where
+ handler sta = do
+ env <- ask @Env
+ toggle False sta [env.period, env.period, 0]
+
+mapper :: Env -> Bool -> Set GPIO
+mapper env True = singleton env.gpioOk
+mapper env False = singleton env.gpioError
+
+-- Status service blinks a GPIO pin periodically and listens for error
+-- messages. If an error is received it switches to a different pin.
+main :: IO ()
+main =
+ launch "status" withoutInputEcho $ \env logger level ->
+ (poll @_ @Error & F.fsm @_ @_ @Env @() & handle)
+ & runClient @Env
+ & runGPIO (mapper env)
+ & evalState ()
+ & evalState stateOk
+ & runLog env.name logger level
+ & runReader env
+ & runResource
+ & runEff
diff --git a/hsm-status/hsm-status.cabal b/hsm-status/hsm-status.cabal
new file mode 100644
index 0000000..64528bd
--- /dev/null
+++ b/hsm-status/hsm-status.cabal
@@ -0,0 +1,39 @@
+cabal-version: 3.4
+author: Paul Oliver
+build-type: Simple
+maintainer: contact@pauloliver.dev
+name: hsm-status
+version: 0.1.0.0
+
+library
+ build-depends:
+ , base
+ , binary
+ , text
+
+ exposed-modules: Hsm.Status.Error
+ ghc-options: -Wall -Wunused-packages
+ default-language: GHC2021
+
+executable status
+ build-depends:
+ , base
+ , binary
+ , containers
+ , echo
+ , effectful-core
+ , hsm-core
+ , hsm-gpio
+ , log-effectful
+ , resourcet-effectful
+ , streamly-core
+ , text
+
+ main-is: Main.hs
+ other-modules: Hsm.Status.Error
+ ghc-options: -Wall -Wunused-packages
+
+ if !arch(x86_64)
+ ghc-options: -optl=-mno-fix-cortex-a53-835769
+
+ default-language: GHC2021