storage rpc

This commit is contained in:
Dmitry Zuikov 2023-10-04 13:38:35 +03:00
parent 613f26e418
commit 28163d0123
23 changed files with 622 additions and 103 deletions

View File

@ -7,16 +7,11 @@ module HBS2.Data.Types.Refs
import HBS2.Base58 import HBS2.Base58
import HBS2.Hash import HBS2.Hash
import HBS2.Merkle
import HBS2.Net.Proto.Types import HBS2.Net.Proto.Types
import HBS2.Net.Auth.Credentials
import HBS2.Prelude import HBS2.Prelude
import Codec.Serialise(serialise) import Codec.Serialise(serialise)
import Data.Data import Data.Data
import GHC.Generics
import Data.Hashable hiding (Hashed)
import Data.Maybe (fromMaybe)
newtype HashRef = HashRef { fromHashRef :: Hash HbSync } newtype HashRef = HashRef { fromHashRef :: Hash HbSync }
deriving newtype (Eq,Ord,IsString,Pretty,Hashable) deriving newtype (Eq,Ord,IsString,Pretty,Hashable)
@ -67,7 +62,6 @@ instance Serialise SequentialRef
instance Serialise HashRef instance Serialise HashRef
type IsRefPubKey s = ( Eq (PubKey 'Sign s) type IsRefPubKey s = ( Eq (PubKey 'Sign s)
, Serialise (PubKey 'Sign s) , Serialise (PubKey 'Sign s)
, FromStringMaybe (PubKey 'Sign s) , FromStringMaybe (PubKey 'Sign s)
@ -82,4 +76,15 @@ newtype SomeRefKey a = SomeRefKey a
instance Serialise a => Hashed HbSync (SomeRefKey a) where instance Serialise a => Hashed HbSync (SomeRefKey a) where
hashObject (SomeRefKey s) = hashObject (serialise s) hashObject (SomeRefKey s) = hashObject (serialise s)
newtype RefAlias = RefAlias { unRefAlias :: HashRef }
deriving stock (Eq,Ord,Show)
deriving newtype (Pretty,Serialise)
instance Hashed HbSync RefAlias where
hashObject (RefAlias h) = fromHashRef h
refAlias :: Hashed HbSync ref => ref -> RefAlias
refAlias x = RefAlias (HashRef $ hashObject @HbSync x)

View File

@ -5,10 +5,9 @@ import HBS2.Hash
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
import Data.Kind import Data.Kind
import Data.Hashable hiding (Hashed)
import Lens.Micro.Platform import Lens.Micro.Platform
import Prettyprinter
import Codec.Serialise()
class Pretty (Hash h) => IsKey h where class Pretty (Hash h) => IsKey h where
type family Key h :: Type type family Key h :: Type
@ -21,11 +20,11 @@ newtype StoragePrefix = StoragePrefix { fromPrefix :: FilePath }
deriving newtype (IsString,Pretty) deriving newtype (IsString,Pretty)
newtype Offset = Offset Integer newtype Offset = Offset Integer
deriving newtype (Eq,Ord,Enum,Num,Real,Integral,Hashable,Pretty) deriving newtype (Eq,Ord,Enum,Num,Real,Integral,Hashable,Pretty,Serialise)
deriving stock (Show) deriving stock (Show)
newtype Size = Size Integer newtype Size = Size Integer
deriving newtype (Eq,Ord,Enum,Num,Real,Integral,Hashable,Pretty) deriving newtype (Eq,Ord,Enum,Num,Real,Integral,Hashable,Pretty,Serialise)
deriving stock (Show) deriving stock (Show)
class ( Monad m class ( Monad m

View File

@ -0,0 +1,39 @@
{-# Language TemplateHaskell #-}
module CLI.Common where
import HBS2.Net.Messaging.Unix
import HBS2.Net.Proto.Service
import PeerConfig
import RPC2.Client.Unix
import RPC2.Service.Unix (getSocketName)
import RPC2.API
import Control.Applicative
import Control.Monad.Reader
import Data.Maybe
import Lens.Micro.Platform
import UnliftIO
data RPCOpt =
RPCOpt
{ _rpcOptConf :: Maybe FilePath
, _rpcOptAddr :: Maybe String
}
makeLenses 'RPCOpt
withMyRPC :: forall api m . (MonadUnliftIO m, api ~ RPC2)
=> RPCOpt
-> (ServiceCaller api UNIX -> m ())
-> m ()
withMyRPC o m = do
conf <- peerConfigRead (view rpcOptConf o)
soConf <- runReaderT getSocketName conf
let soOpt = view rpcOptAddr o
let soname = fromJust $ soOpt <|> Just soConf
withRPC2 @RPC2 @UNIX soname m

View File

@ -6,15 +6,15 @@ import HBS2.Net.Auth.Credentials
import HBS2.Net.Proto.Definition() import HBS2.Net.Proto.Definition()
import HBS2.Net.Proto.RefChan import HBS2.Net.Proto.RefChan
import HBS2.Net.Proto.Types import HBS2.Net.Proto.Types
import HBS2.Net.Messaging.Unix
import HBS2.Data.Types.SignedBox import HBS2.Data.Types.SignedBox
import HBS2.OrDie import HBS2.OrDie
-- FIXME: to-remove-old-rpc -- FIXME: to-remove-old-rpc
import RPC2 --
import CLI.Common
import RPC2.API import RPC2.API
import RPC2.Service.Unix import RPC2.Service.Unix as RPC2
import Options.Applicative import Options.Applicative
import Data.ByteString qualified as BS import Data.ByteString qualified as BS
@ -24,6 +24,7 @@ import Codec.Serialise
import Data.Maybe import Data.Maybe
import System.Exit import System.Exit
pRefChan :: Parser (IO ()) pRefChan :: Parser (IO ())
pRefChan = hsubparser ( command "head" (info pRefChanHead (progDesc "head commands" )) pRefChan = hsubparser ( command "head" (info pRefChanHead (progDesc "head commands" ))
<> command "propose" (info pRefChanPropose (progDesc "post propose transaction")) <> command "propose" (info pRefChanPropose (progDesc "post propose transaction"))
@ -55,9 +56,6 @@ pRefChanHeadGen = do
pRefChanHeadDump :: Parser (IO ()) pRefChanHeadDump :: Parser (IO ())
pRefChanHeadDump= do pRefChanHeadDump= do
fn <- optional $ strArgument (metavar "refchan head blob") fn <- optional $ strArgument (metavar "refchan head blob")
pure $ do pure $ do
lbs <- maybe1 fn LBS.getContents LBS.readFile lbs <- maybe1 fn LBS.getContents LBS.readFile
@ -82,7 +80,7 @@ pRefChanHeadPost :: Parser (IO ())
pRefChanHeadPost = do pRefChanHeadPost = do
opts <- pRpcCommon opts <- pRpcCommon
ref <- strArgument (metavar "HEAD-BLOCK-TREE-HASH") ref <- strArgument (metavar "HEAD-BLOCK-TREE-HASH")
pure $ withRPC2 @UNIX opts $ \caller -> do pure $ withMyRPC opts $ \caller -> do
href <- pure (fromStringMay ref) `orDie` "HEAD-BLOCK-TREE-HASH" href <- pure (fromStringMay ref) `orDie` "HEAD-BLOCK-TREE-HASH"
-- FIXME: proper-error-handling -- FIXME: proper-error-handling
void $ callService @RpcRefChanHeadPost caller href void $ callService @RpcRefChanHeadPost caller href
@ -91,7 +89,7 @@ pRefChanHeadFetch :: Parser (IO ())
pRefChanHeadFetch = do pRefChanHeadFetch = do
opts <- pRpcCommon opts <- pRpcCommon
ref <- strArgument (metavar "REFCHAH-HEAD-KEY") ref <- strArgument (metavar "REFCHAH-HEAD-KEY")
pure $ withRPC2 @UNIX opts $ \caller -> do pure $ withMyRPC opts $ \caller -> do
href <- pure (fromStringMay ref) `orDie` "invalid REFCHAN-HEAD-REF" href <- pure (fromStringMay ref) `orDie` "invalid REFCHAN-HEAD-REF"
void $ callService @RpcRefChanHeadFetch caller href void $ callService @RpcRefChanHeadFetch caller href
@ -99,7 +97,7 @@ pRefChanHeadGet :: Parser (IO ())
pRefChanHeadGet = do pRefChanHeadGet = do
rpc <- pRpcCommon rpc <- pRpcCommon
ref <- strArgument (metavar "REFCHAH-HEAD-KEY") ref <- strArgument (metavar "REFCHAH-HEAD-KEY")
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
href <- pure (fromStringMay ref) `orDie` "invalid REFCHAN-HEAD-REF" href <- pure (fromStringMay ref) `orDie` "invalid REFCHAN-HEAD-REF"
callService @RpcRefChanHeadGet caller href >>= \case callService @RpcRefChanHeadGet caller href >>= \case
Left{} -> exitFailure Left{} -> exitFailure
@ -113,7 +111,7 @@ pRefChanPropose = do
fn <- optional $ strOption (long "file" <> short 'f' <> help "file") fn <- optional $ strOption (long "file" <> short 'f' <> help "file")
dry <- optional (flag' True (long "dry" <> short 'n' <> help "only dump transaction")) <&> fromMaybe False dry <- optional (flag' True (long "dry" <> short 'n' <> help "only dump transaction")) <&> fromMaybe False
sref <- strArgument (metavar "REFCHAH-KEY") sref <- strArgument (metavar "REFCHAH-KEY")
pure $ withRPC2 @UNIX opts $ \caller -> do pure $ withMyRPC opts $ \caller -> do
sc <- BS.readFile kra sc <- BS.readFile kra
puk <- pure (fromStringMay @(RefChanId L4Proto) sref) `orDie` "can't parse refchan/public key" puk <- pure (fromStringMay @(RefChanId L4Proto) sref) `orDie` "can't parse refchan/public key"
creds <- pure (parseCredentials @(Encryption L4Proto) (AsCredFile sc)) `orDie` "bad keyring file" creds <- pure (parseCredentials @(Encryption L4Proto) (AsCredFile sc)) `orDie` "bad keyring file"
@ -134,7 +132,7 @@ pRefChanNotify = do
kra <- strOption (long "author" <> short 'a' <> help "author credentials") kra <- strOption (long "author" <> short 'a' <> help "author credentials")
fn <- optional $ strOption (long "file" <> short 'f' <> help "file") fn <- optional $ strOption (long "file" <> short 'f' <> help "file")
sref <- strArgument (metavar "REFCHAH-REF") sref <- strArgument (metavar "REFCHAH-REF")
pure $ withRPC2 @UNIX opts $ \caller -> do pure $ withMyRPC opts $ \caller -> do
sc <- BS.readFile kra sc <- BS.readFile kra
puk <- pure (fromStringMay @(RefChanId L4Proto) sref) `orDie` "can't parse refchan/public key" puk <- pure (fromStringMay @(RefChanId L4Proto) sref) `orDie` "can't parse refchan/public key"
creds <- pure (parseCredentials @(Encryption L4Proto) (AsCredFile sc)) `orDie` "bad keyring file" creds <- pure (parseCredentials @(Encryption L4Proto) (AsCredFile sc)) `orDie` "bad keyring file"
@ -146,7 +144,7 @@ pRefChanGet :: Parser (IO ())
pRefChanGet = do pRefChanGet = do
opts <- pRpcCommon opts <- pRpcCommon
sref <- strArgument (metavar "REFCHAH-KEY") sref <- strArgument (metavar "REFCHAH-KEY")
pure $ withRPC2 @UNIX opts $ \caller -> do pure $ withMyRPC opts $ \caller -> do
puk <- pure (fromStringMay @(RefChanId L4Proto) sref) `orDie` "can't parse refchan/public key" puk <- pure (fromStringMay @(RefChanId L4Proto) sref) `orDie` "can't parse refchan/public key"
callService @RpcRefChanGet caller puk >>= \case callService @RpcRefChanGet caller puk >>= \case
Left{} -> exitFailure Left{} -> exitFailure
@ -157,7 +155,7 @@ pRefChanFetch :: Parser (IO ())
pRefChanFetch = do pRefChanFetch = do
opts <- pRpcCommon opts <- pRpcCommon
ref <- strArgument (metavar "REFCHAH-KEY") ref <- strArgument (metavar "REFCHAH-KEY")
pure $ withRPC2 @UNIX opts $ \caller -> do pure $ withMyRPC opts $ \caller -> do
href <- pure (fromStringMay ref) `orDie` "invalid REFCHAN-HEAD-REF" href <- pure (fromStringMay ref) `orDie` "invalid REFCHAN-HEAD-REF"
void $ callService @RpcRefChanFetch caller href void $ callService @RpcRefChanFetch caller href

View File

@ -183,6 +183,7 @@ peerConfigRead mbfp = do
else pure x else pure x
canonicalizeConfPaths _ _ x = pure x canonicalizeConfPaths _ _ x = pure x
instance {-# OVERLAPPABLE #-} (IsString b, HasCfgKey a (Maybe b)) => HasCfgValue a (Maybe b) where instance {-# OVERLAPPABLE #-} (IsString b, HasCfgKey a (Maybe b)) => HasCfgValue a (Maybe b) where
cfgValue (PeerConfig syn) = val cfgValue (PeerConfig syn) = val
where where

View File

@ -18,13 +18,12 @@ import HBS2.Data.Types.SignedBox
import HBS2.Data.Types import HBS2.Data.Types
import HBS2.Net.Auth.Credentials import HBS2.Net.Auth.Credentials
import HBS2.Net.IP.Addr import HBS2.Net.IP.Addr
import HBS2.Net.Messaging
import HBS2.Net.Messaging.UDP import HBS2.Net.Messaging.UDP
import HBS2.Net.Messaging.TCP import HBS2.Net.Messaging.TCP
import HBS2.Net.PeerLocator import HBS2.Net.PeerLocator
import HBS2.Net.Proto as Proto import HBS2.Net.Proto as Proto
import HBS2.Net.Proto.Definition import HBS2.Net.Proto.Definition
import HBS2.Net.Proto.Dialog -- import HBS2.Net.Proto.Dialog
import HBS2.Net.Proto.EncryptionHandshake import HBS2.Net.Proto.EncryptionHandshake
import HBS2.Net.Proto.Event.PeerExpired import HBS2.Net.Proto.Event.PeerExpired
import HBS2.Net.Proto.Peer import HBS2.Net.Proto.Peer
@ -35,7 +34,6 @@ import HBS2.Net.Proto.RefLog
import HBS2.Net.Proto.RefChan import HBS2.Net.Proto.RefChan
import HBS2.Net.Proto.Sessions import HBS2.Net.Proto.Sessions
import HBS2.Net.Proto.Service import HBS2.Net.Proto.Service
import HBS2.Net.Messaging.Unix (UNIX,newMessagingUnix,runMessagingUnix)
import HBS2.OrDie import HBS2.OrDie
import HBS2.Storage.Simple import HBS2.Storage.Simple
import HBS2.Data.Detect import HBS2.Data.Detect
@ -46,7 +44,6 @@ import HBS2.System.Logger.Simple hiding (info)
import Data.Config.Suckless.KeyValue(HasConf(..)) import Data.Config.Suckless.KeyValue(HasConf(..))
import Brains import Brains
import RPC2
import PeerTypes import PeerTypes
import BlockDownload import BlockDownload
import BlockHttpDownload import BlockHttpDownload
@ -65,11 +62,13 @@ import ProxyMessaging
-- import PeerMain.DialogCliCommand -- import PeerMain.DialogCliCommand
-- import PeerMain.Dialog.Server -- import PeerMain.Dialog.Server
import PeerMeta import PeerMeta
import CLI.Common
import CLI.RefChan import CLI.RefChan
import RefChan import RefChan
import Log import Log
import RPC2.Service.Unix as RPC2 import RPC2.Service.Unix as RPC2
import RPC2.Service.Storage.Unix qualified as RS
import RPC2.API import RPC2.API
import Codec.Serialise as Serialise import Codec.Serialise as Serialise
@ -270,14 +269,14 @@ runCLI = do
pDie = do pDie = do
rpc <- pRpcCommon rpc <- pRpcCommon
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
l <- async $ void $ callService @RpcDie caller () l <- async $ void $ callService @RpcDie caller ()
pause @'Seconds 0.25 pause @'Seconds 0.25
cancel l cancel l
pPoke = do pPoke = do
rpc <- pRpcCommon rpc <- pRpcCommon
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
r <- callService @RpcPoke caller () r <- callService @RpcPoke caller ()
case r of case r of
Left e -> err (viaShow e) Left e -> err (viaShow e)
@ -286,19 +285,19 @@ runCLI = do
pAnnounce = do pAnnounce = do
rpc <- pRpcCommon rpc <- pRpcCommon
h <- strArgument ( metavar "HASH" ) h <- strArgument ( metavar "HASH" )
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
void $ callService @RpcAnnounce caller h void $ callService @RpcAnnounce caller h
pFetch = do pFetch = do
rpc <- pRpcCommon rpc <- pRpcCommon
h <- strArgument ( metavar "HASH" ) h <- strArgument ( metavar "HASH" )
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
void $ callService @RpcFetch caller h void $ callService @RpcFetch caller h
pPing = do pPing = do
rpc <- pRpcCommon rpc <- pRpcCommon
h <- strArgument ( metavar "ADDR" ) h <- strArgument ( metavar "ADDR" )
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
callService @RpcPing caller h >>= \case callService @RpcPing caller h >>= \case
Left e -> err (viaShow e) Left e -> err (viaShow e)
Right True -> putStrLn "pong" Right True -> putStrLn "pong"
@ -306,7 +305,7 @@ runCLI = do
pPeers = do pPeers = do
rpc <- pRpcCommon rpc <- pRpcCommon
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
r <- callService @RpcPeers caller () r <- callService @RpcPeers caller ()
case r of case r of
Left e -> err (viaShow e) Left e -> err (viaShow e)
@ -317,7 +316,7 @@ runCLI = do
pPexInfo = do pPexInfo = do
rpc <- pRpcCommon rpc <- pRpcCommon
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
r <- callService @RpcPexInfo caller () r <- callService @RpcPexInfo caller ()
case r of case r of
Left e -> err (viaShow e) Left e -> err (viaShow e)
@ -334,7 +333,7 @@ runCLI = do
<|> <|>
hsubparser ( command "debug" (info (onOff DebugOn) (progDesc "set debug") ) ) hsubparser ( command "debug" (info (onOff DebugOn) (progDesc "set debug") ) )
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
void $ callService @RpcLogLevel caller setlog void $ callService @RpcLogLevel caller setlog
pInit = do pInit = do
@ -350,7 +349,7 @@ runCLI = do
pRefLogSend = do pRefLogSend = do
rpc <- pRpcCommon rpc <- pRpcCommon
kr <- strOption (long "keyring" <> short 'k' <> help "reflog keyring" <> metavar "FILE") kr <- strOption (long "keyring" <> short 'k' <> help "reflog keyring" <> metavar "FILE")
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
s <- BS.readFile kr s <- BS.readFile kr
creds <- pure (parseCredentials @(Encryption L4Proto) (AsCredFile s)) `orDie` "bad keyring file" creds <- pure (parseCredentials @(Encryption L4Proto) (AsCredFile s)) `orDie` "bad keyring file"
bs <- BS.take defChunkSize <$> BS.hGetContents stdin bs <- BS.take defChunkSize <$> BS.hGetContents stdin
@ -361,7 +360,7 @@ runCLI = do
pRefLogSendRaw = do pRefLogSendRaw = do
rpc <- pRpcCommon rpc <- pRpcCommon
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
bs <- LBS.take defChunkSize <$> LBS.hGetContents stdin bs <- LBS.take defChunkSize <$> LBS.hGetContents stdin
msg <- pure (deserialiseOrFail @(RefLogUpdate L4Proto) bs) `orDie` "Invalid reflog transaction" msg <- pure (deserialiseOrFail @(RefLogUpdate L4Proto) bs) `orDie` "Invalid reflog transaction"
void $ callService @RpcRefLogPost caller msg void $ callService @RpcRefLogPost caller msg
@ -369,14 +368,14 @@ runCLI = do
pRefLogFetch = do pRefLogFetch = do
rpc <- pRpcCommon rpc <- pRpcCommon
ref <- strArgument ( metavar "REFLOG-KEY" ) ref <- strArgument ( metavar "REFLOG-KEY" )
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
href <- pure (fromStringMay ref) `orDie` "invalid REFLOG-KEY" href <- pure (fromStringMay ref) `orDie` "invalid REFLOG-KEY"
void $ callService @RpcRefLogFetch caller href void $ callService @RpcRefLogFetch caller href
pRefLogGet = do pRefLogGet = do
rpc <- pRpcCommon rpc <- pRpcCommon
ref <- strArgument ( metavar "REFLOG-KEY" ) ref <- strArgument ( metavar "REFLOG-KEY" )
pure $ withRPC2 @UNIX rpc $ \caller -> do pure $ withMyRPC rpc $ \caller -> do
href <- pure (fromStringMay ref) `orDie` "invalid REFLOG-KEY" href <- pure (fromStringMay ref) `orDie` "invalid REFLOG-KEY"
callService @RpcRefLogGet caller href >>= \case callService @RpcRefLogGet caller href >>= \case
Left{} -> exitFailure Left{} -> exitFailure
@ -993,7 +992,17 @@ runPeer opts = Exception.handle (\e -> myException e
rpc2 <- async (runReaderT RPC2.runService rpc2ctx) rpc2 <- async (runReaderT RPC2.runService rpc2ctx)
link rpc2 link rpc2
void $ waitAnyCancel $ w <> [udp,loop,rpc2,ann,messMcast,brainsThread] rpcStorage <- async (runReaderT (RS.runService (AnyStorage s)) conf)
link rpcStorage
void $ waitAnyCancel $ w <> [ udp
, loop
, rpc2
, rpcStorage
, ann
, messMcast
, brainsThread
]
liftIO $ simpleStorageStop s liftIO $ simpleStorageStop s

View File

@ -580,4 +580,3 @@ trace1 :: (MonadIO m, ToLogStr a) => a -> m ()
trace1 = log @TRACE1 trace1 = log @TRACE1

View File

@ -1,60 +1,4 @@
{-# Language TemplateHaskell #-}
module RPC2 where module RPC2 where
import HBS2.Prelude
import HBS2.Clock
import HBS2.Net.Proto.Service
import HBS2.Net.Messaging.Unix
import HBS2.Net.Proto.Types
import HBS2.System.Logger.Simple
import Data.Config.Suckless.KeyValue() import Data.Config.Suckless.KeyValue()
import RPC2.Service.Unix as RPC2
import RPC2.API
import PeerConfig
import Data.Maybe
import Control.Applicative
import Lens.Micro.Platform
import Control.Monad.Reader
import UnliftIO
data RPCOpt =
RPCOpt
{ _rpcOptConf :: Maybe FilePath
, _rpcOptAddr :: Maybe String
}
makeLenses 'RPCOpt
withRPC2 :: forall e m . (e ~ UNIX, HasProtocol e (ServiceProto RPC2 e), MonadUnliftIO m)
=> RPCOpt
-> ( ServiceCaller RPC2 e -> m () )
-> m ()
withRPC2 o action = do
conf <- peerConfigRead (view rpcOptConf o)
soConf <- runReaderT RPC2.getSocketName conf
let soOpt = view rpcOptAddr o
let soname = fromJust $ soOpt <|> Just soConf
debug $ "withRPC2" <+> pretty soname
client1 <- newMessagingUnix False 1.0 soname
m1 <- async $ runMessagingUnix client1
-- link m1
caller <- makeServiceCaller @RPC2 @UNIX (fromString soname)
p2 <- liftIO $ async $ runReaderT (runServiceClient @RPC2 @UNIX caller) client1
action caller
pause @'Seconds 0.05
cancel p2
void $ waitAnyCatchCancel [m1, p2]

View File

@ -45,4 +45,3 @@ type RPC2 = '[ RpcPoke
, RpcDie , RpcDie
] ]

View File

@ -0,0 +1,6 @@
module RPC2.Client.Unix
( module HBS2.Peer.RPC.Client.Unix
)where
import HBS2.Peer.RPC.Client.Unix

View File

@ -0,0 +1,8 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
module RPC2.Service.Storage.Unix
( module HBS2.Peer.RPC.Internal.Service.Storage.Unix
)
where
import HBS2.Peer.RPC.Internal.Service.Storage.Unix

View File

@ -0,0 +1,8 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
module RPC2.Storage
( module HBS2.Peer.RPC.API.Storage
, module HBS2.Peer.RPC.Internal.Storage
) where
import HBS2.Peer.RPC.API.Storage
import HBS2.Peer.RPC.Internal.Storage

View File

@ -1,9 +1,13 @@
module RPC2.Types where module RPC2.Types
( module RPC2.Types
, module HBS2.Peer.RPC.Class
) where
import HBS2.Actors.Peer import HBS2.Actors.Peer
import HBS2.Net.Proto.Types import HBS2.Net.Proto.Types
import HBS2.Data.Types.Refs (HashRef) import HBS2.Data.Types.Refs (HashRef)
import HBS2.Data.Types.SignedBox import HBS2.Data.Types.SignedBox
import HBS2.Peer.RPC.Class
import Data.Config.Suckless.Syntax import Data.Config.Suckless.Syntax
import PeerTypes (DownloadEnv(..)) import PeerTypes (DownloadEnv(..))
@ -24,6 +28,4 @@ data RPC2Context =
, rpcDoRefChanNotify :: (PubKey 'Sign HBS2Basic, SignedBox ByteString L4Proto) -> IO () , rpcDoRefChanNotify :: (PubKey 'Sign HBS2Basic, SignedBox ByteString L4Proto) -> IO ()
} }
class HasRpcContext a m where
getRpcContext :: m a

View File

@ -0,0 +1,48 @@
module RPC2.Client.Unix where
import HBS2.Prelude.Plated
import HBS2.Clock
import HBS2.Net.Messaging.Unix
import HBS2.Net.Proto
import HBS2.Net.Proto.Service
import HBS2.System.Logger.Simple
import RPC2.Service.Unix()
import Data.Config.Suckless.KeyValue()
import Control.Monad.Reader
import UnliftIO
withRPC2 :: forall api e m . ( e ~ UNIX
, HasProtocol e (ServiceProto api e)
, MonadUnliftIO m
-- FIXME: remove-this-debug-shit
, MonadUnliftIO m
)
=> FilePath
-> ( ServiceCaller api e -> m () )
-> m ()
withRPC2 soname action = do
debug $ "withRPC2" <+> pretty soname
client1 <- newMessagingUnix False 1.0 soname
m1 <- async $ runMessagingUnix client1
-- link m1
caller <- makeServiceCaller @api @UNIX (fromString soname)
p2 <- liftIO $ async $ runReaderT (runServiceClient @api @e caller) client1
action caller
pause @'Seconds 0.05
cancel p2
void $ waitAnyCatchCancel [m1, p2]

View File

@ -123,6 +123,21 @@ common shared-properties
, TypeFamilies , TypeFamilies
library
import: shared-properties
import: common-deps
hs-source-dirs: lib
default-language: Haskell2010
exposed-modules:
HBS2.Peer.RPC.Class
HBS2.Peer.RPC.API
HBS2.Peer.RPC.API.Storage
HBS2.Peer.RPC.Client.Unix
HBS2.Peer.RPC.Internal.Storage
HBS2.Peer.RPC.Internal.Service.Storage.Unix
executable hbs2-peer executable hbs2-peer
import: shared-properties import: shared-properties
@ -147,7 +162,9 @@ executable hbs2-peer
, Fetch , Fetch
, Log , Log
, RPC2 , RPC2
, RPC2.Client.Unix
, RPC2.Service.Unix , RPC2.Service.Unix
, RPC2.Service.Storage.Unix
, RPC2.API , RPC2.API
, RPC2.Types , RPC2.Types
, RPC2.Poke , RPC2.Poke
@ -160,6 +177,7 @@ executable hbs2-peer
, RPC2.Ping , RPC2.Ping
, RPC2.RefLog , RPC2.RefLog
, RPC2.RefChan , RPC2.RefChan
, RPC2.Storage
, PeerTypes , PeerTypes
, PeerConfig , PeerConfig
, RefLog , RefLog
@ -168,11 +186,14 @@ executable hbs2-peer
, HttpWorker , HttpWorker
, Brains , Brains
, ProxyMessaging , ProxyMessaging
, CLI.Common
, CLI.RefChan , CLI.RefChan
-- other-extensions: -- other-extensions:
build-depends: base build-depends: base, hbs2-peer
hs-source-dirs: app hs-source-dirs: app
default-language: Haskell2010 default-language: Haskell2010

View File

@ -0,0 +1,3 @@
module HBS2.Peer.RPC.API where

View File

@ -0,0 +1,22 @@
module HBS2.Peer.RPC.API.Storage where
data RpcStorageHasBlock
data RpcStorageGetBlock
data RpcStorageEnqueueBlock
data RpcStoragePutBlock
data RpcStorageGetChunk
data RpcStorageGetRef
data RpcStorageUpdateRef
data RpcStorageDelRef
type StorageAPI = '[ RpcStorageHasBlock
, RpcStorageHasBlock
, RpcStorageGetBlock
, RpcStorageEnqueueBlock
, RpcStoragePutBlock
, RpcStorageGetChunk
, RpcStorageGetRef
, RpcStorageUpdateRef
, RpcStorageDelRef
]

View File

@ -0,0 +1,6 @@
module HBS2.Peer.RPC.Class where
class HasRpcContext a m where
getRpcContext :: m a

View File

@ -0,0 +1,46 @@
module HBS2.Peer.RPC.Client.Unix where
import HBS2.Prelude.Plated
import HBS2.Clock
import HBS2.Net.Messaging.Unix
import HBS2.Net.Proto
import HBS2.Net.Proto.Service
import HBS2.Peer.RPC.Internal.Service.Storage.Unix()
import HBS2.System.Logger.Simple
import Data.Kind
import Control.Monad.Reader
import UnliftIO
withRPC2 :: forall (api :: [Type]) e m . ( e ~ UNIX
, HasProtocol e (ServiceProto api e)
, MonadUnliftIO m
-- FIXME: remove-this-debug-shit
, MonadUnliftIO m
)
=> FilePath
-> ( ServiceCaller api e -> m () )
-> m ()
withRPC2 soname action = do
debug $ "withRPC2" <+> pretty soname
client1 <- newMessagingUnix False 1.0 soname
m1 <- async $ runMessagingUnix client1
-- link m1
caller <- makeServiceCaller @api @UNIX (fromString soname)
p2 <- liftIO $ async $ runReaderT (runServiceClient @api @e caller) client1
action caller
pause @'Seconds 0.05
cancel p2
void $ waitAnyCatchCancel [m1, p2]

View File

@ -0,0 +1,81 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
module HBS2.Peer.RPC.Internal.Service.Storage.Unix where
import HBS2.Prelude.Plated
import HBS2.Actors.Peer
import HBS2.Net.Proto
import HBS2.Net.Proto.Service
import HBS2.Net.Messaging.Unix
import HBS2.Peer.RPC.API.Storage
import HBS2.Peer.RPC.Internal.Storage
import HBS2.System.Logger.Simple
import Data.Config.Suckless.Syntax
import Data.Config.Suckless.KeyValue
import Data.ByteString.Lazy (ByteString)
import Data.Text qualified as Text
import Control.Monad.Reader
import Codec.Serialise
import UnliftIO
instance HasProtocol UNIX (ServiceProto StorageAPI UNIX) where
type instance ProtocolId (ServiceProto StorageAPI UNIX) = 0xDA2374610001
type instance Encoded UNIX = ByteString
decode = either (const Nothing) Just . deserialiseOrFail
encode = serialise
sodef :: FilePath
sodef = "/tmp/hbs2-rpc2.storage.socket"
getSocketName :: HasConf m => m FilePath
getSocketName = do
syn <- getConf
let soname = lastDef sodef [ Text.unpack n
| ListVal @C (Key "rpc2.storage" [SymbolVal "unix", LitStrVal n]) <- syn
]
pure soname
instance MonadUnliftIO m => (HasDeferred UNIX (ServiceProto StorageAPI UNIX) m) where
deferred _ m = void $ async m
instance Monad m => HasFabriq UNIX (ReaderT (AnyStorage, MessagingUnix) m) where
getFabriq = asks (Fabriq . snd)
instance Monad m => HasOwnPeer UNIX (ReaderT (AnyStorage, MessagingUnix) m) where
ownPeer = asks ( msgUnixSelf . snd )
-- FIXME: fix-this-ugly-shit
instance Monad m
=> HasRpcContext AnyStorage (ResponseM UNIX (ReaderT (AnyStorage, MessagingUnix) m)) where
getRpcContext = lift $ asks fst
runService :: ( HasConf m
, MonadUnliftIO m
, HasDeferred UNIX (ServiceProto StorageAPI UNIX) m
)
=> AnyStorage -> m ()
runService sto = do
soname <- getSocketName
notice $ "RPC2 Storage Service started" <+> pretty soname
server <- newMessagingUnixOpts [MUFork] True 1.0 soname
m1 <- async $ runMessagingUnix server
link m1
flip runReaderT (sto, server) do
runProto @UNIX
[ makeResponse (makeServer @StorageAPI)
]

View File

@ -0,0 +1,90 @@
{-# OPTIONS_GHC -fno-warn-orphans #-}
module HBS2.Peer.RPC.Internal.Storage
( module HBS2.Peer.RPC.API.Storage
, module HBS2.Peer.RPC.Class
)
where
import HBS2.Actors.Peer.Types
import HBS2.Prelude.Plated
import HBS2.Data.Types.Refs (HashRef(..),RefAlias(..))
import HBS2.Storage
import HBS2.Peer.RPC.Class
import HBS2.Peer.RPC.API.Storage
import HBS2.Net.Proto.Service
import Data.Functor
import Data.ByteString.Lazy ( ByteString )
import Control.Monad.Reader
instance Monad m => HasRpcContext AnyStorage (ReaderT AnyStorage m) where
getRpcContext = ask
instance (MonadIO m, HasRpcContext AnyStorage m) => HandleMethod m RpcStorageHasBlock where
type instance Input RpcStorageHasBlock = HashRef
type instance Output RpcStorageHasBlock = Maybe Integer
handleMethod href = do
sto <- getRpcContext @AnyStorage
liftIO $ hasBlock sto (fromHashRef href)
instance (MonadIO m, HasRpcContext AnyStorage m) => HandleMethod m RpcStorageGetBlock where
type instance Input RpcStorageGetBlock = HashRef
type instance Output RpcStorageGetBlock = Maybe ByteString
handleMethod href = do
sto <- getRpcContext @AnyStorage
liftIO $ getBlock sto (fromHashRef href)
instance (MonadIO m, HasRpcContext AnyStorage m) => HandleMethod m RpcStorageEnqueueBlock where
type instance Input RpcStorageEnqueueBlock = ByteString
type instance Output RpcStorageEnqueueBlock = Maybe HashRef
handleMethod lbs = do
sto <- getRpcContext @AnyStorage
liftIO $ enqueueBlock sto lbs <&> fmap HashRef
instance (MonadIO m, HasRpcContext AnyStorage m) => HandleMethod m RpcStoragePutBlock where
type instance Input RpcStoragePutBlock = ByteString
type instance Output RpcStoragePutBlock = Maybe HashRef
handleMethod lbs = do
sto <- getRpcContext @AnyStorage
liftIO $ putBlock sto lbs <&> fmap HashRef
instance (MonadIO m, HasRpcContext AnyStorage m) => HandleMethod m RpcStorageGetChunk where
type instance Input RpcStorageGetChunk = (HashRef, Offset, Size)
type instance Output RpcStorageGetChunk = Maybe ByteString
handleMethod (h,o,s) = do
sto <- getRpcContext @AnyStorage
liftIO $ getChunk sto (fromHashRef h) o s
instance (MonadIO m, HasRpcContext AnyStorage m) => HandleMethod m RpcStorageGetRef where
type instance Input RpcStorageGetRef = RefAlias
type instance Output RpcStorageGetRef = Maybe HashRef
handleMethod ref = do
sto <- getRpcContext @AnyStorage
liftIO $ getRef sto ref <&> fmap HashRef
instance (MonadIO m, HasRpcContext AnyStorage m) => HandleMethod m RpcStorageUpdateRef where
type instance Input RpcStorageUpdateRef = (RefAlias, HashRef)
type instance Output RpcStorageUpdateRef = ()
handleMethod (ref, val) = do
sto <- getRpcContext @AnyStorage
liftIO $ updateRef sto ref (fromHashRef val)
instance (MonadIO m, HasRpcContext AnyStorage m) => HandleMethod m RpcStorageDelRef where
type instance Input RpcStorageDelRef = RefAlias
type instance Output RpcStorageDelRef = ()
handleMethod ref = do
sto <- getRpcContext @AnyStorage
liftIO $ delRef sto ref

View File

@ -18,7 +18,7 @@ common warnings
common common-deps common common-deps
build-depends: build-depends:
base, hbs2-core, hbs2-storage-simple base, hbs2-core, hbs2-storage-simple, hbs2-peer
, async , async
, bytestring , bytestring
, cache , cache
@ -313,6 +313,57 @@ test-suite test-proto-service
, vector , vector
-- executable test-proto-service
test-suite test-storage-service
import: shared-properties
import: common-deps
default-language: Haskell2010
ghc-options:
-- -prof
-- -fprof-auto
other-modules:
-- other-extensions:
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: StorageServiceTest.hs
build-depends:
base, hbs2-core, hbs2-storage-simple, hbs2-peer
, async
, attoparsec
, bytestring
, cache
, clock
, containers
, data-default
, data-textual
, directory
, hashable
, microlens-platform
, mtl
, mwc-random
, network
, network-ip
, prettyprinter
, QuickCheck
, random
, safe
, serialise
, stm
, streaming
, tasty
, tasty-hunit
, text
, transformers
, uniplate
, vector
test-suite test-tcp test-suite test-tcp
import: shared-properties import: shared-properties
import: common-deps import: common-deps

View File

@ -0,0 +1,134 @@
module Main where
import HBS2.Hash
import HBS2.Actors.Peer
import HBS2.Actors.Peer.Types
import HBS2.Data.Types.Refs
import HBS2.Net.Messaging.Unix
import HBS2.Net.Proto.Service
import HBS2.Storage
import HBS2.Storage.Simple (simpleStorageWorker,simpleStorageInit,SimpleStorage(..))
import HBS2.Peer.RPC.API.Storage
import HBS2.Peer.RPC.Client.Unix
import HBS2.Peer.RPC.Internal.Storage()
import HBS2.Peer.RPC.Internal.Service.Storage.Unix()
import HBS2.OrDie
import HBS2.System.Logger.Simple
import Control.Monad.Reader
import System.FilePath
import UnliftIO
import Prettyprinter
import Data.ByteString.Lazy qualified as LBS
import Data.ByteString.Lazy (ByteString)
import Data.Maybe
import Test.Tasty.HUnit
main :: IO ()
main = do
setLogging @DEBUG (logPrefix "[debug] ")
setLogging @INFO (logPrefix "")
withSystemTempDirectory "storageRpcTest" $ \dir -> do
let soname = dir </> "rpc.socket"
let opts = [ StoragePrefix (dir </> ".storage")
]
sto <- simpleStorageInit @HbSync opts
worker <- async (simpleStorageWorker sto)
link worker
let blk1 = "AAAAA"
h1 <- putBlock sto blk1 `orDie` "can't write block"
debug $ "written" <+> pretty h1
let rk1 = SomeRefKey ("SOMEREFKEY1" :: ByteString)
updateRef sto rk1 h1
rk1val <- getRef sto rk1
info $ "rk1val:" <+> pretty rk1val
rk1val1 <- getRef sto (refAlias rk1)
info $ "rk1val1:" <+> pretty rk1val1
assertBool "ref-alias-works-1" ( fromJust rk1val == fromJust rk1val1 )
server <- newMessagingUnix True 1.0 soname
m1 <- async $ runMessagingUnix server
link m1
proto <- async $ flip runReaderT (AnyStorage sto, server) do
runProto @UNIX
[ makeResponse (makeServer @StorageAPI)
]
link proto
withRPC2 @StorageAPI soname $ \caller -> do
info "does it work?"
size <- callService @RpcStorageHasBlock caller (HashRef h1) `orDie` "can't read block"
info $ "got block size: " <+> pretty size
assertBool "block-size-1" (size == Just (fromIntegral $ LBS.length blk1))
b <- callService @RpcStorageGetBlock caller (HashRef h1) `orDie` "can't read block"
info $ "got block" <+> viaShow b
assertBool "block-eq-1" ( b == Just blk1 )
let pechen = "PECHENTERSKI"
h2 <- callService @RpcStoragePutBlock caller pechen `orDie` "service error"
info $ "stored block hash:" <+> pretty h2
let hh2 = fromJust h2
blk2 <- callService @RpcStorageGetBlock caller hh2 `orDie` "block lookup failed"
info $ "stored block value:" <+> viaShow blk2
assertBool "block-eq-2" (Just pechen == blk2)
let rk2 = refAlias rk1
rk2val <- callService @RpcStorageGetRef caller rk2 `orDie` "can't read ref"
info $ "rk2val:" <+> pretty rk2val
assertBool "ref-alias-works-2" (fromJust rk2val == HashRef h1)
callService @RpcStorageUpdateRef caller (rk2, hh2)
rk3val <- callService @RpcStorageGetRef caller rk2 `orDie` "can't update ref"
info $ "rk3val" <+> pretty rk3val
assertBool "ref-alias-update-works-1" (fromJust rk3val == hh2)
rk4val <- getRef sto rk1
info $ "rk4val" <+> pretty rk4val
assertBool "ref-alias-works-2" (fromJust rk4val == fromHashRef hh2)
setLoggingOff @DEBUG
setLoggingOff @INFO