]> gitweb @ CieloNegro.org - Lucu.git/blob - Network/HTTP/Lucu/Interaction.hs
staticDir
[Lucu.git] / Network / HTTP / Lucu / Interaction.hs
1 module Network.HTTP.Lucu.Interaction
2     ( Interaction(..)
3     , InteractionState(..)
4     , InteractionQueue
5     , newInteractionQueue -- IO InteractionQueue
6     , newInteraction      -- Config -> HostName -> Maybe Request -> IO Interaction
7
8     , writeItr   -- Interaction -> (Interaction -> TVar a) -> a -> STM ()
9     , readItr    -- Interaction -> (Interaction -> TVar a) -> (a -> b) -> STM b
10     , readItrF   -- (Functor f) => Interaction -> (Interaction -> TVar (f a)) -> (a -> b) -> STM (f b)
11     , updateItr  -- Interaction -> (Interaction -> TVar a) -> (a -> a) -> STM ()
12     , updateItrF -- (Functor f) => Interaction -> (Interaction -> TVar (f a)) -> (a -> a) -> STM ()
13     )
14     where
15
16 import           Control.Concurrent.STM
17 import qualified Data.ByteString.Lazy.Char8 as B
18 import           Data.ByteString.Lazy.Char8 (ByteString)
19 import qualified Data.Sequence as S
20 import           Data.Sequence (Seq)
21 import           Network
22 import           Network.HTTP.Lucu.Config
23 import           Network.HTTP.Lucu.Request
24 import           Network.HTTP.Lucu.Response
25
26 data Interaction = Interaction {
27       itrConfig       :: Config
28     , itrRemoteHost   :: HostName
29     , itrResourcePath :: Maybe [String]
30     , itrRequest      :: Maybe Request
31     , itrResponse     :: TVar (Maybe Response)
32
33     -- FIXME: この三つは本來 TVar であるべきでないので、唯の Bool にす
34     -- るに越した事は無いが、それは重要でない。そんな golf で自分の貴重
35     -- な時間を /dev/null に突っ込むのは、他にしたい事が何も無くなって
36     -- からにすべき。
37     , itrRequestHasBody    :: TVar Bool
38     , itrRequestIsChunked  :: TVar Bool
39     , itrExpectedContinue  :: TVar Bool
40
41     , itrReqChunkLength    :: TVar (Maybe Int)
42     , itrReqChunkRemaining :: TVar (Maybe Int)
43     , itrReqChunkIsOver    :: TVar Bool
44     , itrReqBodyWanted     :: TVar (Maybe Int)
45     , itrReqBodyWasteAll   :: TVar Bool
46     , itrReceivedBody      :: TVar ByteString -- Resource が受領した部分は削除される
47
48     , itrWillReceiveBody   :: TVar Bool
49     , itrWillChunkBody     :: TVar Bool
50     , itrWillDiscardBody   :: TVar Bool
51     , itrWillClose         :: TVar Bool
52
53     , itrBodyToSend :: TVar ByteString
54     , itrBodyIsNull :: TVar Bool
55
56     , itrState :: TVar InteractionState
57
58     , itrWroteContinue :: TVar Bool
59     , itrWroteHeader   :: TVar Bool
60     }
61
62 -- Resource の視點で見た時の状態。常に上から下へ行き、逆行しない。初期
63 -- 状態は ExaminingRequest。
64 data InteractionState = ExaminingRequest
65                       | GettingBody
66                       | DecidingHeader
67                       | DecidingBody
68                       | Done
69                         deriving (Show, Eq, Ord, Enum)
70
71 type InteractionQueue = TVar (Seq Interaction)
72
73
74 newInteractionQueue :: IO InteractionQueue
75 newInteractionQueue = newTVarIO S.empty
76
77
78 newInteraction :: Config -> HostName -> Maybe Request -> IO Interaction
79 newInteraction conf host req
80     = do responce <- newTVarIO Nothing
81
82          requestHasBody     <- newTVarIO False
83          requestIsChunked   <- newTVarIO False
84          expectedContinue   <- newTVarIO False
85          
86          reqChunkLength     <- newTVarIO Nothing -- 現在のチャンク長
87          reqChunkRemaining  <- newTVarIO Nothing -- 現在のチャンクの殘り
88          reqChunkIsOver     <- newTVarIO False   -- 最後のチャンクを讀み終へた
89          reqBodyWanted      <- newTVarIO Nothing -- Resource が要求してゐるチャンク長
90          reqBodyWasteAll    <- newTVarIO False   -- 殘りの body を讀み捨てよと云ふ要求
91          receivedBody       <- newTVarIO B.empty
92
93          willReceiveBody   <- newTVarIO False
94          willChunkBody     <- newTVarIO False
95          willDiscardBody   <- newTVarIO False
96          willClose         <- newTVarIO False
97
98          bodyToSend <- newTVarIO B.empty
99          bodyIsNull <- newTVarIO True -- 一度でも bodyToSend が空でなくなったら False
100
101          state <- newTVarIO ExaminingRequest
102
103          wroteContinue <- newTVarIO False
104          wroteHeader   <- newTVarIO False
105
106          return $ Interaction {
107                       itrConfig       = conf
108                     , itrRemoteHost   = host
109                     , itrResourcePath = Nothing
110                     , itrRequest      = req
111                     , itrResponse     = responce
112
113                     , itrRequestHasBody    = requestHasBody
114                     , itrRequestIsChunked  = requestIsChunked
115                     , itrExpectedContinue = expectedContinue
116
117                     , itrReqChunkLength    = reqChunkLength
118                     , itrReqChunkRemaining = reqChunkRemaining
119                     , itrReqChunkIsOver    = reqChunkIsOver
120                     , itrReqBodyWanted     = reqBodyWanted
121                     , itrReqBodyWasteAll   = reqBodyWasteAll
122                     , itrReceivedBody      = receivedBody
123
124                     , itrWillReceiveBody   = willReceiveBody
125                     , itrWillChunkBody     = willChunkBody
126                     , itrWillDiscardBody   = willDiscardBody
127                     , itrWillClose         = willClose
128
129                     , itrBodyToSend = bodyToSend
130                     , itrBodyIsNull = bodyIsNull
131                     
132                     , itrState = state
133                     
134                     , itrWroteContinue = wroteContinue
135                     , itrWroteHeader   = wroteHeader
136                     }
137
138
139 writeItr :: Interaction -> (Interaction -> TVar a) -> a -> STM ()
140 writeItr itr accessor value
141     = writeTVar (accessor itr) value
142
143
144 readItr :: Interaction -> (Interaction -> TVar a) -> (a -> b) -> STM b
145 readItr itr accessor reader
146     = readTVar (accessor itr) >>= return . reader
147
148
149 readItrF :: (Functor f) => Interaction -> (Interaction -> TVar (f a)) -> (a -> b) -> STM (f b)
150 readItrF itr accessor reader
151     = readItr itr accessor (fmap reader)
152
153
154 updateItr :: Interaction -> (Interaction -> TVar a) -> (a -> a) -> STM ()
155 updateItr itr accessor updator
156     = do old <- readItr itr accessor id
157          writeItr itr accessor (updator old)
158
159
160 updateItrF :: (Functor f) => Interaction -> (Interaction -> TVar (f a)) -> (a -> a) -> STM ()
161 updateItrF itr accessor updator
162     = updateItr itr accessor (fmap updator)