2016-05-07 18 views
0

Я хотел бы передать stdin через HTTP-соединение, используя text/event-stream. Вещь Network.Wai.EventSource выглядит как хороший кандидат.Поток stdin к 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 

Which (я думаю) делает:

  • читает стандартный ввод как Ленивые потокового
  • расщепляет потоковый в линию
  • производящей один ServerEvent для всех строк (это кажется неправильным - должно быть, должно быть, несколько событий?)
  • Builds Заявка на WAI из IO ServerEvent
  • Персонального приложение к порту 1337

При запуске этого (например, используя ping -c 5 example.com | stack exec test-exe), он не отвечает, пока не будет прочитан весь stdin.

Как создать приложение Wai, которое очищает HTTP-соединение каждый раз, когда он читает строку от stdin?

ответ

1

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 

Чтобы проверить, в одном окне запуска сервера, а в другом запустить команду curl -v http://localhost:1337. Для каждой строки, которую вы вводите в окне сервера, вы получите кадр данных из curl. Ввод пустой строки закроет HTTP-соединение, но сервер останется включенным, что позволит вам снова подключиться к нему.