irc-client-1.0.0.0

Ver­sion 1.0.0.0 of my ir­c-client lib­rary has just been pushed to Hack­age. This is a su­per­-major re­lease which changes just about everything, so rather than try to write a changelog, I’ll give a gen­eral in­tro­duc­tion to the pack­age.


ir­c-client is a lib­rary for writing event-driven IRC cli­ents. It sup­ports both plain­text and TLS. A simple client which joins a channel and prints everything to stdout looks like this:

{-# LAN­GUAGE Over­loaded­Strings #-}

im­port Con­trol.Lens
im­port Net­work.IR­C.Client

main :: IO ()
main = do
  let conn = tlsCon­nec­tion (With­De­fault­Config "ir­c.­freen­ode.net" 6697)
               & log­func .~ stdout­Logger
  let cfg = de­fault­Instance­Config "nick­name"
              & chan­nels .~ ["#chan­nel"]
  runClient conn cfg ()

At the heart of the lib­rary is an event loop: a mes­sage is re­ceived, and every matching event handler is launched. Event hand­lers can be state­ful.

We can make a client which keeps track of a counter like so:

{-# LAN­GUAGE Over­loaded­Strings #-}

im­port Con­trol.Lens
im­port Con­trol.­Mon­ad.State
im­port Data.­Monoid
im­port Data.­Text
im­port Net­work.IR­C.Client

main :: IO ()
main = do
  let conn = tlsCon­nec­tion (With­De­fault­Config "ir­c.­freen­ode.net" 6697)
               & log­func .~ stdout­Logger
  let cfg = de­fault­Instance­Config "nick­name"
              & chan­nels .~ ["#chan­nel"]
              & hand­lers %~ (counter:)
  runClient conn cfg 0

counter :: EventHandler Int
counter =
  let in­cre­ments = ["inc", "in­cre­ment", "++", "+1"]
      decre­ments = ["dec", "decre­ment", "--", "-1"]
      go src f = do
        a' <- state (\a -> (f a, f a))
        replyTo src ("new count is " <> pack (show a'))
  in EventHandler (match­Type _Privmsg) $ \src mes­sage -> case mes­sage of
      (_, Right str)
        | str `elem` in­cre­ments -> go src (\x -> x + 1)
        | str `elem` decre­ments -> go src (\x -> x - 1)
      _ -> pure ()

The third para­meter of runClient is the ini­tial state. In our first cli­ent, we had no state, so we used (). Here we’re keeping track of an in­teger, so we start with 0. This state is ex­posed by a Mon­ad­State in­stance, and can be atom­ic­ally up­dated with state (STM is used under the hood).

Event hand­lers are run in se­quence. If one blocks, everything after it is stalled. If you want a long-run­ning task from an event hand­ler, you can fork a thread which will be killed when the client dis­con­nects:

fork :: IRC s () -> IRC s ThreadId

The runClient call will block until the client dis­con­nects. If you want to in­cor­porate your client into some larger pro­gram, you can get a handle to in­teract with it from a normal IO thread:

{-# LAN­GUAGE Over­loaded­Strings #-}

im­port Con­trol.­Con­cur­rent
im­port Con­trol.Lens
im­port Net­work.IR­C.Client

main :: IO ()
main = do
  let conn = tlsCon­nec­tion (With­De­fault­Config "ir­c.­freen­ode.net" 6697)
               & log­func .~ stdout­Logger
  let cfg = de­fault­Instance­Config "nick­name"
              & chan­nels .~ ["#chan­nel"]
              & hand­lers %~ (yourHand­lers++)
  irc­state <- newIRC­State conn cfg ini­tial­State
  forkIO (runCli­ent­With irc­state)
  -- you can now use runIR­CAc­tion with the irc­state value to in­teract with the client
  -- eg:
  runIR­CAc­tion dis­con­nect irc­state

Well, that’s the ba­sics. You can read the docs to get all the de­tails, and feel free to talk to me on IRC or open an issue if you have any ques­tions.

Date
Tags
haskell, irc-client, programming, release notes
Target Audience
Haskell programmers.
Attention Conservation Notice
irc-client is a Haskell library for writing, you guessed it, IRC clients.