hbs2/hbs2-storage-simple/lib/HBS2/Storage/Simple/Extra.hs

121 lines
3.3 KiB
Haskell

{-# Language UndecidableInstances #-}
module HBS2.Storage.Simple.Extra where
import HBS2.Merkle
import HBS2.Hash
import HBS2.Prelude
import HBS2.Storage
import HBS2.Storage.Simple
import HBS2.Data.Types.Refs
import HBS2.Defaults
import Data.Foldable (for_)
import Data.Bifunctor
import Data.ByteString.Lazy (ByteString)
import Data.ByteString.Lazy qualified as B
import Data.Function
import Lens.Micro.Platform
import System.FilePattern.Directory
import Data.ByteString.Lazy.Char8 qualified as LBS
import Data.ByteString.Char8 qualified as BS
import System.FilePath
import Data.Maybe
import Control.Concurrent.STM
import Control.Concurrent.Async
import Control.Monad
import Streaming.Prelude qualified as S
import Streaming qualified as S
import System.IO
pieces :: Integral a => a
pieces = 1024
class SimpleStorageExtra a where
putAsMerkle :: forall h . (IsSimpleStorageKey h, Hashed h ByteString) => SimpleStorage h -> a -> IO MerkleHash
readChunked :: MonadIO m => Handle -> Int -> S.Stream (S.Of ByteString) m ()
readChunked handle size = fuu
where
fuu = fix \next -> do
chunk <- liftIO do
B.hGet handle size
unless (B.null chunk) do
S.yield chunk
next
instance SimpleStorageExtra Handle where
putAsMerkle ss handle = do
hashes <- readChunked handle (fromIntegral defBlockSize) -- FIXME: to settings!
& S.mapM (\blk -> enqueueBlock ss blk >> pure blk)
& S.map (HashRef . hashObject)
& S.toList_
putAsMerkle ss hashes
instance SimpleStorageExtra (S.Stream (S.Of ByteString) IO ()) where
putAsMerkle ss streamChunks = do
hashes <- streamChunks
& S.mapM (\blk -> enqueueBlock ss blk >> pure blk)
& S.map (HashRef . hashObject)
& S.toList_
putAsMerkle ss hashes
instance SimpleStorageExtra [HashRef] where
putAsMerkle ss hashes = do
let pt = toPTree (MaxSize pieces) (MaxNum pieces) hashes -- FIXME: settings
root <- makeMerkle 0 pt $ \(_,_,bs) -> void $ putBlock ss bs
pure (MerkleHash root)
instance SimpleStorageExtra ByteString where
putAsMerkle ss bs = do
hashes <- S.each (B.unpack bs)
& S.chunksOf (fromIntegral defBlockSize)
& S.mapped (fmap (first B.pack) . S.toList)
& S.mapM (\blk -> enqueueBlock ss blk >> pure blk)
& S.map (HashRef . hashObject)
& S.toList_
let pt = toPTree (MaxSize pieces) (MaxNum pieces) hashes -- FIXME: settings
root <- makeMerkle 0 pt $ \(_,_,bss) -> void $ putBlock ss bss
pure (MerkleHash root)
simpleStorageFsck :: forall h . (IsSimpleStorageKey h, Hashed h ByteString)
=> SimpleStorage h
-> IO [(Maybe (Hash HbSync), FilePath)]
simpleStorageFsck sto = do
let fblock = view storageBlocks sto
files <- getDirectoryFiles fblock ["**/*"]
-- FIXME: thread-num-hardcode
bad <- forM files $ \f -> do
let fname = fblock </> f
let ha = splitDirectories f & mconcat & fromStringMay @(Hash HbSync)
case ha of
Just hash -> do
hr <- BS.readFile fname <&> hashObject @HbSync
if hr == hash then do
pure []
else
pure [(Just hash, fname)]
Nothing -> do
pure [(Nothing, fname)]
pure $ mconcat bad