Search code examples
haskellbotsirc

Haskell IRC Bot Stalling Out


I know Haskell fairly well, and I'm writing an IRC interface for my bot. I have the following problem:

After running the code..

module Main (main) where

import Network
import Data.List
import System.IO

server = "irc.freenode.org"
port   = 6667
chan   = "#tanuki"
nick   = "DuckBot01"

main :: IO ()
main = do
    bot <- connect 
    run bot

connect :: IO Handle
connect = notify $ do
    h <- connectTo server (PortNumber (fromIntegral port))
    hSetBuffering h NoBuffering
    return $ Bot { socket = h }
  where
    notify a = do
        putStrLn ("Connecting to " ++ server ++ " ... ") >> hFlush stdout
        putStrLn "done."
        a

run :: Handle -> IO () 
run h = do
    write h "NICK" nick
    write h "USER" (nick++" 0 * :tutorial bot")
    write h "JOIN" chan
    listen h 
--
-- Process each line from the server
--
listen :: Handle -> IO ()
listen h = forever $ do
    s <- init `fmap` hGetLine h
    putStrLn s
    if ping s then pong s else eval h (clean s)
  where
    forever a = a >> forever a
    clean     = drop 1 . dropWhile (/= ':') . drop 1
    ping x    = "PING :" `isPrefixOf` x
    pong x    = write h "PONG" (':' : drop 6 x)

eval :: Handle -> String -> IO ()
eval     h "!quit"               = write h "QUIT" ":byebye" 
eval     _ _                     = return () -- ignore everything else

privmsg :: Handle -> String -> IO ()
privmsg h s = write h "PRIVMSG" (chan ++ " :" ++ s)

write :: Handle -> String -> String -> IO ()
write handle s t = do
    hPrint handle $ s ++ " " ++ t ++ "\r\n"
    putStrLn $ "> " ++ s ++ " " ++ t ++ "\n"

I get the following output in the terminal:

Loading package bytestring-0.9.2.1 ... linking ... done.
Loading package transformers-0.2.2.0 ... linking ... done.
Loading package mtl-2.0.1.0 ... linking ... done.
Loading package array-0.4.0.0 ... linking ... done.
Loading package deepseq-1.3.0.0 ... linking ... done.
Loading package text-0.11.1.13 ... linking ... done.
Loading package parsec-3.1.2 ... linking ... done.
Loading package unix-2.5.1.0 ... linking ... done.
Loading package network-2.3.0.10 ... linking ... done.
Connecting to irc.freenode.org ... 
done.
> NICK DuckBot01

> USER DuckBot01 0 * :tutorial bot

> JOIN #tanuki

:cameron.freenode.net NOTICE * :*** Looking up your hostname...
:cameron.freenode.net NOTICE * :*** Checking Ident
:cameron.freenode.net NOTICE * :*** Found your hostname
:cameron.freenode.net NOTICE * :*** No Ident response
ERROR :Closing Link: 127.0.0.1 (Connection timed out)
*** Exception: <socket: 8>: hGetLine: end of file

Why does it time out? It's not my connection, my normal IRC client works fine. Help is appreciated.


Solution

  • Use hPutStr instead of hPrint so that way your \r\n is rendered and sent to the server correctly. hPrint will give you the same output as show, which is not what you want. I recently made a bot following the Roll Your Own IRC Bot page, too, and I stuck with using hPrintf.

    hPutStrLn automatically appends \n to your string, so you don't need to put that in your write if that's not what you want.

    Also, you should change this bit.

    return $ Bot { socket = h }
    

    Your function is supposed to return a Handle but you're returning a Bot which you haven't defined. Just change it to return h and you should be okay there. (Since you've got it to compile, I'm assuming you fixed that.)