mirror of https://github.com/voidlizard/hbs2
wip
This commit is contained in:
parent
4862cf6db2
commit
0ea0b90a9d
|
@ -94,6 +94,7 @@ library
|
||||||
, HBS2.Polling
|
, HBS2.Polling
|
||||||
, HBS2.Hash
|
, HBS2.Hash
|
||||||
, HBS2.Merkle
|
, HBS2.Merkle
|
||||||
|
, HBS2.Merkle.MetaData
|
||||||
, HBS2.Net.Auth.Schema
|
, HBS2.Net.Auth.Schema
|
||||||
, HBS2.Net.Auth.GroupKeyAsymm
|
, HBS2.Net.Auth.GroupKeyAsymm
|
||||||
, HBS2.Net.Auth.GroupKeySymm
|
, HBS2.Net.Auth.GroupKeySymm
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
module HBS2.Merkle.MetaData where
|
||||||
|
|
||||||
|
import HBS2.Prelude
|
||||||
|
import HBS2.OrDie
|
||||||
|
import HBS2.Data.Types.Refs
|
||||||
|
import HBS2.Merkle
|
||||||
|
import HBS2.Storage
|
||||||
|
import HBS2.Data.Types.SmallEncryptedBlock
|
||||||
|
import HBS2.Net.Auth.GroupKeySymm as G
|
||||||
|
import HBS2.Storage.Operations.Class
|
||||||
|
|
||||||
|
import Data.Coerce
|
||||||
|
import Data.ByteString.Lazy qualified as LBS
|
||||||
|
import Codec.Serialise
|
||||||
|
import Data.Text.Encoding qualified as TE
|
||||||
|
import Control.Monad.Except
|
||||||
|
|
||||||
|
{- HLINT ignore "Functor law" -}
|
||||||
|
|
||||||
|
extractMetaData :: forall s m . (MonadIO m, ForGroupKeySymm s, MonadError OperationError m)
|
||||||
|
|
||||||
|
=> (GroupKey 'Symm s -> m (Maybe GroupSecret))
|
||||||
|
-> AnyStorage
|
||||||
|
-> HashRef
|
||||||
|
-> m Text
|
||||||
|
extractMetaData fk sto hash = do
|
||||||
|
|
||||||
|
headBlock <- getBlock sto (coerce hash)
|
||||||
|
>>= orThrowError MissedBlockError
|
||||||
|
<&> deserialiseOrFail @(MTreeAnn [HashRef])
|
||||||
|
>>= orThrowError UnsupportedFormat
|
||||||
|
|
||||||
|
case headBlock of
|
||||||
|
MTreeAnn { _mtaMeta = ShortMetadata s } -> do
|
||||||
|
pure s
|
||||||
|
|
||||||
|
MTreeAnn { _mtaMeta = AnnHashRef h, _mtaCrypt = NullEncryption } -> do
|
||||||
|
getBlock sto h
|
||||||
|
>>= orThrowError MissedBlockError
|
||||||
|
<&> LBS.toStrict
|
||||||
|
<&> TE.decodeUtf8
|
||||||
|
|
||||||
|
MTreeAnn { _mtaMeta = AnnHashRef h } -> do
|
||||||
|
getBlock sto h
|
||||||
|
>>= orThrowError MissedBlockError
|
||||||
|
<&> deserialiseOrFail @(SmallEncryptedBlock AnnMetaData)
|
||||||
|
>>= orThrowError UnsupportedFormat
|
||||||
|
>>= G.decryptBlock @_ @s sto fk
|
||||||
|
>>= \case
|
||||||
|
ShortMetadata s -> pure s
|
||||||
|
_ -> throwError UnsupportedFormat
|
||||||
|
|
||||||
|
_ -> throwError UnsupportedFormat
|
||||||
|
|
||||||
|
|
|
@ -396,8 +396,6 @@ decryptBlock :: forall t s sto h m . ( MonadIO m
|
||||||
, MonadError OperationError m
|
, MonadError OperationError m
|
||||||
, Storage sto h ByteString m
|
, Storage sto h ByteString m
|
||||||
, ForGroupKeySymm s
|
, ForGroupKeySymm s
|
||||||
, PubKey 'Encrypt s ~ AK.PublicKey
|
|
||||||
, PrivKey 'Encrypt s ~ AK.SecretKey
|
|
||||||
, h ~ HbSync
|
, h ~ HbSync
|
||||||
, Serialise t
|
, Serialise t
|
||||||
)
|
)
|
||||||
|
|
|
@ -71,6 +71,7 @@ pattern AcceptTran t a b <- (unpackAcceptTran -> (t, a, b))
|
||||||
where
|
where
|
||||||
AcceptTran Nothing a b = AcceptTran1 a b
|
AcceptTran Nothing a b = AcceptTran1 a b
|
||||||
AcceptTran (Just t) a b = AcceptTran2 (Just t) a b
|
AcceptTran (Just t) a b = AcceptTran2 (Just t) a b
|
||||||
|
{-# COMPLETE AcceptTran #-}
|
||||||
|
|
||||||
instance ForRefChans e => Serialise (ProposeTran e)
|
instance ForRefChans e => Serialise (ProposeTran e)
|
||||||
instance ForRefChans e => Serialise (AcceptTran e)
|
instance ForRefChans e => Serialise (AcceptTran e)
|
||||||
|
|
|
@ -3,6 +3,7 @@ module HBS2.Peer.RPC.Client.RefChan where
|
||||||
|
|
||||||
import HBS2.OrDie
|
import HBS2.OrDie
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
|
import HBS2.Merkle
|
||||||
import HBS2.Storage.Operations.ByteString
|
import HBS2.Storage.Operations.ByteString
|
||||||
import HBS2.Data.Types.SignedBox
|
import HBS2.Data.Types.SignedBox
|
||||||
|
|
||||||
|
@ -13,9 +14,13 @@ import HBS2.Peer.RPC.API.Storage
|
||||||
import HBS2.Peer.RPC.Client.Internal
|
import HBS2.Peer.RPC.Client.Internal
|
||||||
import HBS2.Peer.RPC.Client.StorageClient
|
import HBS2.Peer.RPC.Client.StorageClient
|
||||||
|
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
import Data.Coerce
|
import Data.Coerce
|
||||||
import Control.Monad.Except
|
import Control.Monad.Except
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
|
import Control.Monad.Trans.Cont
|
||||||
|
import Control.Monad.Reader
|
||||||
|
import Codec.Serialise
|
||||||
import UnliftIO
|
import UnliftIO
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,3 +60,123 @@ getRefChanHead puk = do
|
||||||
|
|
||||||
pure hdblk
|
pure hdblk
|
||||||
|
|
||||||
|
postRefChanTx :: forall proto s m . ( MonadUnliftIO m
|
||||||
|
, HasClientAPI RefChanAPI proto m
|
||||||
|
, HasClientAPI StorageAPI proto m
|
||||||
|
, HasProtocol proto (ServiceProto RefChanAPI proto)
|
||||||
|
, HasProtocol proto (ServiceProto StorageAPI proto)
|
||||||
|
, ForSignedBox s
|
||||||
|
, s ~ HBS2Basic
|
||||||
|
)
|
||||||
|
=> PubKey 'Sign s
|
||||||
|
-> SignedBox ByteString s
|
||||||
|
-> m ()
|
||||||
|
postRefChanTx puk box = do
|
||||||
|
api <- getClientAPI @RefChanAPI @proto
|
||||||
|
callRpcWaitMay @RpcRefChanPropose (TimeoutSec 1) api (puk, box) >>= \case
|
||||||
|
Nothing -> throwIO RpcTimeoutError
|
||||||
|
Just e -> pure e
|
||||||
|
|
||||||
|
fetchRefChanHead :: forall proto m . ( MonadUnliftIO m
|
||||||
|
, HasClientAPI RefChanAPI proto m
|
||||||
|
, HasProtocol proto (ServiceProto RefChanAPI proto)
|
||||||
|
)
|
||||||
|
=> PubKey 'Sign 'HBS2Basic
|
||||||
|
-> m ()
|
||||||
|
fetchRefChanHead puk = do
|
||||||
|
api <- getClientAPI @RefChanAPI @proto
|
||||||
|
callRpcWaitMay @RpcRefChanHeadFetch (TimeoutSec 1) api puk >>= \case
|
||||||
|
Nothing -> throwIO RpcTimeoutError
|
||||||
|
_ -> pure ()
|
||||||
|
|
||||||
|
fetchRefChan :: forall proto m . ( MonadUnliftIO m
|
||||||
|
, HasClientAPI RefChanAPI proto m
|
||||||
|
, HasProtocol proto (ServiceProto RefChanAPI proto)
|
||||||
|
)
|
||||||
|
=> PubKey 'Sign 'HBS2Basic
|
||||||
|
-> m ()
|
||||||
|
fetchRefChan puk = do
|
||||||
|
api <- getClientAPI @RefChanAPI @proto
|
||||||
|
callRpcWaitMay @RpcRefChanFetch (TimeoutSec 1) api puk >>= \case
|
||||||
|
Nothing -> throwIO RpcTimeoutError
|
||||||
|
_ -> pure ()
|
||||||
|
|
||||||
|
|
||||||
|
getRefChanValue :: forall proto m . ( MonadUnliftIO m
|
||||||
|
, HasClientAPI RefChanAPI proto m
|
||||||
|
, HasProtocol proto (ServiceProto RefChanAPI proto)
|
||||||
|
)
|
||||||
|
=> PubKey 'Sign 'HBS2Basic
|
||||||
|
-> m (Maybe HashRef)
|
||||||
|
getRefChanValue puk = do
|
||||||
|
api <- getClientAPI @RefChanAPI @proto
|
||||||
|
callRpcWaitMay @RpcRefChanGet (TimeoutSec 1) api puk >>= \case
|
||||||
|
Nothing -> throwIO RpcTimeoutError
|
||||||
|
Just e -> pure e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- this is not MonadUnliftIO to be compatible with
|
||||||
|
-- streaming
|
||||||
|
--
|
||||||
|
|
||||||
|
data RScanEnv proto =
|
||||||
|
RScanEnv {
|
||||||
|
rchanAPI :: ServiceCaller RefChanAPI proto
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
instance Monad m => HasClientAPI RefChanAPI proto (ReaderT (RScanEnv proto) m) where
|
||||||
|
getClientAPI = asks rchanAPI
|
||||||
|
|
||||||
|
data RefChanUpdateUnpacked e =
|
||||||
|
A (AcceptTran e) | P HashRef (ProposeTran e)
|
||||||
|
deriving stock (Generic)
|
||||||
|
|
||||||
|
{-# COMPLETE A,P #-}
|
||||||
|
|
||||||
|
walkRefChanTx :: forall proto m . ( MonadIO m
|
||||||
|
, HasClientAPI RefChanAPI proto m
|
||||||
|
, HasProtocol proto (ServiceProto RefChanAPI proto)
|
||||||
|
, HasStorage m
|
||||||
|
)
|
||||||
|
=> PubKey 'Sign 'HBS2Basic
|
||||||
|
-> (RefChanUpdateUnpacked L4Proto -> m ())
|
||||||
|
-> m ()
|
||||||
|
walkRefChanTx puk action = do
|
||||||
|
sto <- getStorage
|
||||||
|
api <- getClientAPI @RefChanAPI @proto
|
||||||
|
|
||||||
|
let env = RScanEnv api
|
||||||
|
|
||||||
|
flip runContT pure $ callCC $ \exit -> do
|
||||||
|
|
||||||
|
rcv' <- liftIO (runReaderT (getRefChanValue @proto puk) env)
|
||||||
|
|
||||||
|
rcv <- ContT $ maybe1 rcv' none
|
||||||
|
|
||||||
|
walkMerkle (coerce rcv) (getBlock sto) $ \case
|
||||||
|
-- FIXME: error-handling
|
||||||
|
Left _ -> exit ()
|
||||||
|
|
||||||
|
Right (hs :: [HashRef]) -> do
|
||||||
|
for_ hs $ \h -> do
|
||||||
|
lbs' <- getBlock sto (coerce h)
|
||||||
|
lbs <- ContT $ maybe1 lbs' none
|
||||||
|
|
||||||
|
let txraw = deserialiseOrFail @(RefChanUpdate L4Proto) lbs
|
||||||
|
& either (const Nothing) Just
|
||||||
|
|
||||||
|
tx <- ContT $ maybe1 txraw none
|
||||||
|
|
||||||
|
case tx of
|
||||||
|
|
||||||
|
Accept _ box -> do
|
||||||
|
(_, txx) <- ContT $ maybe1 (unboxSignedBox0 box) none
|
||||||
|
lift $ action (A txx)
|
||||||
|
|
||||||
|
Propose _ box -> do
|
||||||
|
(_, txx) <- ContT $ maybe1 (unboxSignedBox0 box) none
|
||||||
|
lift $ action (P h txx)
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,14 @@ module HBS2.Sync.Prelude
|
||||||
|
|
||||||
import HBS2.Prelude.Plated as Exported
|
import HBS2.Prelude.Plated as Exported
|
||||||
import HBS2.Base58
|
import HBS2.Base58
|
||||||
|
import HBS2.Merkle
|
||||||
|
import HBS2.Merkle.MetaData
|
||||||
import HBS2.OrDie as Exported
|
import HBS2.OrDie as Exported
|
||||||
import HBS2.Data.Types.Refs as Exported
|
import HBS2.Data.Types.Refs as Exported
|
||||||
|
import HBS2.Data.Types.SignedBox
|
||||||
|
import HBS2.Net.Auth.Credentials
|
||||||
import HBS2.Net.Auth.GroupKeySymm qualified as Symm
|
import HBS2.Net.Auth.GroupKeySymm qualified as Symm
|
||||||
|
import HBS2.Net.Auth.Schema
|
||||||
import HBS2.Clock as Exported
|
import HBS2.Clock as Exported
|
||||||
import HBS2.Net.Proto.Service
|
import HBS2.Net.Proto.Service
|
||||||
import HBS2.Storage
|
import HBS2.Storage
|
||||||
|
@ -29,6 +34,8 @@ import HBS2.Misc.PrettyStuff as Exported
|
||||||
import HBS2.CLI.Run hiding (PeerException(..))
|
import HBS2.CLI.Run hiding (PeerException(..))
|
||||||
import HBS2.CLI.Run.MetaData
|
import HBS2.CLI.Run.MetaData
|
||||||
|
|
||||||
|
import HBS2.KeyMan.Keys.Direct
|
||||||
|
|
||||||
import Data.Config.Suckless as Exported
|
import Data.Config.Suckless as Exported
|
||||||
import Data.Config.Suckless.Script as Exported
|
import Data.Config.Suckless.Script as Exported
|
||||||
import Data.Config.Suckless.Script.File
|
import Data.Config.Suckless.Script.File
|
||||||
|
@ -37,7 +44,11 @@ import Codec.Serialise as Exported
|
||||||
import Control.Concurrent.STM (flushTQueue)
|
import Control.Concurrent.STM (flushTQueue)
|
||||||
import Control.Monad.Reader as Exported
|
import Control.Monad.Reader as Exported
|
||||||
import Control.Monad.Trans.Cont as Exported
|
import Control.Monad.Trans.Cont as Exported
|
||||||
|
import Control.Monad.Trans.Maybe
|
||||||
|
import Control.Monad.Except
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
import Data.ByteString.Lazy qualified as LBS
|
import Data.ByteString.Lazy qualified as LBS
|
||||||
|
import Data.Coerce
|
||||||
import Data.Either
|
import Data.Either
|
||||||
import Data.HashMap.Strict qualified as HM
|
import Data.HashMap.Strict qualified as HM
|
||||||
import Data.HashSet qualified as HS
|
import Data.HashSet qualified as HS
|
||||||
|
@ -93,6 +104,11 @@ instance MonadIO m => HasClientAPI PeerAPI UNIX (SyncApp m) where
|
||||||
getClientAPI = ask >>= orThrow PeerNotConnectedException
|
getClientAPI = ask >>= orThrow PeerNotConnectedException
|
||||||
<&> peerAPI
|
<&> peerAPI
|
||||||
|
|
||||||
|
instance MonadIO m => HasStorage (SyncApp m) where
|
||||||
|
getStorage = do
|
||||||
|
api <- getClientAPI @StorageAPI @UNIX
|
||||||
|
pure $ AnyStorage (StorageClient api)
|
||||||
|
|
||||||
withSyncApp :: SyncAppPerks m => Maybe SyncEnv -> SyncApp m a -> m a
|
withSyncApp :: SyncAppPerks m => Maybe SyncEnv -> SyncApp m a -> m a
|
||||||
withSyncApp env action = runReaderT (fromSyncApp action) env
|
withSyncApp env action = runReaderT (fromSyncApp action) env
|
||||||
|
|
||||||
|
@ -143,6 +159,7 @@ data RunDirectoryException =
|
||||||
RefChanNotSetException
|
RefChanNotSetException
|
||||||
| RefChanHeadNotFoundException
|
| RefChanHeadNotFoundException
|
||||||
| EncryptionKeysNotDefined
|
| EncryptionKeysNotDefined
|
||||||
|
| SignKeyNotSet
|
||||||
deriving stock (Show,Typeable)
|
deriving stock (Show,Typeable)
|
||||||
|
|
||||||
instance Exception RunDirectoryException
|
instance Exception RunDirectoryException
|
||||||
|
@ -159,7 +176,7 @@ getFileTimestamp filePath = do
|
||||||
pure (round $ utcTimeToPOSIXSeconds t0)
|
pure (round $ utcTimeToPOSIXSeconds t0)
|
||||||
|
|
||||||
|
|
||||||
data EntryType = File | Dir
|
data EntryType = File | Dir | Tomb
|
||||||
deriving stock (Eq,Ord,Show,Data,Generic)
|
deriving stock (Eq,Ord,Show,Data,Generic)
|
||||||
|
|
||||||
data EntryDesc =
|
data EntryDesc =
|
||||||
|
@ -182,32 +199,32 @@ isFile = \case
|
||||||
|
|
||||||
entriesFromLocalFile :: MonadUnliftIO m => FilePath -> FilePath -> m (Map FilePath DirEntry)
|
entriesFromLocalFile :: MonadUnliftIO m => FilePath -> FilePath -> m (Map FilePath DirEntry)
|
||||||
entriesFromLocalFile prefix fn' = do
|
entriesFromLocalFile prefix fn' = do
|
||||||
|
|
||||||
let fn0 = removePrefix prefix fn
|
let fn0 = removePrefix prefix fn
|
||||||
ts <- getFileTimestamp fn
|
ts <- getFileTimestamp fn
|
||||||
|
pure $ entriesFromFile ts fn0
|
||||||
let dirs = splitDirectories (dropFileName fn0)
|
|
||||||
& dropWhile (== ".")
|
|
||||||
|
|
||||||
debug $ red "SOURCE" <+> pretty fn0 <+> pretty fn <+> pretty dirs
|
|
||||||
|
|
||||||
let es = flip L.unfoldr ("",dirs) $ \case
|
|
||||||
(_,[]) -> Nothing
|
|
||||||
(p,d:ds) -> Just (dirEntry ts (p </> d), (p </> d, ds) )
|
|
||||||
|
|
||||||
pure $ Map.fromList [ (p, e)
|
|
||||||
| e@(DirEntry _ p) <- fileEntry ts fn0 : es
|
|
||||||
]
|
|
||||||
|
|
||||||
where
|
where
|
||||||
fn = normalise fn'
|
fn = normalise fn'
|
||||||
dirEntry ts p = DirEntry (EntryDesc Dir ts) p
|
|
||||||
fileEntry ts p = DirEntry (EntryDesc File ts) p
|
entriesFromFile :: Word64 -> FilePath -> Map FilePath DirEntry
|
||||||
|
entriesFromFile ts fn0 = do
|
||||||
|
let dirs = splitDirectories (dropFileName fn0)
|
||||||
|
& dropWhile (== ".")
|
||||||
|
let es = flip L.unfoldr ("",dirs) $ \case
|
||||||
|
(_,[]) -> Nothing
|
||||||
|
(p,d:ds) -> Just (dirEntry (p </> d), (p </> d, ds) )
|
||||||
|
|
||||||
|
Map.fromList [ (p, e)
|
||||||
|
| e@(DirEntry _ p) <- fileEntry fn0 : es
|
||||||
|
]
|
||||||
|
where
|
||||||
|
dirEntry p = DirEntry (EntryDesc Dir ts) p
|
||||||
|
fileEntry p = DirEntry (EntryDesc File ts) p
|
||||||
|
|
||||||
runDirectory :: ( IsContext c
|
runDirectory :: ( IsContext c
|
||||||
, SyncAppPerks m
|
, SyncAppPerks m
|
||||||
, HasClientAPI RefChanAPI UNIX m
|
, HasClientAPI RefChanAPI UNIX m
|
||||||
, HasClientAPI StorageAPI UNIX m
|
, HasClientAPI StorageAPI UNIX m
|
||||||
|
, HasStorage m
|
||||||
, Exception (BadFormException c)
|
, Exception (BadFormException c)
|
||||||
) => FilePath -> RunM c m ()
|
) => FilePath -> RunM c m ()
|
||||||
runDirectory path = do
|
runDirectory path = do
|
||||||
|
@ -223,6 +240,8 @@ runDirectory path = do
|
||||||
err $ "no refchan head found for" <+> pretty path
|
err $ "no refchan head found for" <+> pretty path
|
||||||
EncryptionKeysNotDefined -> do
|
EncryptionKeysNotDefined -> do
|
||||||
err $ "no readers defined in the refchan for " <+> pretty path
|
err $ "no readers defined in the refchan for " <+> pretty path
|
||||||
|
SignKeyNotSet -> do
|
||||||
|
err $ "sign key not set or not found " <+> pretty path
|
||||||
|
|
||||||
`catch` \case
|
`catch` \case
|
||||||
(e :: OperationError) -> do
|
(e :: OperationError) -> do
|
||||||
|
@ -242,6 +261,7 @@ runDirectory path = do
|
||||||
notice $ yellow "run directory" <+> pretty path
|
notice $ yellow "run directory" <+> pretty path
|
||||||
|
|
||||||
trc <- newTVarIO Nothing
|
trc <- newTVarIO Nothing
|
||||||
|
tsign <- newTVarIO Nothing
|
||||||
texcl <- newTQueueIO
|
texcl <- newTQueueIO
|
||||||
tincl <- newTQueueIO
|
tincl <- newTQueueIO
|
||||||
|
|
||||||
|
@ -273,6 +293,19 @@ runDirectory path = do
|
||||||
|
|
||||||
_ -> pure ()
|
_ -> pure ()
|
||||||
|
|
||||||
|
|
||||||
|
bindBuiltins $ bindMatch "sign" $ nil_ $ \case
|
||||||
|
[SignPubKeyLike s] -> do
|
||||||
|
debug $ red "SIGN" <+> pretty (AsBase58 s)
|
||||||
|
|
||||||
|
runMaybeT do
|
||||||
|
creds <- MaybeT $ runKeymanClient $ loadCredentials s
|
||||||
|
atomically $ writeTVar tsign (Just creds)
|
||||||
|
|
||||||
|
pure ()
|
||||||
|
|
||||||
|
_ -> pure ()
|
||||||
|
|
||||||
evalTop ins
|
evalTop ins
|
||||||
|
|
||||||
incl <- atomically (flushTQueue tincl) <&> HS.fromList <&> HS.toList
|
incl <- atomically (flushTQueue tincl) <&> HS.fromList <&> HS.toList
|
||||||
|
@ -281,9 +314,14 @@ runDirectory path = do
|
||||||
refchan <- readTVarIO trc
|
refchan <- readTVarIO trc
|
||||||
>>= orThrow RefChanNotSetException
|
>>= orThrow RefChanNotSetException
|
||||||
|
|
||||||
|
fetchRefChan @UNIX refchan
|
||||||
|
|
||||||
rch <- Client.getRefChanHead @UNIX refchan
|
rch <- Client.getRefChanHead @UNIX refchan
|
||||||
>>= orThrow RefChanHeadNotFoundException
|
>>= orThrow RefChanHeadNotFoundException
|
||||||
|
|
||||||
|
creds <- readTVarIO tsign
|
||||||
|
>>= orThrow SignKeyNotSet
|
||||||
|
|
||||||
sto <- getClientAPI @StorageAPI @UNIX
|
sto <- getClientAPI @StorageAPI @UNIX
|
||||||
<&> AnyStorage . StorageClient
|
<&> AnyStorage . StorageClient
|
||||||
|
|
||||||
|
@ -310,14 +348,18 @@ runDirectory path = do
|
||||||
debug "FUCKING GOT REFCHAN HEAD"
|
debug "FUCKING GOT REFCHAN HEAD"
|
||||||
|
|
||||||
let local = Map.fromList [ (p,e) | e@(DirEntry _ p) <- es' ]
|
let local = Map.fromList [ (p,e) | e@(DirEntry _ p) <- es' ]
|
||||||
let remote = Map.empty
|
|
||||||
|
remote <- getStateFromRefChan refchan
|
||||||
|
|
||||||
let merged = Map.unionWith merge local remote
|
let merged = Map.unionWith merge local remote
|
||||||
|
|
||||||
for_ (Map.toList merged) $ \(p,e) -> do
|
for_ (Map.toList merged) $ \(p,e) -> do
|
||||||
debug $ yellow "entry" <+> pretty p <+> viaShow e
|
debug $ yellow "entry" <+> pretty p <+> viaShow e
|
||||||
|
|
||||||
when (not (Map.member p remote) && isFile e) do
|
warn $ red "POSTING IS SWITCHED OFF"
|
||||||
|
|
||||||
|
|
||||||
|
when (not (Map.member p remote) && isFile e && False) do
|
||||||
|
|
||||||
-- FIXME: dangerous!
|
-- FIXME: dangerous!
|
||||||
lbs <- liftIO (LBS.readFile (path </> p))
|
lbs <- liftIO (LBS.readFile (path </> p))
|
||||||
|
@ -342,6 +384,14 @@ runDirectory path = do
|
||||||
href <- createTreeWithMetadata sto (Just gk) meta lbs
|
href <- createTreeWithMetadata sto (Just gk) meta lbs
|
||||||
>>= orThrowPassIO
|
>>= orThrowPassIO
|
||||||
|
|
||||||
|
let tx = AnnotatedHashRef Nothing href
|
||||||
|
let spk = view peerSignPk creds
|
||||||
|
let ssk = view peerSignSk creds
|
||||||
|
|
||||||
|
let box = makeSignedBox @HBS2Basic spk ssk (LBS.toStrict $ serialise tx)
|
||||||
|
|
||||||
|
postRefChanTx @UNIX refchan box
|
||||||
|
|
||||||
notice $ red "POST NEW REMOTE ENTRY" <+> pretty p <+> pretty href
|
notice $ red "POST NEW REMOTE ENTRY" <+> pretty p <+> pretty href
|
||||||
|
|
||||||
pure ()
|
pure ()
|
||||||
|
@ -351,6 +401,53 @@ runDirectory path = do
|
||||||
|
|
||||||
debug $ pretty ins
|
debug $ pretty ins
|
||||||
|
|
||||||
|
getStateFromRefChan rchan = do
|
||||||
|
|
||||||
|
debug $ red "getStateFromRefChan" <+> pretty (AsBase58 rchan)
|
||||||
|
|
||||||
|
sto <- getStorage
|
||||||
|
|
||||||
|
outq <- newTQueueIO
|
||||||
|
tss <- newTVarIO mempty
|
||||||
|
|
||||||
|
walkRefChanTx @UNIX rchan $ \case
|
||||||
|
A (AcceptTran ts _ what) -> do
|
||||||
|
debug $ red "ACCEPT" <+> pretty ts <+> pretty what
|
||||||
|
for_ ts $ \w -> do
|
||||||
|
atomically $ modifyTVar tss (HM.insertWith max what (coerce @_ @Word64 w))
|
||||||
|
|
||||||
|
P orig (ProposeTran _ box) -> void $ runMaybeT do
|
||||||
|
(_, bs) <- unboxSignedBox0 box & toMPlus
|
||||||
|
AnnotatedHashRef w href <- deserialiseOrFail @AnnotatedHashRef (LBS.fromStrict bs)
|
||||||
|
& toMPlus . either (const Nothing) Just
|
||||||
|
|
||||||
|
let findKey gk = liftIO (runKeymanClient (extractGroupKeySecret gk))
|
||||||
|
|
||||||
|
runExceptT (extractMetaData @'HBS2Basic findKey sto href)
|
||||||
|
>>= either (const none) ( \meta -> atomically $ writeTQueue outq (orig, (href, meta)) )
|
||||||
|
|
||||||
|
trees <- atomically (flushTQueue outq)
|
||||||
|
|
||||||
|
tsmap <- readTVarIO tss
|
||||||
|
|
||||||
|
ess0 <- S.toList_ do
|
||||||
|
for_ trees $ \(txh, (tree, meta)) -> do
|
||||||
|
let what = parseTop meta & fromRight mempty
|
||||||
|
let loc = headDef "" [ l | ListVal [StringLike "location:", StringLike l] <- what ]
|
||||||
|
|
||||||
|
void $ runMaybeT do
|
||||||
|
fn <- toMPlus $ headMay [ l | ListVal [StringLike "file-name:", StringLike l] <- what ]
|
||||||
|
ts <- toMPlus $ HM.lookup txh tsmap
|
||||||
|
let r = entriesFromFile ts (loc </> fn)
|
||||||
|
lift $ S.yield r
|
||||||
|
|
||||||
|
let ess = Map.unionsWith merge ess0
|
||||||
|
|
||||||
|
for_ (Map.toList ess) $ \(p,e) -> do
|
||||||
|
debug $ "REMOTE ENTRY" <+> pretty p <+> viaShow e
|
||||||
|
|
||||||
|
pure mempty
|
||||||
|
|
||||||
|
|
||||||
syncEntries :: forall c m . (MonadUnliftIO m, IsContext c) => MakeDictM c m ()
|
syncEntries :: forall c m . (MonadUnliftIO m, IsContext c) => MakeDictM c m ()
|
||||||
syncEntries = do
|
syncEntries = do
|
||||||
|
@ -362,6 +459,7 @@ syncEntries = do
|
||||||
_ -> do
|
_ -> do
|
||||||
setLogging @DEBUG debugPrefix
|
setLogging @DEBUG debugPrefix
|
||||||
|
|
||||||
|
-- debugPrefix :: LoggerEntry -> LoggerEntry
|
||||||
debugPrefix = toStderr . logPrefix "[debug] "
|
debugPrefix = toStderr . logPrefix "[debug] "
|
||||||
|
|
||||||
setupLogger :: MonadIO m => m ()
|
setupLogger :: MonadIO m => m ()
|
||||||
|
|
Loading…
Reference in New Issue