IRC Server in Go

Introduction

About the Project

So I’ve been playing with Go recently, and am at the point where I want a bigger project to work on, I initially thought about some sort of client-side protocol implementation, but it looks like there’s already a library to handle the client-side of just about any protocol worth looking at.

Skills I’m using

This project is indeed heavily focused on programming in Go, but will make use of language agnostic skills, such as network programming, concurrency and event-driven architecture.

Updates

  1. 2014-12-02
  2. 2014-12-03
  3. 2014-12-06
  4. 2014-12-07
  5. 2014-12-10
  6. 2014-12-12
  7. 2015-01-06

Further Reading

If you’re interested in knowing more about what’s behind this project, take a look at the following links:

1 Like

Project Update: 2014-12-02

Planning the Application

So the first challege with this project is working out where to start. Do I start with writing the code to handle the IRC protocol? Do I tackle managing the connected users? Do I handle the message bus? So very confusing!

So as I always do with something like this is start with a simple mock-up of what I want, that is, a very simple prototype which ticks the bare essential criteria.

In this case, I want to build the most simple IRC server possible. One which allows the user to connect, and send messages, and have those messages broadcast to all other connected clients.

For bonus points I will avoid using libraries to handle functionality which I can build myself (within reason).
I will write my own IRC protocol handling, server handling, built directly on the go net package.

This will introduce one of the key points of using Go, which is concurrency.
Each client will be handled by its own goroutine, which means each client connected will have its own virtual thread managed by Go’s built in scheduler. This is a simple measure which should hopefully allow the application to scale to many users with relative ease.

I’ve got some thoughts already about what I’ll use for the message bus, most likely using ZeroMQ / 0mq as it is a lightweight messaging system which can be used in-process, as well as over the network (should I wish to implement clustering)

Next step: Start building the prototype.

You can track the progress of the code on my Github: Repository Link

Progress Update: 2014-12-03

The Prototype

So I’ve started to build my prototype, which is able to accept incoming connections and understand a couple of basic commands. One thing I didn’t anticipate is that the spec for the IRC protocol is somewhat confusing, having checked both RFC 1459 and the newer RFC 2812, and also using wireshark to snoop some live data, I found that actually I need to handle users and nicks from the very beginning, as the first two commands the client will usually send are USER and NICK, both of which need to have a proper response for the client to recognize the connection.

Next Steps

The next thing I need to do for this prototype is to properly handle the initial USER and NICK commands the client will send, and to also handle client-requested PING commands, to keep the connection open.
I can then add a single channel to the server and then work on the message broadcasting.

Once that is done I can start to think about using what I’ve learnt from this prototype in a more maintainable version with more features.

1 Like

Progress Update: 2014-12-06

Prototype Progress

One of the challenges I mentioned in my previous post was that the server responses aren’t documented in a particularly helpful way, there are no examples given, only instructions on what each response is to be used for, and how they should be handled.

To this end I used [Wireshark][wireshark] to capture data from a connection to a real IRC network, to be used as a basis for the control message flow needed in my IRC server.

At this point, the prototype is able to take a user connection, set their ident and nick, and then send the appropriate 001 response to indicate to the client that their connection is established.

Next Steps

Next step is to implement the JOIN and PRIVMSG commands, so that a user can join a channel and send messages into it, which will be broadcast to all other users of the server.

After that, it will soon be time to begin planning a more final structure for the application, and to get started on that.

Progress Update: 2014-12-07

The Prototype

The prototype is now at a point where the basics are covered and I’m at a point where the ideas need more fleshing out before I can continue much futher.

Next Steps

The next step will be to introduce ZeroMQ into the mix, and see if and how I can use that to handle the message routing and the handling of multiple communicating clients.

Progress Update: 2014-12-10

Code Improvements

I’ve made progress with a more final version of the IRC server, which is better structured…

Next Steps

Next is to handle the commands the client issues in an effective way. I’m also still thinking about how to handle message routing and also how to handle channels…

# Progress Update 12/12/2014

Message Handling

I’ve looked around on github to see how other Go developers are working with network protocols and handling messgages, with special attention to IRC clients and bots. After taking a look at a bunch of approaches I’ve decided to use a callback based system which will reference a CallbackFunction interface, meaning given a message, and the connection from which it was received, the message type can be identified. In this case the IRC command, and that can be used to invoke a CallbackFunction to handle the specific type of message.

Next Steps

Implementing some CallbackFunctions to handle the essential messages for IRC, such as USER,NICK and PING. And then using these to send the required server responses for a new client connection.

#Progress Update 06/01/2015

I’m still working on this project! (Although I’ve taken a long break)

Message Handling

I think I’ve cracked the nut on how to handle the messages, I’m going to implement something rough for now though. Then see if it works well enough or needs improvement.

#Progress update 19/02/2015

It’s been over a month since my last update, but I am still working on this project from time to time, and here’s where I’ve got.

Channels

I’ve realised that channels are a great step to take before message handling, as they help implement a method to syndicate the messages to the receivers. For now I’m using a map[string]*IRCConnection , where the string key is the connection Ident, which looks like this: nick!user@host, so I can uniquely identify a connection based on that. The Ident is also what is returned when you coerce the connection to a string.

So far channels are implemented as a struct:


type IRCConnectionMap map[string]*IRCConnection

type IRCChannel struct {
    connections IRCConnectionMap
    owner IRCConnection
    name string
}

So when a message is sent, a goroutine will be called to iterate over IRCChannel.connections, and for each connection it will call IRCConnection.SendMessage to relay the message to each of the clients.

This is still to be tested, but its coming along still!

# Progress Uopdate: 21/02/2015

An Exciting development…

I’ve now got it to ingest messages and relay them to other connected clients on the server. There are still a couple of big issues though:

  • All messages come from the server, making the chat effectively anonymous between users…
  • The first word of the message is not actually included as part of the message

A screenshot of things!
(For anyone wondering that’s IRSSI on the left, and Weechat, my usual IRC client on the right)