mirror of https://github.com/voidlizard/hbs2
wip
This commit is contained in:
parent
31c49e2169
commit
76579675b6
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 ()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue