{-# LANGUAGE NamedFieldPuns #-}
module Network.HTTP2.Arch.Context where
import Control.Concurrent.STM
import Data.IORef
import Network.HTTP.Types (Method)
import Imports hiding (insert)
import Network.HPACK
import Network.HTTP2.Arch.Cache (Cache, emptyCache)
import qualified Network.HTTP2.Arch.Cache as Cache
import Network.HTTP2.Arch.Rate
import Network.HTTP2.Arch.Stream
import Network.HTTP2.Arch.Types
import Network.HTTP2.Frame
data Role = Client | Server deriving (Role -> Role -> Bool
(Role -> Role -> Bool) -> (Role -> Role -> Bool) -> Eq Role
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Role -> Role -> Bool
$c/= :: Role -> Role -> Bool
== :: Role -> Role -> Bool
$c== :: Role -> Role -> Bool
Eq,Int -> Role -> ShowS
[Role] -> ShowS
Role -> String
(Int -> Role -> ShowS)
-> (Role -> String) -> ([Role] -> ShowS) -> Show Role
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Role] -> ShowS
$cshowList :: [Role] -> ShowS
show :: Role -> String
$cshow :: Role -> String
showsPrec :: Int -> Role -> ShowS
$cshowsPrec :: Int -> Role -> ShowS
Show)
data RoleInfo = ServerInfo {
RoleInfo -> TQueue (Input Stream)
inputQ :: TQueue (Input Stream)
}
| ClientInfo {
RoleInfo -> ByteString
scheme :: ByteString
, RoleInfo -> ByteString
authority :: ByteString
, RoleInfo -> IORef (Cache (ByteString, ByteString) Stream)
cache :: IORef (Cache (Method,ByteString) Stream)
}
newServerInfo :: IO RoleInfo
newServerInfo :: IO RoleInfo
newServerInfo = TQueue (Input Stream) -> RoleInfo
ServerInfo (TQueue (Input Stream) -> RoleInfo)
-> IO (TQueue (Input Stream)) -> IO RoleInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO (TQueue (Input Stream))
forall a. IO (TQueue a)
newTQueueIO
newClientInfo :: ByteString -> ByteString -> Int -> IO RoleInfo
newClientInfo :: ByteString -> ByteString -> Int -> IO RoleInfo
newClientInfo ByteString
scm ByteString
auth Int
lim = ByteString
-> ByteString
-> IORef (Cache (ByteString, ByteString) Stream)
-> RoleInfo
ClientInfo ByteString
scm ByteString
auth (IORef (Cache (ByteString, ByteString) Stream) -> RoleInfo)
-> IO (IORef (Cache (ByteString, ByteString) Stream))
-> IO RoleInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Cache (ByteString, ByteString) Stream
-> IO (IORef (Cache (ByteString, ByteString) Stream))
forall a. a -> IO (IORef a)
newIORef (Int -> Cache (ByteString, ByteString) Stream
forall k v. Int -> Cache k v
emptyCache Int
lim)
insertCache :: Method -> ByteString -> Stream -> RoleInfo -> IO ()
insertCache :: ByteString -> ByteString -> Stream -> RoleInfo -> IO ()
insertCache ByteString
m ByteString
path Stream
v (ClientInfo ByteString
_ ByteString
_ IORef (Cache (ByteString, ByteString) Stream)
ref) = IORef (Cache (ByteString, ByteString) Stream)
-> (Cache (ByteString, ByteString) Stream
-> (Cache (ByteString, ByteString) Stream, ()))
-> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef (Cache (ByteString, ByteString) Stream)
ref ((Cache (ByteString, ByteString) Stream
-> (Cache (ByteString, ByteString) Stream, ()))
-> IO ())
-> (Cache (ByteString, ByteString) Stream
-> (Cache (ByteString, ByteString) Stream, ()))
-> IO ()
forall a b. (a -> b) -> a -> b
$ \Cache (ByteString, ByteString) Stream
c ->
((ByteString, ByteString)
-> Stream
-> Cache (ByteString, ByteString) Stream
-> Cache (ByteString, ByteString) Stream
forall k v. Ord k => k -> v -> Cache k v -> Cache k v
Cache.insert (ByteString
m,ByteString
path) Stream
v Cache (ByteString, ByteString) Stream
c, ())
insertCache ByteString
_ ByteString
_ Stream
_ RoleInfo
_ = String -> IO ()
forall a. HasCallStack => String -> a
error String
"insertCache"
lookupCache :: Method -> ByteString -> RoleInfo -> IO (Maybe Stream)
lookupCache :: ByteString -> ByteString -> RoleInfo -> IO (Maybe Stream)
lookupCache ByteString
m ByteString
path (ClientInfo ByteString
_ ByteString
_ IORef (Cache (ByteString, ByteString) Stream)
ref) = (ByteString, ByteString)
-> Cache (ByteString, ByteString) Stream -> Maybe Stream
forall k v. Ord k => k -> Cache k v -> Maybe v
Cache.lookup (ByteString
m,ByteString
path) (Cache (ByteString, ByteString) Stream -> Maybe Stream)
-> IO (Cache (ByteString, ByteString) Stream) -> IO (Maybe Stream)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef (Cache (ByteString, ByteString) Stream)
-> IO (Cache (ByteString, ByteString) Stream)
forall a. IORef a -> IO a
readIORef IORef (Cache (ByteString, ByteString) Stream)
ref
lookupCache ByteString
_ ByteString
_ RoleInfo
_ = String -> IO (Maybe Stream)
forall a. HasCallStack => String -> a
error String
"lookupCache"
data Context = Context {
Context -> Role
role :: Role
, Context -> RoleInfo
roleInfo :: RoleInfo
, Context -> IORef Settings
http2settings :: IORef Settings
, Context -> IORef Bool
firstSettings :: IORef Bool
, Context -> StreamTable
streamTable :: StreamTable
, Context -> IORef Int
concurrency :: IORef Int
, Context -> IORef (Maybe Int)
continued :: IORef (Maybe StreamId)
, Context -> IORef Int
myStreamId :: IORef StreamId
, Context -> IORef Int
peerStreamId :: IORef StreamId
, Context -> TQueue (Output Stream)
outputQ :: TQueue (Output Stream)
, Context -> TQueue Control
controlQ :: TQueue Control
, Context -> DynamicTable
encodeDynamicTable :: DynamicTable
, Context -> DynamicTable
decodeDynamicTable :: DynamicTable
, Context -> TVar Int
connectionWindow :: TVar WindowSize
, Context -> Rate
pingRate :: Rate
, Context -> Rate
settingsRate :: Rate
, Context -> Rate
emptyFrameRate :: Rate
}
newContext :: RoleInfo -> IO Context
newContext :: RoleInfo -> IO Context
newContext RoleInfo
rinfo =
Role
-> RoleInfo
-> IORef Settings
-> IORef Bool
-> StreamTable
-> IORef Int
-> IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context
Context Role
rl RoleInfo
rinfo
(IORef Settings
-> IORef Bool
-> StreamTable
-> IORef Int
-> IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
-> IO (IORef Settings)
-> IO
(IORef Bool
-> StreamTable
-> IORef Int
-> IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Settings -> IO (IORef Settings)
forall a. a -> IO (IORef a)
newIORef Settings
defaultSettings
IO
(IORef Bool
-> StreamTable
-> IORef Int
-> IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
-> IO (IORef Bool)
-> IO
(StreamTable
-> IORef Int
-> IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Bool -> IO (IORef Bool)
forall a. a -> IO (IORef a)
newIORef Bool
False
IO
(StreamTable
-> IORef Int
-> IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
-> IO StreamTable
-> IO
(IORef Int
-> IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO StreamTable
newStreamTable
IO
(IORef Int
-> IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
-> IO (IORef Int)
-> IO
(IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int -> IO (IORef Int)
forall a. a -> IO (IORef a)
newIORef Int
0
IO
(IORef (Maybe Int)
-> IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
-> IO (IORef (Maybe Int))
-> IO
(IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe Int -> IO (IORef (Maybe Int))
forall a. a -> IO (IORef a)
newIORef Maybe Int
forall a. Maybe a
Nothing
IO
(IORef Int
-> IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
-> IO (IORef Int)
-> IO
(IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int -> IO (IORef Int)
forall a. a -> IO (IORef a)
newIORef Int
sid0
IO
(IORef Int
-> TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
-> IO (IORef Int)
-> IO
(TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int -> IO (IORef Int)
forall a. a -> IO (IORef a)
newIORef Int
0
IO
(TQueue (Output Stream)
-> TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
-> IO (TQueue (Output Stream))
-> IO
(TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO (TQueue (Output Stream))
forall a. IO (TQueue a)
newTQueueIO
IO
(TQueue Control
-> DynamicTable
-> DynamicTable
-> TVar Int
-> Rate
-> Rate
-> Rate
-> Context)
-> IO (TQueue Control)
-> IO
(DynamicTable
-> DynamicTable -> TVar Int -> Rate -> Rate -> Rate -> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO (TQueue Control)
forall a. IO (TQueue a)
newTQueueIO
IO
(DynamicTable
-> DynamicTable -> TVar Int -> Rate -> Rate -> Rate -> Context)
-> IO DynamicTable
-> IO (DynamicTable -> TVar Int -> Rate -> Rate -> Rate -> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int -> IO DynamicTable
newDynamicTableForEncoding Int
defaultDynamicTableSize
IO (DynamicTable -> TVar Int -> Rate -> Rate -> Rate -> Context)
-> IO DynamicTable
-> IO (TVar Int -> Rate -> Rate -> Rate -> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int -> Int -> IO DynamicTable
newDynamicTableForDecoding Int
defaultDynamicTableSize Int
4096
IO (TVar Int -> Rate -> Rate -> Rate -> Context)
-> IO (TVar Int) -> IO (Rate -> Rate -> Rate -> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Int -> IO (TVar Int)
forall a. a -> IO (TVar a)
newTVarIO Int
defaultInitialWindowSize
IO (Rate -> Rate -> Rate -> Context)
-> IO Rate -> IO (Rate -> Rate -> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO Rate
newRate
IO (Rate -> Rate -> Context) -> IO Rate -> IO (Rate -> Context)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO Rate
newRate
IO (Rate -> Context) -> IO Rate -> IO Context
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO Rate
newRate
where
rl :: Role
rl = case RoleInfo
rinfo of
ClientInfo{} -> Role
Client
RoleInfo
_ -> Role
Server
sid0 :: Int
sid0 | Role
rl Role -> Role -> Bool
forall a. Eq a => a -> a -> Bool
== Role
Client = Int
1
| Bool
otherwise = Int
2
isClient :: Context -> Bool
isClient :: Context -> Bool
isClient Context
ctx = Context -> Role
role Context
ctx Role -> Role -> Bool
forall a. Eq a => a -> a -> Bool
== Role
Client
isServer :: Context -> Bool
isServer :: Context -> Bool
isServer Context
ctx = Context -> Role
role Context
ctx Role -> Role -> Bool
forall a. Eq a => a -> a -> Bool
== Role
Server
getMyNewStreamId :: Context -> IO StreamId
getMyNewStreamId :: Context -> IO Int
getMyNewStreamId Context
ctx = IORef Int -> (Int -> (Int, Int)) -> IO Int
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (Context -> IORef Int
myStreamId Context
ctx) Int -> (Int, Int)
forall a. Num a => a -> (a, a)
inc2
where
inc2 :: a -> (a, a)
inc2 a
n = let n' :: a
n' = a
n a -> a -> a
forall a. Num a => a -> a -> a
+ a
2 in (a
n', a
n)
getPeerStreamID :: Context -> IO StreamId
getPeerStreamID :: Context -> IO Int
getPeerStreamID Context
ctx = IORef Int -> IO Int
forall a. IORef a -> IO a
readIORef (IORef Int -> IO Int) -> IORef Int -> IO Int
forall a b. (a -> b) -> a -> b
$ Context -> IORef Int
peerStreamId Context
ctx
setPeerStreamID :: Context -> StreamId -> IO ()
setPeerStreamID :: Context -> Int -> IO ()
setPeerStreamID Context
ctx Int
sid = IORef Int -> Int -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (Context -> IORef Int
peerStreamId Context
ctx) Int
sid
{-# INLINE setStreamState #-}
setStreamState :: Context -> Stream -> StreamState -> IO ()
setStreamState :: Context -> Stream -> StreamState -> IO ()
setStreamState Context
_ Stream{IORef StreamState
streamState :: Stream -> IORef StreamState
streamState :: IORef StreamState
streamState} StreamState
val = IORef StreamState -> StreamState -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef StreamState
streamState StreamState
val
opened :: Context -> Stream -> IO ()
opened :: Context -> Stream -> IO ()
opened ctx :: Context
ctx@Context{IORef Int
concurrency :: IORef Int
concurrency :: Context -> IORef Int
concurrency} Stream
strm = do
IORef Int -> (Int -> (Int, ())) -> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef Int
concurrency (\Int
x -> (Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1,()))
Context -> Stream -> StreamState -> IO ()
setStreamState Context
ctx Stream
strm (OpenState -> StreamState
Open OpenState
JustOpened)
halfClosedRemote :: Context -> Stream -> IO ()
halfClosedRemote :: Context -> Stream -> IO ()
halfClosedRemote Context
ctx stream :: Stream
stream@Stream{IORef StreamState
streamState :: IORef StreamState
streamState :: Stream -> IORef StreamState
streamState} = do
Maybe ClosedCode
closingCode <- IORef StreamState
-> (StreamState -> (StreamState, Maybe ClosedCode))
-> IO (Maybe ClosedCode)
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef IORef StreamState
streamState StreamState -> (StreamState, Maybe ClosedCode)
closeHalf
(ClosedCode -> IO ()) -> Maybe ClosedCode -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ (Context -> Stream -> ClosedCode -> IO ()
closed Context
ctx Stream
stream) Maybe ClosedCode
closingCode
where
closeHalf :: StreamState -> (StreamState, Maybe ClosedCode)
closeHalf :: StreamState -> (StreamState, Maybe ClosedCode)
closeHalf x :: StreamState
x@(Closed ClosedCode
_) = (StreamState
x, Maybe ClosedCode
forall a. Maybe a
Nothing)
closeHalf (HalfClosedLocal ClosedCode
cc) = (ClosedCode -> StreamState
Closed ClosedCode
cc, ClosedCode -> Maybe ClosedCode
forall a. a -> Maybe a
Just ClosedCode
cc)
closeHalf StreamState
_ = (StreamState
HalfClosedRemote, Maybe ClosedCode
forall a. Maybe a
Nothing)
halfClosedLocal :: Context -> Stream -> ClosedCode -> IO ()
halfClosedLocal :: Context -> Stream -> ClosedCode -> IO ()
halfClosedLocal Context
ctx stream :: Stream
stream@Stream{IORef StreamState
streamState :: IORef StreamState
streamState :: Stream -> IORef StreamState
streamState} ClosedCode
cc = do
Bool
shouldFinalize <- IORef StreamState
-> (StreamState -> (StreamState, Bool)) -> IO Bool
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef IORef StreamState
streamState StreamState -> (StreamState, Bool)
closeHalf
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
shouldFinalize (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
Context -> Stream -> ClosedCode -> IO ()
closed Context
ctx Stream
stream ClosedCode
cc
where
closeHalf :: StreamState -> (StreamState, Bool)
closeHalf :: StreamState -> (StreamState, Bool)
closeHalf x :: StreamState
x@(Closed ClosedCode
_) = (StreamState
x, Bool
False)
closeHalf StreamState
HalfClosedRemote = (ClosedCode -> StreamState
Closed ClosedCode
cc, Bool
True)
closeHalf StreamState
_ = (ClosedCode -> StreamState
HalfClosedLocal ClosedCode
cc, Bool
False)
closed :: Context -> Stream -> ClosedCode -> IO ()
closed :: Context -> Stream -> ClosedCode -> IO ()
closed ctx :: Context
ctx@Context{IORef Int
concurrency :: IORef Int
concurrency :: Context -> IORef Int
concurrency,StreamTable
streamTable :: StreamTable
streamTable :: Context -> StreamTable
streamTable} strm :: Stream
strm@Stream{Int
streamNumber :: Stream -> Int
streamNumber :: Int
streamNumber} ClosedCode
cc = do
StreamTable -> Int -> IO ()
remove StreamTable
streamTable Int
streamNumber
IORef Int -> (Int -> (Int, ())) -> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef Int
concurrency (\Int
x -> (Int
xInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1,()))
Context -> Stream -> StreamState -> IO ()
setStreamState Context
ctx Stream
strm (ClosedCode -> StreamState
Closed ClosedCode
cc)
openStream :: Context -> StreamId -> FrameTypeId -> IO Stream
openStream :: Context -> Int -> FrameTypeId -> IO Stream
openStream ctx :: Context
ctx@Context{StreamTable
streamTable :: StreamTable
streamTable :: Context -> StreamTable
streamTable, IORef Settings
http2settings :: IORef Settings
http2settings :: Context -> IORef Settings
http2settings} Int
sid FrameTypeId
ftyp = do
Int
ws <- Settings -> Int
initialWindowSize (Settings -> Int) -> IO Settings -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef Settings -> IO Settings
forall a. IORef a -> IO a
readIORef IORef Settings
http2settings
Stream
newstrm <- Int -> Int -> IO Stream
newStream Int
sid (Int -> IO Stream) -> Int -> IO Stream
forall a b. (a -> b) -> a -> b
$ Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ws
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (FrameTypeId
ftyp FrameTypeId -> FrameTypeId -> Bool
forall a. Eq a => a -> a -> Bool
== FrameTypeId
FrameHeaders Bool -> Bool -> Bool
|| FrameTypeId
ftyp FrameTypeId -> FrameTypeId -> Bool
forall a. Eq a => a -> a -> Bool
== FrameTypeId
FramePushPromise) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Context -> Stream -> IO ()
opened Context
ctx Stream
newstrm
StreamTable -> Int -> Stream -> IO ()
insert StreamTable
streamTable Int
sid Stream
newstrm
Stream -> IO Stream
forall (m :: * -> *) a. Monad m => a -> m a
return Stream
newstrm