We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Convos, a modern IRC client for your browser

00:00

Formal Metadata

Title
Convos, a modern IRC client for your browser
Subtitle
A fullly HTML5 async Node.js-like application in Perl
Title of Series
Number of Parts
199
Author
License
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
HypermediaData conversionRadical (chemistry)Tablet computerTouchscreenInstance (computer science)Cartesian coordinate systemObject (grammar)WindowModule (mathematics)Client (computing)Loop (music)RobotMathematicsProjective planeAsynchronous Transfer ModeParallel portElectronic mailing listMoment (mathematics)Avatar (2009 film)SoftwareInternetworkingMultiplication signTwitterOnline chatComputing platformField (computer science)DigitizingTable (information)Function (mathematics)outputUniform resource locatorWeb 2.0Software frameworkScripting languageLoginMultilaterationOpen sourceTournament (medieval)Connected spacePhysical systemKeyboard shortcutOnline helpRankingDefault (computer science)Computer configurationCore dumpEvent horizonData storage deviceMessage passingBuildingServer (computing)DatabaseIntegrated development environmentProduct (business)Open setInsertion lossOrder (biology)Cellular automatonForm (programming)Covering spaceSoftware testingTheoryCircleQuicksortReading (process)Arithmetic meanProcess (computing)Rule of inferenceSign (mathematics)MultiplicationSource codeNetwork topologyWeb browserEndliche ModelltheorieMassPasswordMereologySmartphoneBitThermal fluctuationsFreezingTraffic reportingMedical imagingGodRight angleDimensional analysisWordAreaTransportation theory (mathematics)Price indexGoodness of fitSocket-SchnittstelleTelecommunicationFamilySet (mathematics)Interior (topology)SpacetimeLine (geometry)Associative propertyAuthorizationPosition operatorShift operatorTesselationResolvent formalismTheoremWind tunnelConfidence intervalLecture/Conference
Revision controlSoftware frameworkNetwork socketEvent horizonScaling (geometry)Flow separationPattern languageOperator (mathematics)Order (biology)Right anglePower (physics)BitSampling (statistics)ModemControl flowChainOpen sourceCartesian coordinate systemSoftware testingGroup actionNumberMessage passingGame controllerINTEGRALSoftware developerTheoryMathematicsPhysical systemEndliche ModelltheorieInstance (computer science)Profil (magazine)Sinc functionCellular automatonAdditionArithmetic meanTwitterUniform resource locatorAngleComputer configurationWeb browserModule (mathematics)Source codeDifferent (Kate Ryan album)Template (C++)NavigationProgrammschleifeWordException handlingInterior (topology)Heat transferMalwareState of matterQuicksortGradientFile formatProcess (computing)Front and back endsInformation securityLine (geometry)Integrated development environmentPRINCE2Client (computing)ImplementationInformationMultiplication signMereologyServer (computing)Local ringElectronic mailing listComputer fileArtistic renderingCondition numberSingle-precision floating-point formatSequenceDistribution (mathematics)Directory serviceInsertion lossMarkup languageHash functionWeb pageCore dumpConnected spaceUser interfaceStandard deviationCodeWeb 2.0Division (mathematics)Bootstrap aggregatingAuthorizationProjective planeData conversionSuite (music)WikiCommitment schemeSolid geometryParallel portSubsetGraphical user interfaceFunction (mathematics)ResultantElectric generatorHookingLecture/Conference
Order (biology)DatabaseHuman migrationGraphical user interfaceMessage passingFrame problemConnected spaceMereologyData storage deviceLatin squareModule (mathematics)Open sourceWeb browserLatent heatBootstrap aggregatingScaling (geometry)HypermediaMultiplication signStandard deviationThread (computing)Server (computing)Loop (music)BefehlsprozessorClient (computing)Software testingPrototypeSystem administrator1 (number)Core dumpAndroid (robot)Electronic mailing listSocial classWeb 2.0Socket-SchnittstelleAvatar (2009 film)Normal (geometry)Revision controlBitPlanningEmailArithmetic progressionCodeHookingDifferent (Kate Ryan album)RobotImplementationoutputSubject indexingFront and back endsGraph (mathematics)Cartesian coordinate systemOperator (mathematics)TrailData conversionKey (cryptography)Product (business)SpacetimeAddress spaceInsertion lossAlgebraIntegrated development environmentQuery languageCopyright infringementCountingForcing (mathematics)AreaSemiconductor memoryForm (programming)Element (mathematics)Presentation of a groupElasticity (physics)SummierbarkeitMathematical optimizationEndliche ModelltheorieAdditionGastropod shellGroup actionPoint cloudSource codeSelf-organizationReal numberNumberUnit testingFinitismusMedical imagingPropagatorRow (database)NP-hardSoftware developerMultiplicationVolume (thermodynamics)Arithmetic meanFreewareFunction (mathematics)Interface (computing)Musical ensembleSpecial unitary groupDigital electronicsBranch (computer science)Exterior algebraComputer programmingLecture/Conference
Software frameworkGame controllerInformationCartesian coordinate systemRight angleLine (geometry)Form (programming)Projective planeWorkstation <Musikinstrument>Library (computing)VotingMedical imagingMultiplication signInternet der DingeOpen sourceClient (computing)AuthenticationBitOpen setoutputMobile WebSinc functionAndroid (robot)Bookmark (World Wide Web)Mobile appLecture/Conference
Open sourceOpen setPoint cloudSimilarity (geometry)Service (economics)
Physicalism2 (number)Meeting/Interview
Lecture/Conference
Lecture/Conference
Transcript: English(auto-generated)
ranked.mo, which is a league and tournament system for any sports, like table tennis or squash or shuffleboard and the output company, which is a publishing platform for digital magazines, like targeting iOS, web and Kindle and eventually Android as well.
Today's talk is about Convos. It's an HTML5 async Node.js-like application info, according to the synopsis, so what does that really mean? What is async? What HTML features? And like Node.ho, why are we here? Why are Firetrucks red?
And those are some of the questions I hope to cover in the talk, but others must remain a mystery. So often when I tell people that I made an IRC client, they're going like, Merck? Really? Didn't that die in the 90s?
Yes, Merck mostly died, I guess. You don't often hear AS8 text location anymore on the IRC. But the Internet Relay Network, their chat still thrives and I kind of like this quote that I saw on Twitter. IRC is a chat network for people who run the Internet by Chris Bessert.
And as you might probably know, IRC is very popular in open source. Most open source projects that I use have their own IRC channel. IRC-Freno.org is full of them, and in the public parallel community we even have our own network, IRC-Freno.org.
And Wikipedia also uses IRC to coordinate their efforts. They have bots that announce when changes are made, and Wikipedia are watching that and screening the changes. Thanks to Screen and IRC2 and later IRC, I was online on IRC pretty much 24-7 from 1993 to 2010.
But a few things started to bother me about this solution in later years. I couldn't get any desktop notifications, so if I didn't have the terminal window open I didn't see what was going on.
And I didn't really have good mobile clients. Of course I have SSH for my tablets and phones and stuff, but it's not a really practical solution, which is why we decided to develop this application. So I got together with Jan Henning-Torsen and started to make combos.
Actually we called it Virk first, but we renamed it later, so we did not take it too similar to Mirk. Before I delve into the technology behind it, I want to go through the product itself. It's open source, and you can find it on GitHub, at Norokishashkonvos.
It's artistic license, like Perl itself. You can go there and follow the installation instructions. It's quite easy. We have a one-line installation script which you can just download and run to get it started. It pretty much only depends on having Perl and a big working build environment and Redis.
I'm not going to go through the installation any further, but once you have it up and running, this is the first screen you see. It's pretty standard sign-up. If you already have registered a user, the first screen on your installation will be the login screen instead.
Once you fill out and successfully register, you need this wizard which asks you which NIC you want to use, and which IRC network you want to use as well.
We have some predefined networks in the setup, and you can also list which channels you want to join. You can also use join later to add channels, but this is just the initial setup. However, if you like using a work IRC or some network that we do not support, you can also add the custom network.
You just specify the name and the IRC server you want to connect the default channels to list, and it will be added to that wizard for the next user to connect as well. We do support SSL, but that requires an optional Perl dependency because it requires libSSL.
If you run a Convos version, it will show you if you have that dependency installed or not. Once you connect the network, it starts up like this. Here you can see the first conversation in the list on the top of the panel here.
It's always the Convos bot, which is a built-in conversation bot that you can use to add and join servers. Eventually, we plan to grow that into a lot more features, and I'll come back to that later. For now, you can, for instance, also trash help to get the list of what you need to do and things like that.
Once it finishes connecting to the server, you can see here now it's connecting to Convos, and once you connect, it will switch over to our channel. You can see here I'm connected. It will always sort this top list by the last visited channels.
I'm only joining the Convos now. If you have more channels than there is room for, it will then put a dropdown on the end so that you can see all your conversations. It's very convenient because often you're already in many channels, and you just switch back and forth between the last couple. We also have key bindings that let you, if you press Shift-Enter,
you can toggle between the input field and the channel list so that you can easily just tab through to the channel you want without using the mouse. We also have an avatar support. As you see here, the Convos bot always looks like Jan Hanning at the moment.
If you specify an avatar, you will turn up like I am in the list here. The one we can't resolve, we will also try to resolve it based on the hostname and look it up and grab avatars. If you can't resolve it, it will automatically generate a unique avatar for you
so that you can recognize the people you're talking to with the same avatar all the time based on their host mode. You're always connected even if you close the browser, so if you go back, you will get a list of the things that have the notifications and mentions that you have while you're gone.
If you can also scroll back, we're automatically loading more chat as you scroll upwards so that you can always see all your history. We're using WebSockets to do the communication, so it's really quite fast as well and feels a bit native, as you can see here.
We're using CSS media queries so that we adapt to various screen sizes. It works even on smartphones and tablets. If the screen is too narrow to fit the user list, it will automatically turn into a dropdown on the top so you can find the users by accessing the dropdown in the same way.
Here you can see I have more channels and conversations than there's room for in the list, so it adds this dropdown at the end there so you can see all your conversations. We also support HTML desktop notifications. We open source that separately from Canvas.
It's mojo-concon-rsc. I found a couple of useful modules on C-Fold called rsc-utils and parse-rsc. Basically, we stitched those together with the mojo-io loop to create something like this. You create a new instance of the object and then specify the NIC and the user and the server,
maybe password if you use password, and then you can set it up to listen to events. If you get a join event, you can trigger a message. We have this core connection that's using this module, and it triggers all of the different events.
For instance, if someone sends a message, it triggers the message event and both stores that into the Redis database and creates a push notification to the published subscribe. The last module that we've open sourced based on building Canvas is mojo-source-plugin-asset-pack. This is basically an asset pipeline that we use.
It's not a new idea, but it's a good one, as you see in many other frameworks as well. Most Ruby frameworks are using, and Node.js frameworks are using asset pipelines. Basically, you just define the assets that you use in your application.
From the start, we implemented all of the pre-RFC versions of the specification, and we were the first framework to have full WebSocket support. We even now support per-message-deflate, which was added to Chrome now in version 22,
so that you can have compressed messages going over a socket. This is how it looks in a malicious controller. This is a WebSocket connection to slash messages. Your JavaScript framework connects to slash messages, and then the browser keeps that connection open,
and we just receive messages and send them back to the core system from the WebSocket. We subscribe to Redis messages and send those over to WebSocket, so that we have a connection from the independently running core all the way to the browser.
In fact, the core doesn't have to run in the same instance as the front-end, so you can easily scale it up if you have many users and set up several front-ends that run against the same core. Of course, with all these callbacks and small Redis operations, we do run into the problem of non-blocking order dependencies.
Sometimes you need to have something running after another callback, or you need to run a couple of operations in parallel and then run another operation. I think in some old samples you might have seen what has been referred to as callback nesting hell, where you have a callback inside a callback inside a callback,
or even how you do parallel processes. The way we have solved this is with a built-in module in MoyoLicious called MoyoEOLukeDelay, which lets you specify in a seemingly sequential order how you run your things. I brought up the example here from the synopsis,
which just shows a simple example where it creates a delay for ten different actions. You can see here it sets up ten timers, and even though this is created in a for loop, they are all running in the same order.
This will take 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, and then 10, 9, 8, 7, 6, 5, 4, and then boom. You can see you can put in a hook so that when all your actions are finished, you can do a callback. Typically, in a controller action,
you use MoyoDelay to do all your Redis operations. In your own finisher queue, you do render, so you render the template or generate HTML or JSON or whatever your action is. It's a little bit simpler, more realistic example
of how we use it. I do two Redis operations in parallel, and then output the results when they're both finished. In addition to building this thing on the MoyoLicious framework, we've also stolen quite a bit of the Moyo culture.
That means we do all our development on GitHub and accept changes to pull requests. We have a common parallel tidy RC, which we actually borrowed from the MoyoLicious project as well. Since we're in 0.4, we are now running parallel tidy automatically on all commits so that the callback is coherent and we follow the same standard for every commit.
We've also been focusing a lot on having a solid test suite based on the same kind of principles that the MoyoLicious test suite uses. We use testConConModeMojo to test all for controller actions and things like that.
Deploying this thing. My previous open source application was mojo-mojo, a wiki based on the catalyst framework. It was a little bit of a pain to install. It had a dependency chain of 417 CPAN modules and landed me on the CPAN Heavy 100 top list.
That made it a little bit hard to install. If something breaks in that chain of 417 CPAN modules, you have a problem. Converse has nine dependencies, including MoyoLicious. We also use Carton to bundle all of those dependencies with the distribution.
When you download the distribution, you actually know which version you're going to install. The authors can just ship a new version and break my application. Mia Gava made this thing based on his experiences with Ruby. Carton is very similar to a Ruby project called Bundler, where you bundle all the depths into the distro.
On setup time, it installs it into the local directory on your server. Even if you have other versions installed in the system, it will use the local versions when you run that app. He also created the CPAN file format, which is an easy way for applications to specify the dependencies.
You know, CPAN modules use the makefile.pl, using module install, or X2Tilt's makemaker. Those aren't really well suited for applications. CPAN file is supported by CPANM and Carton, and it allows you to specify your dependencies in a really simple file format.
You can also lock the versions to say, my application requires this version of the module at all times. Once we have that set up and bundled, you use carton exec to run your server with the given carton dependencies. Typically, to start convos, you do carton exec convos-backend, for instance,
or convos-server. If you run the server by default, it will run the backend embedded, but if you want, you can also run it separately, so that you can upgrade, for instance, the frontend, the restart,
the frontend without disconnecting from RC. In addition, we have created a Dockerfile to make it easy to test this thing, and we have a Docker trusted build, so whenever we do a release, Docker automatically rebuilds the Dockerfile and updates the code. I don't know if you've looked at Docker,
but it's a very simple standard container format so that you can run different applications with very little overhead inside their own separate Linux environment. If you have Docker installed, you can just pull and run, and it will start up convos automatically without any further hassle.
It's also possible to deploy convos to Heroku. The WebSocket support is in beta, so you have to enable that. But malicious confirms the PSCGI spec that plaque uses, so you can use Miyagawa's buildpack to deploy to Heroku. And that was deployment, so I'm going to move on to talking about building the web frontend.
Of course, everything is HTML, CSS, and JavaScript. The first implementation, we started with a quite heavy JS MVC, where we rendered all the templates client-side
and transferred it to JSON over the WebSocket. We ended up thinking that the solution was too complicated, so we just tore it out, and we're now simplified by generating all the server templates inside the server side, and we're sending HTML over the wire. Even the IRC messages are just a simple HTML markup
that we can push directly into the user interface. Rather than Ajax, we're using IaH. We're also using HTML5 push state, so that when you change the channels, we will actually update URLs.
This degrades gracefully, so if you have an old browser that doesn't support it, it will just do a full page reload, and you will have exactly the same URL. But this also means that we have good bookmarkable URLs. I don't know if you remember, but for a while there was this trend of having hash marks in your URL, which is really annoying because it breaks things, and you can't do curl to get the source or whatever,
and you will see different things. Push state is a much better solution, and it's supported in all modern browsers. The way we implemented it was using jQuery Pjax, which was a jQuery module made by GitHub. They use it for their source tree navigator, where when you go up and down in the source tree,
it also automatically looks like it's updating the URLs, but it's actually just doing Ajax and JavaScript to change it. Here is how we set that up. For each of the different links,
we specify which target that it should render it, and which fragment it should use. Then we have a Pjax success trigger at the end, which sets up everything based on the new information that we loaded into the divs. We also started doing the design in Bootstrap.
It's a really easy and fast way to prototype something, and it's great for making stuff like admin interfaces, but our experience was that if you want to make a really custom, specific UI, Bootstrap is more hassle than it's worth. So in the end, we tore it out,
and wrote a simple custom media query-based layout. It was less work than trying to force Bootstrap to do exactly the things that we wanted. Bootstrap is great for the first 90%, but you can struggle a lot with the last 10. So in the end, we decided to try to keep it simple
and stupid for all of our front-end things, but we still met some problems. The first problem that we faced with the solution was IRC stopped working when I moved around. Whenever you close your laptop and go to somewhere else, the WebSocket closed and it never reconnected once it was broken. So we used VS Reconnecting,
which is a simple module that you can find on GitHub, and whenever your WebSocket connection is broken, it will try to reconnect, and that's all that's for us. But then still, IRC stopped working anyways, which was really puzzling for a long time. You had it open in your browser, and eventually it would disconnect or timeout.
And we were using the WebSocket ping frame, so we were expecting the keepalive to be working. But apparently, Chrome doesn't really use those ping frames, so we ended up having to create a different solution. This is something we found other people were doing as well,
and we're just sending pings over standard WebSocket frames rather than using the specific WebSocket ping frames. And that solved the problem and made it keep the connection alive, because it stopped working and Chrome didn't even notice. It thought it was connected until you tried sending a message, but you weren't getting any new messages in.
Of course, we also met Unicode problems. I think that goes in every product, but IRC has no real standard character encoding. Many people use UTF-8, but some use Latin-1 or other Latin things. So Christian Hansen has made this module called Unicode UTF-8.
It supports a fallback to Latin-1 if the part isn't about Unicode. So that means that we always send Unicode out, but if someone sends Latin-1 to us, we can parse it and handle it just like it was Unicode.
So the next problem we met was, we changed how we use our schema storage. How do we update all the existing users? So we wrote Convas Upgrader, which runs a bunch of migrations in order just to change your database. So we keep track of which version of the application you are using,
and whenever you're upgrading, we automatically can transform your ready schema using run operations. So this is an example from one of the latest versions, where we removed obsolete keys that were not in use anymore.
And those were automatically regenerated. So it's just cleaning up like that. So things that we plan to implement that we haven't gotten around to yet. We do plan to, as of 0.4, we have about one and a half years of development,
and we have a minimum viable product. So we've been iterating until we got it right. But we want to implement search. We already do logging to file, so all the conversations will be logged to the server, but we plan to implement a pluggable indexer backend. We will probably just ship with ACK,
the Andy Lester's graph module, and allow you to use Elasticsearch or SAPAN or whatever by writing a different indexer. We also want native mobile clients. Luckily, IRC Cloud has open-sourced their iOS and Android clients, so the current plan is to implement their API,
and then we will get the clients for free rather than having to implement Android and iOS clients ourselves. The other thing we are looking into doing is plug-ins. We really want our IRC bot to get more of a personality, so the way we plan to do that is expose hooks
so that you can make the built-in bot answer different things. One of the first things I'm looking at is doing an ELISA bot so that you can chat to it if you're lonely, but maybe more useful things like GitHub notifications and things as well. Actually, Convos can run already without an IRC server,
so you can just use a loopback connection if you have a work channel and you're only communicating through Convos. We hope to allow Node.NET Hooks so that people can customize things for their own use. The last thing I have on my roadmap is distributed IRC avatars
so that we try to generate those avatars based on the host mask, but that is often not practical because people are IRC from hosts that are not their email address, so we're looking into using C2CP to query clients to ask them for a gravatar email and then use that to generate an avatar.
We have some progress on that already. There is an experimental branch, so that will probably land in 0.5. Of course, if you want the feature, we would very much appreciate pull requests. The code is open source and it's free to hack on.
Of course, it would be nice if you come and talk to us first so that you don't waste your time with implementing something that we do. I have a little bit of time. How much time do I have left?
Ten minutes. I have a little bit of time for questions, I guess. I have one. It looks really, really good. Would it make any sense to extend the support to include the avatar as well as IRC? Yeah, that would be very possible because we have a connection class which is separate and it would be easy to subclass that and to use the netjabber or whatever
instead of the IRC thing that we do. Of course, you would need an asynchronous Jabber driver, but I don't think that would be huge. I'm not using Jabber, so I'm not hugely motivated myself, but I think it would make sense to do it as well. Are there any particular issues with particular browsers being supported?
Well, we don't support all browsers. We support all of the everywhere browsers, like Chrome and IE10 and Safari and new Mozilla versions, but like IE6, there's just no way. You have to have web sockets.
All modern browsers are supported, but most old browsers wouldn't work. Including Android WebKit? One of the screenshots I pasted was from my Android tablet, so recent Chromes and Android work fine. I haven't tested it much on the 2.0, but Android 4 should be perfect.
I also have gotten a Firefox phone from Salva in the back of the room, so we do the final on testing and making sure that it works properly on that as well. I feel that it works on the JOLA phone with the same physical ones. Yeah, so browser support is pretty good.
Yes? Did you say that you are keeping the connection, even if you disconnect from the browser and you get all the log back and everything? Yeah. How are you doing that part? Well, so the core class is sending both push notifications and all the messages to the Redis store,
and so we store all of your... If you don't have any listeners to the push notification, it just doesn't go anywhere. It just doesn't go anywhere, but when you connect your browser, you just fetch the connection list from Redis and get all the messages. So you keep the connection live on the server? The connection lives on the server, yeah.
The IO loop keeps all of the connections live in the same thread. So if you're running a server with many connections, I really recommend using the EV server. I was doing a test server and with the Pure Pro version, I started getting CPU issues around 15, 20 clients that were all using many channels,
but with the EV, it scales really well. Over there? Is there any plan to be able to use it as a browser? Well, you mean like to connect to a normal client? Yeah. Yeah, I have been looking into that and there is a plan for it, but it's not on the short-term roadmap.
Maybe one or two versions from now. Have you considered using Apache Cordova for your mobile front-end, because since it's an HTML application and that's the hybrid frameworks,
then it can give you all the native clients for free? Yeah, I have been looking into using it at a phone gap. The only reason I wanted is to make it easier to be able to put it in App Store, because people have a little bit of problem using that bookmark thing to add it to their home screen. And I really want the native push notifications, which I can't do.
So, either Cordova or... I'm a little bit confused by those, because phone gap using something else is also open source, right? Well, phone gap was open source, completely open source. It was turned into an Apache project, which is Cordova. So that is the same project, alright. Can I configure the client to fetch my users
from an LDAP server? You could do that. Right now, it's just stored in Redis, and I don't have any support for that, but I think it will be really easy to implement as well, because authentication is really separate,
and since we're using religious, I know there's already authentication libraries from religious. So right now, it's not supported, but quite easy to implement. Alright? Was that the last one? So, if you have any further questions,
you can come to IRCperlorg at the Convos channel. So, you can go get Convos at convos.vi. We actually registered a Belarusian domain, because it seemed like a good idea at the time. Yeah, okay. Thank you very much.
Thank you for the talk.
You said something about an Android and iOS application. What was the name? We're telling the IRC cloud it's a similar service source, but it's not an open source, and it's hosted through pay-per-month. They have open source care clients,
so if you look at IRC, you'll see the search bar, you'll find there, you'll find search again. So what we plan to do is just port them, and say maybe I'll delete it. I think otherwise they're like... How's it going, asshole?
Okay. No, I mean... I wasn't supposed to be here.
I was supposed to be home. Alright. Okay. Ah, so... Okay, I see. Okay.
Okay. Actually, wait. It might be me. One second.