up
[cloogle-irc.git] / IRCBot.icl
1 implementation module IRCBot
2
3 from Data.Func import $
4 import Data.Either
5 import Data.Error
6 import Data.Maybe
7 import IRC
8 import TCPIP
9
10 from Text import class Text(join), instance Text String
11
12 import StdList
13 import StdBool
14
15 TIMEOUT :== Just 1000
16
17 bot :: (String, Int) [IRCMessage] [IRCMessage] a (IRCMessage a *World -> (Maybe [IRCMessage], a, *World)) *World -> (MaybeErrorString a, *World)
18 bot (host, port) start end state bot w
19 //Lookup hostname
20 # (ip, w) = lookupIPAddress host w
21 | isNothing ip = (Error $ "DNS lookup for " +++ host +++ " failed", w)
22 //Connect
23 # (rpt,chan,w) = connectTCP_MT TIMEOUT (fromJust ip, port) w
24 | rpt == TR_Expired = (Error $ "Connection to " +++ host +++ " timed out", w)
25 | rpt == TR_NoSuccess = (Error $ "Could not connect to " +++ host, w)
26 // Send startup commands
27 # (merr, chan, w) = send (map toString start) (fromJust chan) w
28 | isError merr = (Error $ fromError merr, w)
29 //Start processing function
30 # (mer, chan, state, w) = process chan state bot w
31 | isError mer = (Error $ fromError mer, w)
32 // Send shutdown commands
33 # (merr, {rChannel,sChannel}, w) = send (map toString end) chan w
34 | isError merr = (Error $ fromError merr, w)
35 //Close channels
36 = (Ok state, closeChannel sChannel (closeRChannel rChannel w))
37
38 import StdDebug,StdMisc
39 process :: TCP_DuplexChannel a (IRCMessage a *World -> (Maybe [IRCMessage], a, *World)) *World -> (MaybeErrorString (), TCP_DuplexChannel, a, *World)
40 process chan state bot w
41 //Receive
42 # (merr_resp, chan, w) = recv chan w
43 | isError merr_resp = (Error (fromError merr_resp), chan, state, w)
44 # (Ok mresp) = merr_resp
45 | isNothing mresp = process chan state bot w
46 | not (trace_tn $ "Received: " +++ fromJust mresp) = undef
47 //Process
48 = case parseIRCMessage (fromJust mresp) of
49 (Left err) = (Error $ "IRC Parsing error: " +++ join "\n" err, chan, state, w)
50 (Right msg)
51 # (mircc, state, w) = bot msg state w
52 | isNothing mircc = (Ok (), chan, state, w) // Bot asks to quit
53 //Possible send the commands
54 # (merr, chan, w) = send (map toString $ fromJust mircc) chan w
55 | isError merr = (Error $ fromError merr, chan, state, w)
56 //Recurse
57 = process chan state bot w
58
59 send :: [String] TCP_DuplexChannel *World -> (MaybeErrorString (), TCP_DuplexChannel, *World)
60 send [] chan w = (Ok (), chan, w)
61 send [msg:msgs] {sChannel,rChannel} w
62 # (_, w) = sleep 250000 w
63 # (rpt,i,sChannel,w) = send_MT TIMEOUT (toByteSeq msg) sChannel w
64 | rpt <> TR_Success = (Error "Could not send message", {sChannel=sChannel,rChannel=rChannel}, w)
65 = send msgs {sChannel=sChannel,rChannel=rChannel} w
66 where
67 sleep :: !Int !*World -> (!Int, *World)
68 sleep i w = code {
69 ccall usleep "I:I:A"
70 }
71
72 recv :: TCP_DuplexChannel *World -> (MaybeErrorString (Maybe String), TCP_DuplexChannel, *World)
73 recv {sChannel,rChannel} w
74 # (rpt, resp, rChannel, w) = receive_MT TIMEOUT rChannel w
75 | rpt == TR_Expired = (Ok Nothing, {sChannel=sChannel,rChannel=rChannel}, w)
76 | rpt == TR_NoSuccess || isNothing resp = (Error "Timeout recv fail", {sChannel=sChannel,rChannel=rChannel}, w)
77 = (Ok $ Just $ toString $ fromJust resp, {sChannel=sChannel,rChannel=rChannel}, w)