将 stdin 流式传输到 Wai.EventSource
Stream stdin to a Wai.EventSource
我想使用 text/event-stream
通过 HTTP 连接流式传输标准输入。 Network.Wai.EventSource 看起来是个不错的候选人。
我尝试使用此代码:
import Network.Wai
import Network.Wai.EventSource
import Network.Wai.Middleware.AddHeaders
import Network.Wai.Handler.Warp (run)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Lazy.Char8 as C
import Blaze.ByteString.Builder.ByteString
toEvent :: [L.ByteString] -> ServerEvent
toEvent s = ServerEvent {
eventName = Nothing,
eventId = Nothing,
eventData = map fromLazyByteString s
}
createWaiApp :: IO L.ByteString -> Application
createWaiApp input = eventSourceAppIO $ fmap (toEvent . C.lines) input
main :: IO ()
main = run 1337 $ createWaiApp L.getContents
哪个(我认为):
- 将标准输入读取为 Lazy ByteStream
- 将 ByteStream 拆分成行
- 为所有行生成一个 ServerEvent(感觉不对 - 应该有多个事件?)
- 从
IO ServerEvent
构建 WAI 应用程序
- 将应用程序绑定到端口 1337
当我运行这个(例如使用ping -c 5 example.com | stack exec test-exe
)时它不会响应,直到整个标准输入被读取。
我如何构建一个每次从标准输入读取 行 时刷新 HTTP 连接的 Wai 应用程序?
L.getContents
是一个单一的IO操作,所以只会创建一个事件。
下面是创建多个事件的 eventSourcEventAppIO 示例:
import Blaze.ByteString.Builder.Char8 (fromString)
...same imports as above...
nextEvent :: IO ServerEvent
nextEvent = do
s <- getLine
let event = if s == ""
then CloseEvent
else ServerEvent
{ eventName = Nothing
, eventId = Nothing
, eventData = [ fromString s ]
}
case event of
CloseEvent -> putStrLn "<close event>"
ServerEvent _ _ _ -> putStrLn "<server event>"
return event
main :: IO ()
main = run 1337 $ eventSourceAppIO nextEvent
要进行测试,在一个 window 中启动服务器,在另一个 运行 中使用命令 curl -v http://localhost:1337
。对于您在服务器 window 中输入的每一行,您将从 curl 获得一个数据框。输入空行将关闭 HTTP 连接,但服务器将保持 运行ning 允许您再次连接。
我想使用 text/event-stream
通过 HTTP 连接流式传输标准输入。 Network.Wai.EventSource 看起来是个不错的候选人。
我尝试使用此代码:
import Network.Wai
import Network.Wai.EventSource
import Network.Wai.Middleware.AddHeaders
import Network.Wai.Handler.Warp (run)
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Lazy.Char8 as C
import Blaze.ByteString.Builder.ByteString
toEvent :: [L.ByteString] -> ServerEvent
toEvent s = ServerEvent {
eventName = Nothing,
eventId = Nothing,
eventData = map fromLazyByteString s
}
createWaiApp :: IO L.ByteString -> Application
createWaiApp input = eventSourceAppIO $ fmap (toEvent . C.lines) input
main :: IO ()
main = run 1337 $ createWaiApp L.getContents
哪个(我认为):
- 将标准输入读取为 Lazy ByteStream
- 将 ByteStream 拆分成行
- 为所有行生成一个 ServerEvent(感觉不对 - 应该有多个事件?)
- 从
IO ServerEvent
构建 WAI 应用程序
- 将应用程序绑定到端口 1337
当我运行这个(例如使用ping -c 5 example.com | stack exec test-exe
)时它不会响应,直到整个标准输入被读取。
我如何构建一个每次从标准输入读取 行 时刷新 HTTP 连接的 Wai 应用程序?
L.getContents
是一个单一的IO操作,所以只会创建一个事件。
下面是创建多个事件的 eventSourcEventAppIO 示例:
import Blaze.ByteString.Builder.Char8 (fromString)
...same imports as above...
nextEvent :: IO ServerEvent
nextEvent = do
s <- getLine
let event = if s == ""
then CloseEvent
else ServerEvent
{ eventName = Nothing
, eventId = Nothing
, eventData = [ fromString s ]
}
case event of
CloseEvent -> putStrLn "<close event>"
ServerEvent _ _ _ -> putStrLn "<server event>"
return event
main :: IO ()
main = run 1337 $ eventSourceAppIO nextEvent
要进行测试,在一个 window 中启动服务器,在另一个 运行 中使用命令 curl -v http://localhost:1337
。对于您在服务器 window 中输入的每一行,您将从 curl 获得一个数据框。输入空行将关闭 HTTP 连接,但服务器将保持 运行ning 允许您再次连接。