This commit is contained in:
Dmitry Zuikov 2023-01-21 14:41:26 +03:00
parent 31c49e2169
commit 76579675b6
5 changed files with 94 additions and 78 deletions

View File

@ -66,7 +66,7 @@ library
exposed-modules: exposed-modules:
HBS2.Actors HBS2.Actors
, HBS2.Actors.ChunkWriter , HBS2.Actors.ChunkWriter
, HBS2.Actors.Peer -- , HBS2.Actors.Peer
, HBS2.Clock , HBS2.Clock
, HBS2.Data.Types , HBS2.Data.Types
, HBS2.Data.Types.Refs , HBS2.Data.Types.Refs
@ -78,9 +78,10 @@ library
, HBS2.Net.PeerLocator , HBS2.Net.PeerLocator
, HBS2.Net.PeerLocator.Static , HBS2.Net.PeerLocator.Static
, HBS2.Net.Proto , HBS2.Net.Proto
, HBS2.Net.Proto.Types
, HBS2.Net.Proto.BlockInfo
, HBS2.Net.Proto.BlockChunks , HBS2.Net.Proto.BlockChunks
, HBS2.Net.Proto.BlockInfo
, HBS2.Net.Proto.Sessions
, HBS2.Net.Proto.Types
, HBS2.Prelude , HBS2.Prelude
, HBS2.Prelude.Plated , HBS2.Prelude.Plated
, HBS2.Storage , HBS2.Storage

View File

@ -31,25 +31,6 @@ import Data.Maybe
import Codec.Serialise hiding (encode,decode) import Codec.Serialise hiding (encode,decode)
data SKey = forall a . (Unkey a, Eq a, Hashable a) => SKey (Proxy a) Dynamic
class Typeable a => Unkey a where
unfuck :: Proxy a -> Dynamic -> Maybe a
instance Typeable a => Unkey a where
unfuck _ = fromDynamic @a
newSKey :: forall a . (Eq a, Typeable a, Unkey a, Hashable a) => a -> SKey
newSKey s = SKey (Proxy @a) (toDyn s)
instance Hashable SKey where
hashWithSalt s (SKey p d) = hashWithSalt s (unfuck p d)
instance Eq SKey where
(==) (SKey p1 a) (SKey p2 b) = unfuck p1 a == unfuck p1 b
data AnyMessage e = AnyMessage Integer (Encoded e) data AnyMessage e = AnyMessage Integer (Encoded e)
deriving stock (Generic) deriving stock (Generic)

View File

@ -2,6 +2,7 @@ module HBS2.Net.Proto.BlockInfo where
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
import HBS2.Net.Proto import HBS2.Net.Proto
import HBS2.Net.Proto.Sessions
import HBS2.Hash import HBS2.Hash
import Codec.Serialise () import Codec.Serialise ()

View File

@ -11,7 +11,6 @@ import GHC.TypeLits
import Data.Proxy import Data.Proxy
import Data.Hashable import Data.Hashable
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Data.Typeable
import System.Random qualified as Random import System.Random qualified as Random
import Data.Digest.Murmur32 import Data.Digest.Murmur32
@ -41,58 +40,6 @@ class Request e p (m :: Type -> Type) | p -> e where
request :: Peer e -> p -> m () request :: Peer e -> p -> m ()
-- we probably can not separate sessions
-- by sub-protocol types without
-- really crazy types.
--
-- And if we really need this, it may be done
-- by injecting a protocol type into 'e' or
-- introducing a common ADT for all session types
-- for common 'e' i.e. 'engine' or 'transport'
--
-- So it is that it is.
data family SessionKey e p :: Type
type family SessionData e p :: Type
class ( Monad m
, HasProtocol e p
, Eq (SessionKey e p)
, Hashable (SessionKey e p)
, Typeable (SessionData e p)
-- , Typeable e
-- , Typeable p
) => Sessions e p m | p -> e where
-- | Session fetch function.
-- | It will insert a new session, if default value is Just something.
find :: SessionKey e p -- ^ session key
-> (SessionData e p -> a) -- ^ modification function, i.e. lens
-> m (Maybe a)
-- | Session fetch function.
-- | It will insert a new session, if default value is Just something.
fetch :: Bool -- ^ do add new session if not exists
-> SessionData e p -- ^ default value in case it's not found
-> SessionKey e p -- ^ session key
-> (SessionData e p -> a ) -- ^ modification function, i.e. lens
-> m a
-- | Session update function
-- | If will create a new session if it does not exist.
-- | A modified value (or default) value will we saved.
update :: SessionData e p -- ^ default value in case it's not found
-> SessionKey e p -- ^ session key
-> (SessionData e p -> SessionData e p) -- ^ modification function, i.e. lens
-> m ()
expire :: SessionKey e p -> m ()
class (KnownNat (ProtocolId p), HasPeer e) => HasProtocol e p | p -> e where class (KnownNat (ProtocolId p), HasPeer e) => HasProtocol e p | p -> e where
type family ProtocolId p = (id :: Nat) | id -> p type family ProtocolId p = (id :: Nat) | id -> p

View File

@ -12,6 +12,7 @@ import HBS2.Hash
import HBS2.Net.Messaging import HBS2.Net.Messaging
import HBS2.Net.Messaging.Fake import HBS2.Net.Messaging.Fake
import HBS2.Net.Proto import HBS2.Net.Proto
import HBS2.Net.Proto.Sessions
import HBS2.Net.Proto.BlockChunks import HBS2.Net.Proto.BlockChunks
import HBS2.Net.Proto.BlockInfo import HBS2.Net.Proto.BlockInfo
import HBS2.Prelude.Plated import HBS2.Prelude.Plated
@ -26,10 +27,14 @@ import Control.Concurrent.Async
import Control.Monad.Reader import Control.Monad.Reader
import Data.ByteString.Lazy (ByteString) import Data.ByteString.Lazy (ByteString)
import Data.ByteString.Lazy.Char8 qualified as B8 import Data.ByteString.Lazy.Char8 qualified as B8
import Data.Cache (Cache)
import Data.Cache qualified as Cache
import Data.Default import Data.Default
import Data.Foldable import Data.Dynamic
import Data.Foldable hiding (find)
import Data.Map (Map) import Data.Map (Map)
import Data.Map qualified as Map import Data.Map qualified as Map
import Data.Maybe
import Data.Word import Data.Word
import GHC.TypeLits import GHC.TypeLits
import Lens.Micro.Platform import Lens.Micro.Platform
@ -79,7 +84,7 @@ instance HasProtocol Fake (BlockChunks Fake) where
encode = serialise encode = serialise
type instance SessionData Fake (BlockSize Fake) = BlockSizeSession Fake type instance SessionData e (BlockSize e) = BlockSizeSession e
type instance SessionData Fake (BlockChunks Fake) = BlockDownload type instance SessionData Fake (BlockChunks Fake) = BlockDownload
newtype instance SessionKey Fake (BlockChunks Fake) = newtype instance SessionKey Fake (BlockChunks Fake) =
@ -160,6 +165,7 @@ data PeerEnv e =
, _envFab :: Fabriq e , _envFab :: Fabriq e
, _envStorage :: AnyStorage , _envStorage :: AnyStorage
, _envDeferred :: Pipeline IO () , _envDeferred :: Pipeline IO ()
, _envSessions :: Cache SKey Dynamic
} }
newtype PeerM e m a = PeerM { fromPeerM :: ReaderT (PeerEnv e) m a } newtype PeerM e m a = PeerM { fromPeerM :: ReaderT (PeerEnv e) m a }
@ -206,9 +212,56 @@ instance Monad m => HasFabriq e (PeerM e m) where
instance Monad m => HasStorage (PeerM e m) where instance Monad m => HasStorage (PeerM e m) where
getStorage = asks (view envStorage) getStorage = asks (view envStorage)
instance ( MonadIO m
, HasProtocol e p
, Eq (SessionKey e p)
, Typeable (SessionKey e p)
, Typeable (SessionData e p)
, Hashable (SessionKey e p)
) => Sessions e p (PeerM e m) where
find k f = do
se <- asks (view envSessions)
let sk = newSKey @(SessionKey e p) k
r <- liftIO $ Cache.lookup se sk
case fromDynamic @(SessionData e p) <$> r of
Just v -> pure $ f <$> v
Nothing -> pure Nothing
fetch upd de k fn = do
se <- asks (view envSessions)
let sk = newSKey @(SessionKey e p) k
let ddef = toDyn de
r <- liftIO $ Cache.lookup se sk
case r of
Just v -> pure $ fn $ fromMaybe de (fromDynamic @(SessionData e p) v )
Nothing -> do
when upd $ liftIO $ Cache.insert se sk ddef
pure (fn de)
update de k f = do
se <- asks (view envSessions)
val <- fetch @e @p True de k id
liftIO $ Cache.insert se (newSKey @(SessionKey e p) k) (toDyn (f val))
expire k = do
se <- asks (view envSessions)
liftIO $ Cache.delete se (newSKey @(SessionKey e p) k)
runPeerM :: MonadIO m => AnyStorage -> Fabriq e -> Peer e -> PeerM e m a -> m () runPeerM :: MonadIO m => AnyStorage -> Fabriq e -> Peer e -> PeerM e m a -> m ()
runPeerM s bus p f = do runPeerM s bus p f = do
env <- PeerEnv p bus s <$> newPipeline defProtoPipelineSize env <- PeerEnv p bus s <$> newPipeline defProtoPipelineSize
<*> liftIO (Cache.newCache (Just defCookieTimeout))
let de = view envDeferred env let de = view envDeferred env
as <- liftIO $ async $ runPipeline de as <- liftIO $ async $ runPipeline de
void $ runReaderT (fromPeerM f) env void $ runReaderT (fromPeerM f) env
@ -277,6 +330,25 @@ instance ( HasProtocol e p
sendTo fab (To who) (From self) bs sendTo fab (To who) (From self) bs
instance ( MonadIO m
, HasProtocol e p
, Sessions e p m
, Eq (SessionKey e p)
, Typeable (SessionKey e p)
, Typeable (SessionData e p)
, Hashable (SessionKey e p)
) => Sessions e p (ResponseM e m) where
find k f = lift (find k f)
fetch i d k f = lift (fetch i d k f)
update d k f = lift (update d k f)
expire k = lift (expire k)
runTestPeer :: Peer Fake runTestPeer :: Peer Fake
-> (SimpleStorage HbSync -> IO ()) -> (SimpleStorage HbSync -> IO ())
-> IO () -> IO ()
@ -304,7 +376,21 @@ runTestPeer p zu = do
mapM_ cancel [sw,cw] mapM_ cancel [sw,cw]
handleBlockInfo :: forall e m . ( Monad m
, Sessions e (BlockSize e) m
, Default (SessionData e (BlockSize e))
, Ord (Peer e)
)
=> (Peer e, Hash HbSync, Maybe Integer)
-> m ()
handleBlockInfo (p, h, sz') = do
maybe1 sz' (pure ()) $ \sz -> do
let bsz = fromIntegral sz
update @e def (BlockSizeKey h) (over bsBlockSizes (Map.insert p bsz))
-- FIXME: turn back on event notification
-- lift $ runEngineM env $ emitBlockSizeEvent ev h (p, h, Just sz) -- TODO: fix this crazy shit
main :: IO () main :: IO ()
main = do main = do
@ -340,7 +426,7 @@ main = do
let blk = hasBlock s let blk = hasBlock s
runPeerM (AnyStorage s) fake p0 $ do runPeerM (AnyStorage s) fake p0 $ do
runProto @Fake runProto @Fake
[ makeResponse (blockSizeProto blk dontHandle) [ makeResponse (blockSizeProto blk handleBlockInfo)
-- , makeResponse (blockChunksProto undefined) -- , makeResponse (blockChunksProto undefined)
] ]