Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
import System.IO hiding (hPutStr, putStrLn, hGetLine)
import System.IO.UTF8 hiding (putStrLn)
import qualified System.IO.Error as E
import Data.List
import Control.Concurrent
import Control.Monad.Reader
import Network
import System.Exit
import System.Console.Haskeline
import Data.Maybe
import System.Random
data Bot = Bot {
server :: String,
port :: Int,
channel :: String,
nick :: String,
username :: String,
realname :: String
}
data BotContext = BotContext {
botInfo :: Bot,
netHandle :: Handle
}
runBot :: Bot -> IO()
runBot bot = do
h <- connectTo (server bot) (PortNumber (fromIntegral (port bot)))
hSetBuffering h NoBuffering
let botContext = BotContext bot h
forkIO $ runReaderT (loop isLiving) botContext
E.try $ flip runReaderT botContext $ do
loginBot
lift $ forkIO $ runReaderT (loop cmd) botContext
loop event
return ()
where loop x = x >> loop x
{- active ping to keep live, if the Handle is broken,
- the programm will fail to run, and exit automatic -}
isLiving :: ReaderT BotContext IO ()
isLiving = do
lift $ threadDelay 180000000 -- 180.000.000 µs = 3 Min
msg $ "PING :test"
loginBot :: ReaderT BotContext IO ()
loginBot = do
bot <- ask >>= return.botInfo
msg $ "NICK " ++ (nick bot)
msg $ "USER " ++ (username bot) ++ " 0 * :" ++ (realname bot)
msg $ "JOIN " ++ (channel bot)
msg :: String -> ReaderT BotContext IO ()
msg x = do
h <- ask >>= return.netHandle
lift $ hPutStr h $ x ++ "\r\n"
lift $ putStrLn $ ">>" ++ x
privmsg :: String -> ReaderT BotContext IO ()
privmsg x = do
bot <- ask >>= return.botInfo
msg $ "PRIVMSG " ++ (channel bot) ++ " :" ++ x
ircGetLine :: ReaderT BotContext IO String
ircGetLine = ask >>= return.netHandle >>= lift . hGetLine
cmd :: ReaderT BotContext IO ()
cmd = do
-- mbl <- fmap Just $ lift getLine {- for Debug -}
mbl <- lift $ readline "%"
case mbl of
Nothing -> return ()
Just l -> token l
where
token l | "/quit" `isPrefixOf` l
= do
msg $ "QUIT :" ++ (drop 6 l) ++ "\r\n"
h <- ask >>= return.netHandle
lift $ hClose h
lift $ exitSuccess
| "/join" `isPrefixOf` l = msg $ "JOIN " ++ (drop 6 l) ++ "\r\n"
{- with ' ' in tail, prevent it
to be a prefix of other commands -}
| "/a " `isPrefixOf` l = privmsg $ '\001':(drop 4 l)
++ "\001\r\n"
| "/id " `isPrefixOf` l = msg $ (drop 5 l) ++ "\r\n"
| spaceStr l = return ()
| (not $ null l) && head l == '/' = return ()
| otherwise = privmsg $ l ++ "\r\n"
spaceStr = null . dropWhile isSpace'
{- due to some UTF8 Error @ Data.Char.isSpace -}
isSpace' :: Char -> Bool
isSpace' ' ' = True
isSpace' '\t' = True
isSpace' '\r' = True
isSpace' '\n' = True
isSpace' _ = False
event :: ReaderT BotContext IO ()
event = do
t <- ircGetLine
lift $ putStrLn t
if "PING :" `isPrefixOf` t
then msg $ "PONG :" ++ drop 6 t
else when ("PRIVMSG" `isInfixOf` t) $ do
let t' = safeTail $ dropWhile (/= ':') $ safeTail t
w = replyName t
r <- privateAnswer w t'
d <- lift $ dice 100 {- 1D100 -}
when (isNothing r && d <= 10 ) $ react w t' >> return ()
where
safeTail [] = []
safeTail (_:xs) = xs
{- do not want to wrapp StateT any more -}
{- dice :: Int -> IO (Int) -- 1Dx -}
dice ma = getStdRandom (randomR (1,ma)) :: IO (Int)
replyName t = takeWhile (/= '!') $ safeTail t
reply w x = do
privmsg $ w ++ (':' : ' ' : x)
return $ Just x
-- replyD w x = do {- reply with Delay :: ReaderT IO()-}
-- sec <- lift $ getStdRandom (randomR (5,10))
-- lift $ threadDelay $ sec*1000000
-- privmsg $ w ++ (':' : ' ' : x)
-- return $ Just x
privateAnswer w t = do
i <- ask >>= return.nick.botInfo
if (i `isInfixOf` t)
then reactPriv i w t
>>= \r ->
if isNothing r
then return Nothing -- reply w ":D"
else return r
else return Nothing
{- reactPriv :: My_Nick -> Who -> Text -> Maybe String -}
reactPriv i w t
| "你是谁" `isInfixOf` t = reply w $ "我是" ++ i
| "机器人" `isInfixOf` t ||
("bot" `isInfixOf` t && not ("bot" `isInfixOf` i))
= reply w "嘘!小样你知道的太多了"
| otherwise = react w t
react w t
| "" `isInfixOf` t = reply w ""
| "有没有" `isInfixOf` t = reply w "没有"
| "是不是" `isInfixOf` t = reply w "不是"
| "要不要" `isInfixOf` t = reply w "不要"
| "能不能" `isInfixOf` t = reply w "不能"
| "如何" `isInfixOf` t = reply w "不知道"
| "为什么" `isInfixOf` t = reply w "不为什么"
| "为何" `isInfixOf` t = reply w "不为何"
| "大家好" `isInfixOf` t = reply w "你好"
| "你好" `isInfixOf` t = reply w "你好"
| "" `isInfixOf` t = reply w ""
| "在吗" `isInfixOf` t = reply w "不在"
| "为啥" `isInfixOf` t = reply w "不为啥"
| isQuestion t = answer w t
| otherwise = return Nothing
isQuestion t = "?" `isInfixOf` t
|| "" `isInfixOf` t
|| "" `isInfixOf` t
{- antwortet nur wenn es sicher eine Frage ist -}
answer w t
| "conky" `isInfixOf` t = reply w "不用conky"
| "fvwm" `isInfixOf` t = reply w "不用fvwm"
| "emacs" `isInfixOf` t = reply w "不用emacs"
| "grub2" `isInfixOf` t = reply w "不用grub2"
| "python" `isInfixOf` t = reply w "不用python"
| "有人" `isInfixOf` t = privmsg "<----" >>
return (Just "<----")
| "知道" `isInfixOf` t = reply w "不知道"
| "需要" `isInfixOf` t = reply w "不需要"
| "明白" `isInfixOf` t = reply w "不明白"
| "听说" `isInfixOf` t = reply w "没听说"
| "了解" `isInfixOf` t = reply w "不了解"
| "熟悉" `isInfixOf` t = reply w "不熟悉"
| "会用" `isInfixOf` t = reply w "不会"
| "可以" `isInfixOf` t = reply w "可以"
| "什么" `isInfixOf` t = reply w "不知道"
| "怎么" `isInfixOf` t = reply w "不知道"
| "怎样" `isInfixOf` t = reply w "不知道"
| "" `isInfixOf` t = reply w "不懂"
| "" `isInfixOf` t = reply w "不能"
| "" `isInfixOf` t = reply w "不会"
| "" `isInfixOf` t = reply w "不是"
| "" `isInfixOf` t = reply w "没有"
| "" `isInfixOf` t = reply w "不要"
| otherwise = return Nothing
main = runBot $ Bot {
server = "irc.freenode.org",
port = 6667,
channel = "#ubuntu-cn",
nick = "snugglebat",
username = "purple",
realname = "purple"
}
readline :: String -> IO (Maybe String)
readline = runInputT defaultSettings . getInputLine
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment