Tôi đang triển khai bot IRC và vì tôi đang kết nối qua SSL bằng cách sử dụng OpenSSL.Session, tôi sử dụng hàm lazyRead
để đọc dữ liệu từ ổ cắm. Trong giai đoạn đầu của kết nối, tôi cần phải thực hiện một số điều theo thứ tự: đàm phán nick, nhận dạng nickserv, tham gia các kênh v.v.) để có một số trạng thái liên quan. Ngay bây giờ, tôi đã đưa ra những điều sau đây:Cách thức lý tưởng để xử lý kênh đầu vào lười trong Haskell
data ConnectionState = Initial | NickIdentification | Connected
listen :: SSL.SSL -> IO()
listen ssl = do
lines <- BL.lines `fmap` SSL.lazyRead ssl
evalStateT (mapM_ (processLine ssl) lines) Initial
processLine :: SSL.SSL -> BL.ByteString -> StateT ConnectionState IO()
processLine ssl line = do case message of
Just a -> processMessage ssl a
Nothing -> return()
where message = IRC.decode $ BL.toStrict line
processMessage :: SSL.SSL -> IRC.Message -> StateT ConnectionState IO()
processMessage ssl m = do
state <- S.get
case state of
Initial -> when (IRC.msg_command m == "376") $ do
liftIO $ putStrLn "connected!"
liftIO $ privmsg ssl "NickServ" ("identify " ++ nick_password)
S.put NickIdentification
NickIdentification -> do
when (identified m) $ do
liftIO $ putStrLn "identified!"
liftIO $ joinChannel ssl chan
S.put Connected
Connected -> return()
liftIO $ print m
when (IRC.msg_command m == "PING") $ (liftIO . pong . mconcat . map show) (IRC.msg_params m)
Vì vậy, khi tôi đến trạng thái "Đã kết nối", tôi vẫn sẽ kết thúc câu lệnh khi khởi tạo kết nối. Vấn đề khác là thêm StateT lồng nhau sẽ rất đau đớn.
Cách khác là thay thế mapM
bằng thứ gì đó tùy chỉnh để chỉ xử lý các đường cho đến khi chúng tôi kết nối và sau đó bắt đầu một vòng lặp khác trong phần còn lại. Điều này sẽ yêu cầu theo dõi những gì còn lại trong danh sách hoặc gọi lại SSL.lazyRead
(không quá tệ).
Một giải pháp khác là giữ cho các dòng còn lại liệt kê trong tiểu bang và vẽ các đường khi cần thiết tương tự như getLine
.
Điều tốt hơn nên làm trong trường hợp này là gì? Liệu sự lười biếng của Haskell có làm cho nó để chúng ta đi trực tiếp đến trường hợp Connected
sau khi trạng thái dừng cập nhật hay là case
luôn nghiêm ngặt?
Một giải pháp thay thế khác là sử dụng [ống dẫn] (https://www.fpcomplete.com/school/to-infinity-and-beyond/pick-of-the-week/conduit-overview). –