|
@@ -13,7 +13,7 @@ import qualified System.Log.Logger as HSL
|
13
|
13
|
import ClassyPrelude
|
14
|
14
|
import Control.Concurrent.Lifted (threadDelay)
|
15
|
15
|
import Control.Exception.Lifted (evaluate)
|
16
|
|
-import Control.Monad.State.Strict (get, put, evalStateT)
|
|
16
|
+import Control.Monad.State.Strict (get, put)
|
17
|
17
|
import Data.Time (addUTCTime)
|
18
|
18
|
import System.IO (hIsEOF)
|
19
|
19
|
import System.Timeout (timeout)
|
|
@@ -56,18 +56,17 @@ parseLine botConfig@BotConfig { .. } time line msgParts =
|
56
|
56
|
sendCommandLoop :: MessageChannel Message -> Bot -> IO ()
|
57
|
57
|
sendCommandLoop commandChan bot@Bot { .. } = do
|
58
|
58
|
msg@(Message _ _ cmd) <- receiveMessage commandChan
|
59
|
|
- (exs, lines_) <- formatCommand botConfig msg
|
|
59
|
+ (exs, lines_) <- formatCommand botConfig msg
|
60
|
60
|
|
61
|
61
|
forM_ exs $ \(ex :: SomeException) ->
|
62
|
62
|
errorM ("Error while formatting command: " ++ show cmd ++ "\nError: " ++ show ex)
|
63
|
63
|
|
64
|
|
- unless (null lines_) $
|
|
64
|
+ forM_ lines_ $ \line -> do
|
65
|
65
|
handle (\(e :: SomeException) -> do
|
66
|
66
|
errorM ("Error while writing to connection: " ++ show e)
|
67
|
|
- closeMessageChannel commandChan) $
|
68
|
|
- forM_ lines_ $ \line -> do
|
69
|
|
- TF.hprint botSocket "{}\r\n" $ TF.Only line
|
70
|
|
- infoM . unpack $ "> " ++ line
|
|
67
|
+ closeMessageChannel commandChan) $ do
|
|
68
|
+ TF.hprint botSocket "{}\r\n" $ TF.Only line
|
|
69
|
+ infoM . unpack $ "> " ++ line
|
71
|
70
|
|
72
|
71
|
commandChanClosed <- isClosedMessageChannel commandChan
|
73
|
72
|
unless commandChanClosed $
|
|
@@ -76,12 +75,11 @@ sendCommandLoop commandChan bot@Bot { .. } = do
|
76
|
75
|
_ -> sendCommandLoop commandChan bot
|
77
|
76
|
|
78
|
77
|
readMessageLoop :: MVar BotStatus -> MessageChannel In -> Bot -> Int -> IO ()
|
79
|
|
-readMessageLoop mvBotStatus inChan Bot { .. } timeoutDelay = evalStateT loop mempty
|
|
78
|
+readMessageLoop mvBotStatus inChan Bot { .. } timeoutDelay = loop mempty
|
80
|
79
|
where
|
81
|
80
|
msgPartTimeout = 10
|
82
|
81
|
|
83
|
|
- loop = do
|
84
|
|
- msgParts <- get
|
|
82
|
+ loop msgParts = do
|
85
|
83
|
botStatus <- readMVar mvBotStatus
|
86
|
84
|
case botStatus of
|
87
|
85
|
Disconnected -> io $ closeMessageChannel inChan
|
|
@@ -104,25 +102,26 @@ readMessageLoop mvBotStatus inChan Bot { .. } timeoutDelay = evalStateT loop mem
|
104
|
102
|
Right (Just EOS) -> sendMessage inChan EOD >> return msgParts
|
105
|
103
|
|
106
|
104
|
limit <- io $ map (addUTCTime (- msgPartTimeout)) getCurrentTime
|
107
|
|
- put $ validMsgParts limit msgParts'
|
108
|
|
- loop
|
109
|
|
- where
|
110
|
|
- validMsgParts limit =
|
111
|
|
- foldl' (\m (k, v) -> insertWith (++) k [v] m) mempty
|
112
|
|
- . concat
|
113
|
|
- . filter ((> limit) . msgPartTime . snd . headEx . sortBy (flip $ comparing (msgPartTime . snd)))
|
114
|
|
- . groupAllOn (fst &&& msgPartTarget . snd)
|
115
|
|
- . asList . concatMap (uncurry (map . (,))) . mapToList
|
116
|
|
-
|
117
|
|
- readLine = do
|
118
|
|
- eof <- hIsEOF botSocket
|
119
|
|
- if eof
|
120
|
|
- then return EOS
|
121
|
|
- else mask $ \unmask -> do
|
122
|
|
- line <- map initEx . unmask $ hGetLine botSocket
|
123
|
|
- infoM . unpack $ "< " ++ line
|
124
|
|
- now <- getCurrentTime
|
125
|
|
- return $ Line now line
|
|
105
|
+ loop $ validMsgParts limit msgParts'
|
|
106
|
+
|
|
107
|
+ validMsgParts limit =
|
|
108
|
+ foldl' (\m (k, v) -> insertWith (++) k [v] m) mempty
|
|
109
|
+ . concat
|
|
110
|
+ . filter ((> limit) . msgPartTime . snd . headEx . sortBy (flip $ comparing (msgPartTime . snd)))
|
|
111
|
+ . groupAllOn (fst &&& msgPartTarget . snd)
|
|
112
|
+ . asList
|
|
113
|
+ . concatMap (uncurry (map . (,)))
|
|
114
|
+ . mapToList
|
|
115
|
+
|
|
116
|
+ readLine = do
|
|
117
|
+ eof <- hIsEOF botSocket
|
|
118
|
+ if eof
|
|
119
|
+ then return EOS
|
|
120
|
+ else mask $ \unmask -> do
|
|
121
|
+ line <- map initEx . unmask $ hGetLine botSocket
|
|
122
|
+ infoM . unpack $ "< " ++ line
|
|
123
|
+ now <- getCurrentTime
|
|
124
|
+ return $ Line now line
|
126
|
125
|
|
127
|
126
|
messageProcessLoop :: MessageChannel In -> MessageChannel Message -> IRC ()
|
128
|
127
|
messageProcessLoop inChan messageChan = loop 0
|
|
@@ -139,14 +138,13 @@ messageProcessLoop inChan messageChan = loop 0
|
139
|
138
|
then infoM "Timeout" >> return Disconnected
|
140
|
139
|
else do
|
141
|
140
|
when (status == Kicked) $
|
142
|
|
- threadDelay (5 * oneSec) >> newMessage JoinCmd >>= sendMessage messageChan
|
|
141
|
+ threadDelay (5 * oneSec) >> (sendMessage messageChan =<< newMessage JoinCmd)
|
143
|
142
|
|
144
|
143
|
mIn <- receiveMessage inChan
|
145
|
144
|
case mIn of
|
146
|
145
|
Timeout -> do
|
147
|
|
- idleMsg <- newMessage IdleMsg
|
148
|
|
- sendMessage messageChan idleMsg
|
149
|
|
- sendWhoisMessage nick origNick
|
|
146
|
+ sendMessage messageChan =<< newMessage IdleMsg
|
|
147
|
+ sendWhoisMessage nick origNick idleFor
|
150
|
148
|
return Idle
|
151
|
149
|
EOD -> infoM "Connection closed" >> return Disconnected
|
152
|
150
|
Msg (msg@Message { .. }) -> do
|
|
@@ -162,25 +160,24 @@ messageProcessLoop inChan messageChan = loop 0
|
162
|
160
|
NickAvailable -> return ()
|
163
|
161
|
_ -> loop 0
|
164
|
162
|
|
165
|
|
- where
|
166
|
|
- sendWhoisMessage nick origNick =
|
167
|
|
- when (nick /= origNick && idleFor /= 0 && idleFor `mod` (10 * oneSec) == 0) $
|
168
|
|
- (newMessage . WhoisCmd . nickToText $ origNick) >>= sendMessage messageChan
|
169
|
|
-
|
170
|
|
- handleMsg nick origNick message mpass
|
171
|
|
- | Just (JoinMsg user) <- fromMessage message, userNick user == nick =
|
172
|
|
- infoM "Joined" >> return Joined
|
173
|
|
- | Just (KickMsg { .. }) <- fromMessage message, kickedNick == nick =
|
174
|
|
- infoM "Kicked" >> return Kicked
|
175
|
|
- | Just NickInUseMsg <- fromMessage message =
|
176
|
|
- infoM "Nick already in use" >> return NickNotAvailable
|
177
|
|
- | Just (ModeMsg { .. }) <- fromMessage message, modeUser == Self = do
|
178
|
|
- whenJust mpass $ \pass -> do
|
179
|
|
- msg <- newMessage $ PrivMsgReply (User (Nick "NickServ") "") $ "IDENTIFY " ++ pass
|
180
|
|
- sendMessage messageChan msg
|
181
|
|
- newMessage JoinCmd >>= sendMessage messageChan
|
182
|
|
- return Connected
|
183
|
|
- | Just (WhoisNoSuchNick n) <- fromMessage message, n == origNick =
|
184
|
|
- infoM "Original nick available" >> return NickAvailable
|
185
|
|
- | otherwise =
|
186
|
|
- return Connected
|
|
163
|
+ sendWhoisMessage nick origNick idleFor =
|
|
164
|
+ when (nick /= origNick && idleFor /= 0 && idleFor `mod` (10 * oneSec) == 0) $
|
|
165
|
+ sendMessage messageChan =<< (newMessage . WhoisCmd . nickToText $ origNick)
|
|
166
|
+
|
|
167
|
+ handleMsg nick origNick message mpass
|
|
168
|
+ | Just (JoinMsg user) <- fromMessage message, userNick user == nick =
|
|
169
|
+ infoM "Joined" >> return Joined
|
|
170
|
+ | Just (KickMsg { .. }) <- fromMessage message, kickedNick == nick =
|
|
171
|
+ infoM "Kicked" >> return Kicked
|
|
172
|
+ | Just NickInUseMsg <- fromMessage message =
|
|
173
|
+ infoM "Nick already in use" >> return NickNotAvailable
|
|
174
|
+ | Just (ModeMsg { .. }) <- fromMessage message, modeUser == Self = do
|
|
175
|
+ whenJust mpass $ \pass -> do
|
|
176
|
+ msg <- newMessage $ PrivMsgReply (User (Nick "NickServ") "") $ "IDENTIFY " ++ pass
|
|
177
|
+ sendMessage messageChan msg
|
|
178
|
+ sendMessage messageChan =<< newMessage JoinCmd
|
|
179
|
+ return Connected
|
|
180
|
+ | Just (WhoisNoSuchNickMsg n) <- fromMessage message, n == origNick =
|
|
181
|
+ infoM "Original nick available" >> return NickAvailable
|
|
182
|
+ | otherwise =
|
|
183
|
+ return Connected
|