mirror of https://github.com/voidlizard/hbs2
wip
This commit is contained in:
parent
608a60eb85
commit
6b8cf74411
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
;;
|
||||||
|
|
||||||
|
(watch 30 (lwwref "BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP")
|
||||||
|
(run "./on-my-ref.sh")
|
||||||
|
)
|
||||||
|
|
||||||
|
(watch 10 (lwwref "BTThPdHKF8XnEq4m6wzbKHKA6geLFK4ydYhBXAqBdHSP")
|
||||||
|
(run "./on-my-ref2.sh")
|
||||||
|
)
|
||||||
|
|
||||||
|
(watch 10 (reflog "BKtvRLispCM9UuQqHaNxu4SEUzpQNQ3PeRNknecKGPZ6")
|
||||||
|
(run "./on-my-ref3.sh")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2,13 +2,22 @@
|
||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
import HBS2.Prelude.Plated
|
import HBS2.Prelude.Plated
|
||||||
|
import HBS2.Clock
|
||||||
|
import HBS2.OrDie
|
||||||
|
import HBS2.Hash
|
||||||
|
import HBS2.Data.Types.Refs
|
||||||
import HBS2.Net.Auth.Schema
|
import HBS2.Net.Auth.Schema
|
||||||
import HBS2.Polling
|
import HBS2.Polling
|
||||||
|
import HBS2.Misc.PrettyStuff
|
||||||
import HBS2.System.Dir
|
import HBS2.System.Dir
|
||||||
import HBS2.System.Logger.Simple.ANSI hiding (info)
|
import HBS2.System.Logger.Simple.ANSI hiding (info)
|
||||||
|
|
||||||
|
import HBS2.Peer.Proto.LWWRef
|
||||||
|
import HBS2.Peer.Proto.RefLog
|
||||||
|
|
||||||
import Data.Config.Suckless
|
import Data.Config.Suckless
|
||||||
|
|
||||||
|
import Data.Time.Clock
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Lens.Micro.Platform
|
import Lens.Micro.Platform
|
||||||
import System.Directory
|
import System.Directory
|
||||||
|
|
@ -17,37 +26,62 @@ import UnliftIO
|
||||||
import Options.Applicative
|
import Options.Applicative
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Either
|
import Data.Either
|
||||||
|
import Data.HashMap.Strict (HashMap)
|
||||||
|
import Data.HashMap.Strict qualified as HM
|
||||||
|
import Control.Monad.Trans.Cont
|
||||||
|
import Data.ByteString.Lazy.Char8 qualified as LBS
|
||||||
|
import Data.Text qualified as Text
|
||||||
|
import Codec.Serialise
|
||||||
|
import Streaming.Prelude qualified as S
|
||||||
|
|
||||||
{- HLINT ignore "Functor law" -}
|
{- HLINT ignore "Functor law" -}
|
||||||
|
|
||||||
|
type Config = [Syntax C]
|
||||||
|
|
||||||
|
data family Watcher r
|
||||||
|
|
||||||
|
type RLWW = LWWRefKey HBS2Basic
|
||||||
|
type RRefLog = RefLogKey HBS2Basic
|
||||||
|
|
||||||
|
newtype instance Watcher RRefLog =
|
||||||
|
WatchRefLog ( RRefLog -> [Syntax C] -> IO () )
|
||||||
|
|
||||||
|
newtype instance (Watcher (LWWRefKey HBS2Basic)) =
|
||||||
|
WatchLWWRef ( LWWRefKey HBS2Basic -> [Syntax C] -> IO () )
|
||||||
|
|
||||||
data FixerEnv = FixerEnv
|
data FixerEnv = FixerEnv
|
||||||
{ _config :: TVar [Syntax C]
|
{ _configFile :: Maybe FilePath
|
||||||
|
, _config :: TVar Config
|
||||||
|
, _onRefLog :: TVar ( HashMap RRefLog (NominalDiffTime, [Watcher RRefLog]) )
|
||||||
|
, _onLww :: TVar ( HashMap RLWW (NominalDiffTime, [Watcher RLWW]))
|
||||||
|
, _refLogLast :: TVar ( HashMap RRefLog HashRef )
|
||||||
|
, _lwwLast :: TVar ( HashMap RRefLog HashRef )
|
||||||
}
|
}
|
||||||
|
|
||||||
makeLenses ''FixerEnv
|
makeLenses ''FixerEnv
|
||||||
|
|
||||||
|
|
||||||
data Watch s =
|
|
||||||
WatchRefLog (PubKey 'Sign s)
|
|
||||||
deriving stock (Generic)
|
|
||||||
|
|
||||||
newtype FixerM m a = FixerM { runFixerM :: ReaderT FixerEnv m a }
|
newtype FixerM m a = FixerM { runFixerM :: ReaderT FixerEnv m a }
|
||||||
deriving newtype (Applicative, Functor, Monad, MonadIO, MonadReader FixerEnv, MonadUnliftIO)
|
deriving newtype (Applicative, Functor, Monad, MonadIO, MonadReader FixerEnv, MonadUnliftIO)
|
||||||
|
|
||||||
|
instance MonadIO m => HasConf (FixerM m) where
|
||||||
|
getConf = asks _config >>= readTVarIO
|
||||||
|
|
||||||
|
readConf :: MonadIO m => FilePath -> m [Syntax MegaParsec]
|
||||||
|
readConf fn = liftIO (readFile fn) <&> parseTop <&> fromRight mempty
|
||||||
|
|
||||||
withConfig :: MonadUnliftIO m => Maybe FilePath -> FixerM m () -> FixerM m ()
|
withConfig :: MonadUnliftIO m => Maybe FilePath -> FixerM m () -> FixerM m ()
|
||||||
withConfig cfgPath m = do
|
withConfig cfgPath m = do
|
||||||
defConfDir <- liftIO $ getXdgDirectory XdgConfig "hbs2-fixer"
|
defConfDir <- liftIO $ getXdgDirectory XdgConfig "hbs2-fixer"
|
||||||
|
|
||||||
let configPath = fromMaybe (defConfDir </> "config") cfgPath
|
let configPath = fromMaybe (defConfDir </> "config") cfgPath
|
||||||
|
|
||||||
unless (isJust cfgPath) do
|
unless (isJust cfgPath) do
|
||||||
debug $ pretty configPath
|
debug $ pretty configPath
|
||||||
touch configPath
|
touch configPath
|
||||||
|
|
||||||
syn <- liftIO (readFile configPath) <&> parseTop <&> fromRight mempty
|
syn <- readConf configPath
|
||||||
tsyn <- newTVarIO syn
|
tsyn <- newTVarIO syn
|
||||||
|
|
||||||
local (set config tsyn) (void m)
|
local (set config tsyn . set configFile (Just configPath)) (void m)
|
||||||
|
|
||||||
withApp :: Maybe FilePath -> FixerM IO () -> IO ()
|
withApp :: Maybe FilePath -> FixerM IO () -> IO ()
|
||||||
withApp cfgPath action = do
|
withApp cfgPath action = do
|
||||||
|
|
@ -56,7 +90,14 @@ withApp cfgPath action = do
|
||||||
setLogging @ERROR errorPrefix
|
setLogging @ERROR errorPrefix
|
||||||
setLogging @WARN warnPrefix
|
setLogging @WARN warnPrefix
|
||||||
setLogging @NOTICE noticePrefix
|
setLogging @NOTICE noticePrefix
|
||||||
env <- FixerEnv <$> newTVarIO mempty
|
|
||||||
|
env <- FixerEnv Nothing
|
||||||
|
<$> newTVarIO mempty
|
||||||
|
<*> newTVarIO mempty
|
||||||
|
<*> newTVarIO mempty
|
||||||
|
<*> newTVarIO mempty
|
||||||
|
<*> newTVarIO mempty
|
||||||
|
|
||||||
runReaderT (runFixerM $ withConfig cfgPath action) env
|
runReaderT (runFixerM $ withConfig cfgPath action) env
|
||||||
`finally` do
|
`finally` do
|
||||||
setLoggingOff @DEBUG
|
setLoggingOff @DEBUG
|
||||||
|
|
@ -64,7 +105,6 @@ withApp cfgPath action = do
|
||||||
setLoggingOff @ERROR
|
setLoggingOff @ERROR
|
||||||
setLoggingOff @WARN
|
setLoggingOff @WARN
|
||||||
setLoggingOff @NOTICE
|
setLoggingOff @NOTICE
|
||||||
pure ()
|
|
||||||
|
|
||||||
where
|
where
|
||||||
debugPrefix = toStdout . logPrefix "[debug] "
|
debugPrefix = toStdout . logPrefix "[debug] "
|
||||||
|
|
@ -72,11 +112,125 @@ withApp cfgPath action = do
|
||||||
warnPrefix = toStdout . logPrefix "[warn] "
|
warnPrefix = toStdout . logPrefix "[warn] "
|
||||||
noticePrefix = toStdout . logPrefix "[notice] "
|
noticePrefix = toStdout . logPrefix "[notice] "
|
||||||
|
|
||||||
|
|
||||||
|
data ConfWatch =
|
||||||
|
ConfWatch
|
||||||
|
| ConfRead
|
||||||
|
| ConfUpdate [Syntax C]
|
||||||
|
|
||||||
mainLoop :: FixerM IO ()
|
mainLoop :: FixerM IO ()
|
||||||
mainLoop = forever $ do
|
mainLoop = forever $ do
|
||||||
debug "hbs2-fixer. do stuff since 2024"
|
debug "hbs2-fixer. do stuff since 2024"
|
||||||
pause @'Seconds 5
|
conf <- getConf
|
||||||
|
debug $ line <> vcat (fmap pretty conf)
|
||||||
|
|
||||||
|
flip runContT pure do
|
||||||
|
|
||||||
|
lift $ updateFromConfig conf
|
||||||
|
|
||||||
|
void $ ContT $ withAsync $ do
|
||||||
|
cfg <- asks _configFile `orDie` "config file not specified"
|
||||||
|
|
||||||
|
flip fix ConfRead $ \next -> \case
|
||||||
|
ConfRead -> do
|
||||||
|
debug $ yellow "read config" <+> pretty cfg
|
||||||
|
newConf <- readConf cfg
|
||||||
|
oldConf <- getConf
|
||||||
|
|
||||||
|
let a = hashObject @HbSync (LBS.pack $ show $ pretty newConf)
|
||||||
|
let b = hashObject @HbSync (LBS.pack $ show $ pretty oldConf)
|
||||||
|
|
||||||
|
let changed = a /= b
|
||||||
|
|
||||||
|
if not changed then
|
||||||
|
next ConfWatch
|
||||||
|
else
|
||||||
|
next (ConfUpdate newConf)
|
||||||
|
|
||||||
|
ConfUpdate new -> do
|
||||||
|
debug $ yellow "read config / update state"
|
||||||
|
updateFromConfig new
|
||||||
|
next ConfWatch
|
||||||
|
|
||||||
|
ConfWatch{} -> do
|
||||||
|
pause @'Seconds 10
|
||||||
|
next ConfRead
|
||||||
|
|
||||||
|
-- poll reflogs
|
||||||
|
void $ ContT $ withAsync do
|
||||||
|
|
||||||
|
rlo <- pure $ asks _onRefLog
|
||||||
|
>>= readTVarIO
|
||||||
|
<&> HM.toList
|
||||||
|
<&> \x -> [ (a,b) | (a, (b,_)) <- x ]
|
||||||
|
|
||||||
|
polling (Polling 1 1) rlo $ \ref -> do
|
||||||
|
debug $ red "POLL REFLOG" <+> pretty ref
|
||||||
|
pure ()
|
||||||
|
|
||||||
|
pure ()
|
||||||
|
|
||||||
|
-- poll lww
|
||||||
|
void $ ContT $ withAsync do
|
||||||
|
|
||||||
|
lww <- pure $ asks _onLww
|
||||||
|
>>= readTVarIO
|
||||||
|
<&> HM.toList
|
||||||
|
<&> \x -> [ (a,b) | (a, (b,_)) <- x ]
|
||||||
|
|
||||||
|
polling (Polling 1 1) lww $ \ref -> do
|
||||||
|
debug $ red "POLL LWWREF" <+> pretty ref
|
||||||
|
pure ()
|
||||||
|
|
||||||
|
forever $ pause @'Seconds 60
|
||||||
|
|
||||||
|
|
||||||
|
updateFromConfig :: MonadIO m => Config -> FixerM m ()
|
||||||
|
updateFromConfig conf = do
|
||||||
|
|
||||||
|
asks _config >>= atomically . flip writeTVar conf
|
||||||
|
|
||||||
|
let w = [ (def,sec,actions)
|
||||||
|
| ListVal ( SymbolVal "watch"
|
||||||
|
: LitIntVal sec
|
||||||
|
: ListVal def
|
||||||
|
: actions ) <- conf
|
||||||
|
]
|
||||||
|
|
||||||
|
rlo <- asks _onRefLog
|
||||||
|
rloLast <- asks _refLogLast
|
||||||
|
lww <- asks _onLww
|
||||||
|
lwLast <- asks _lwwLast
|
||||||
|
|
||||||
|
updates <- S.toList_ $ for_ w $ \(who,sec,what) -> do
|
||||||
|
|
||||||
|
case who of
|
||||||
|
[SymbolVal rt, LitStrVal r] -> do
|
||||||
|
case rt of
|
||||||
|
"lwwref" -> do
|
||||||
|
let k' = fromStringMay @RLWW (Text.unpack r)
|
||||||
|
debug $ red $ "SET LWWREF WATCHER" <+> pretty sec <+> pretty k' <+> pretty what
|
||||||
|
for_ k' $ \k -> do
|
||||||
|
S.yield $ modifyTVar lww (HM.insert k (fromIntegral sec, mempty))
|
||||||
|
"reflog" -> do
|
||||||
|
let k' = fromStringMay @RRefLog (Text.unpack r)
|
||||||
|
debug $ red $ "SET LWWREF WATCHER" <+> pretty sec <+> pretty k' <+> pretty what
|
||||||
|
for_ k' $ \k -> do
|
||||||
|
S.yield $ modifyTVar rlo (HM.insert k (fromIntegral sec, mempty))
|
||||||
|
_ -> pure ()
|
||||||
|
|
||||||
|
x -> debug $ red "WTF?" <+> pretty x
|
||||||
|
|
||||||
|
liftIO $ print $ "W" <+> pretty (length updates)
|
||||||
|
|
||||||
|
atomically do
|
||||||
|
writeTVar rlo mempty
|
||||||
|
writeTVar lww mempty
|
||||||
|
writeTVar rloLast mempty
|
||||||
|
writeTVar lwLast mempty
|
||||||
|
sequence_ updates
|
||||||
|
|
||||||
|
debug $ vcat (fmap pretty w)
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue