Weekend project: irc2pusher message relay

Each weekend i try to experiment with something new. It could be pretty much anything: new language, cool piece of open source software, new technology or project. Last time i hacked on OSX launchctl manager which was based off original launchy gem to manage plists. I did not like the idea of switching rubies and gemsets and figured that rewriting it in Go would be the best since it compiles into a static binary and does not required any dependencies.

Last weekend i had the idea of creating a simple relay that would stream messages from one (or multiple) IRC channels to a websocket. I dont use IRC much, but i like to read interesting discussions and just kind of observe on whats going on. Most of my experience with IRC on Mac is around Limechant client, which is by the way is pretty good but disconnected a lot. What i needed was something that i can simply drop into a cloud server and let it run. On client side i could connect using html websockets and build whatever the UI i wanted.

Go has been my to-go language for system scripting so i decided to go with it again. Pusher was used instead of plain websockets. I've been using Pusher for many projects and its rock solid, plus they have a free plan for 100k or something messages per day which is more than enough.

At the time of writing this Pusher does not have their own client written in Go, so i used library written by Timon Vonk: http://github.com/timonv/pusher. Works great. For CLI options parsing i went with go-flags by Jesse van den Kieboom. It has a few quirks but overall is great. The best of it is that it could parse terminal arguments into a golang structure, like this:

type IrcOptions struct {
  Server   string `short:"s" long:"server" description:"IRC server hostname or IP"`
  Port     string `short:"p" long:"port" description:"IRC server port"`
  Nick     string `short:"n" long:"nick" description:"Nickname"`
  Channels string `short:"c" long:"channels" description:"Channels to join"`
}

And initialization would like like this:

opts := new(IrcOptions)
_, err := flags.ParseArgs(opts, os.Args)

if err != nil {
  fmt.Println(err)
  os.Exit(1)
}

IRC part of the project is pretty much standard, just a TCP socket connection that parses incoming data. On PING it responds with PONG, on PRIVMSG it sends a new pusher notification with channel, nickname and message payload. You can the source code here: irc2pusher.go

Start irc2pusher relay with the following command:

PUSHER_ID=myid \
PUSHER_APP=apptoken \
PUSHER_SECRET=secret \
\
irc2pusher -s irc.freenode.org -c channel1,channel2

After relay has established connection, it will send message payloads to pusher in the following format:

{
  "nick": "sender",
  "channel": "#channel",
  "message": "hello there"
}

Check full project source code on Github: https://github.com/sosedoff/irc2pusher