While working on TRC I made a collection of popular IRC clients per platform, only to realise BlackBerry 10 had no real IRC clients. The best one available seemed to be an Android client running in an emulator.
So I asked a friend, collector of phones and owner of Heris IT to help me build a native IRC client for BlackBerry 10 using their Qt based Cascades framework.
This is a beta release that costs half of the final product, but also has half the features. We are doing this early release to collect some feedback, so please let us know what is important to you.
There are a few known issues:
Sending messages is broken on 10.2
The “Settings” button is a dummy.
The “Change nick” button is a dummy.
When the phone is standby the server kicks you of after a few minutes.
I have been trying to implement a CyclicBarrier in core.async, but it took me a while to understand how a channel works.
To support IOC and thread and be fast, the implementation is a lot more verbose and complicated than the bunch of promises I initially expected.
It seems all verbosity and callback hell that can be avoided by using channels is bundled in their implementation. Take this loop from cleanup that removes inactive handlers, can you spot the 2 actual lines of code?
But let’s go back to the beginning. The basic unit of a channel is a handler, a glorified callback. It has a commit method with returns the callback, an id for avoiding deadlock and a method to check if it is active.
The latter is used with alts!!, so that after one possible channel has been acted upon, the other handlers turn inactive, but lets stick to a simple <!!.
Now let’s look at <!! itself, which is pretty simple. It creates a promise and a callback that delivers the promise. It then calls take! with it. If take! returns nil, deref the promise, otherwise deref the box.
Now let’s look at the main course, ManyToManyChannel.
If you look through all the verbosity, take! and put! are pretty similar. There are 3 main code paths in each.
There is someone at the other end. Match up the handlers, call their callbacks and return the value or nil in an IDeref.
There is room in the buffer. Take/put the value in the buffer and return the value or nil in an IDeref.
There is no room. Put the handler in a list and return nil.
I wonder if the code could be made more readable with a few macros for locking and iterators.
Understanding put! is left as a exercise for the reader. Understanding the IOC part is left as an exercise for the Clojure gods.
I will write more about my ideas for barriers and transactions later.
I finally took some time to cut out the private bits from my deploy script and open source it to the world.
This script allows you to deploy an IRC server, bouncer, web interface, bot and some custom modules to anything you can think of: VirtualBox, VPS, EC2, OpenStack, Docker…
The only things that are missing are the SSL certificates and services.
You can add your own certificates, generate self-signed ones, or disable SSL altogether: