{-# Language UndecidableInstances #-} {-# Language AllowAmbiguousTypes #-} module HBS2.Git3.Repo ( initRepo, waitRepo , getRepoRefMaybe , getRepoManifest , HasGitRemoteKey(..) ) where import HBS2.Git3.Prelude import HBS2.Git3.State import HBS2.CLI.Run.MetaData import HBS2.Net.Auth.Credentials import HBS2.Data.Detect ( readLogThrow ) import HBS2.CLI.Run.Internal.Merkle (getTreeContents) import HBS2.CLI.Run.RefLog (getCredentialsForReflog,mkRefLogUpdateFrom) import HBS2.Git3.Config.Local import HBS2.KeyMan.Keys.Direct import Data.Config.Suckless.Script import Data.Config.Suckless.Almost.RPC import Data.ByteString.Lazy.Char8 qualified as LBS8 import Data.ByteString.Lazy qualified as LBS import Data.Text.Encoding qualified as TE import Data.Text.Encoding.Error qualified as TE import Data.Word import Lens.Micro.Platform import System.Random hiding (next) {- HLINT ignore "Functor law"-} data CInit = CheckRepoKeyExist | CreateRepoKey | CheckRepoKeyStart GitRepoKey | CheckRepoKeyWait TimeSpec (Timeout 'Seconds) GitRepoKey | CheckRepoDefBlock GitRepoKey (LWWRef 'HBS2Basic) | CreateRepoDefBlock GitRepoKey initRepo :: forall m . HBS2GitPerks m => [Syntax C] -> Git3 m () initRepo syn = do let (opts, _) = splitOpts [("--new",0)] syn let new = or [ True | ListVal [SymbolVal "--new"] <- opts ] root <- getConfigRootFile sto <- getStorage lwwAPI <- getClientAPI @LWWRefAPI @UNIX refLogAPI <- getClientAPI @RefLogAPI @UNIX peerAPI <- getClientAPI @PeerAPI @UNIX flip fix CheckRepoKeyExist $ \next -> \case CheckRepoKeyExist -> do debug "initRepo:CheckRepoKey" mbk <- getGitRepoKey next $ maybe CreateRepoKey CheckRepoKeyStart mbk CreateRepoKey -> do debug "initRepo:CreateRepoKey" answ <- callProc "hbs2-cli" [] [mkSym "hbs2:lwwref:create"] pk <- [ x | ListVal [SymbolVal "pk", SignPubKeyLike x] <- answ ] & lastMay & orThrowUser "can't create new lwwref" liftIO $ appendFile root (show $ pretty $ mkForm "repo:key" [mkSym @C (show $ pretty (AsBase58 pk))]) CheckRepoKeyStart pk -> do debug $ "initRepo:CheckRepoKeyStart" <+> pretty (AsBase58 pk) callRpcWaitMay @RpcLWWRefFetch (TimeoutSec 1) lwwAPI (LWWRefKey pk) >>= orThrowUser "rpc timeout" now <- getTimeCoarse let waity = if new then ceiling 0.5e9 else ceiling 30e9 let till = TimeoutTS (now + fromNanoSecs waity ) next $ CheckRepoKeyWait (coerce till) 1.0 pk CheckRepoKeyWait till w pk -> do debug $ "initRepo:CheckRepoKeyWait" <+> pretty (AsBase58 pk) rv <- getRepoRefMaybe now <- getTimeCoarse if now > till then do next $ CreateRepoDefBlock pk else do maybe1 rv (pause w >> next (CheckRepoKeyWait till (1.10 * w) pk)) (next . CheckRepoDefBlock pk) CheckRepoDefBlock pk LWWRef{..} -> do debug $ "init:CheckRepoDefBlock" <+> pretty (AsBase58 pk) <+> pretty lwwValue repo <- getRepoManifest reflog <- [ x | ListVal [SymbolVal "reflog", SignPubKeyLike x] <- repo ] & headMay & orThrowUser "malformed repo manifest" callRpcWaitMay @RpcPollAdd (TimeoutSec 1) peerAPI (reflog, "reflog", 17) >>= orThrowUser "rpc timeout" liftIO $ print $ pretty repo CreateRepoDefBlock pk -> do debug $ "init:CreateRepoDefBlock" <+> pretty (AsBase58 pk) seed <- randomIO @Word64 creds <- runKeymanClientRO (loadCredentials pk) >>= orThrowUser ("not found credentials for" <+> pretty (AsBase58 pk)) let (wsk,wpk) = (view peerSignSk creds, view peerSignPk creds) let sk = view peerSignSk creds (rpk,rsk) <- derivedKey @'HBS2Basic @'Sign seed sk let manifest = [ mkForm @C "hbs2-git" [mkInt 3] , mkForm "seed" [mkInt seed] , mkForm "public" [] , mkForm "reflog" [mkSym (show $ pretty (AsBase58 rpk))] ] & vcat . fmap pretty tree <- createTreeWithMetadata sto Nothing mempty (LBS8.pack (show $ manifest)) >>= orThrowPassIO liftIO $ print tree let pt = toPTree (MaxSize defHashListChunk) (MaxNum defTreeChildNum) [tree] blk <- makeMerkle 0 pt $ \(_,_,bs) -> do void $ putBlock sto bs notice $ "current root" <+> pretty blk <+> pretty tree let box = makeSignedBox wpk wsk (LWWRef 3 (coerce blk) Nothing) callRpcWaitMay @RpcLWWRefUpdate (TimeoutSec 1) lwwAPI box >>= orThrowUser "rpc timeout" callRpcWaitMay @RpcPollAdd (TimeoutSec 1) peerAPI (rpk, "reflog", 17) >>= orThrowUser "rpc timeout"