The story of “uws” so far
µWebSockets (“uws”) is an open source WebSocket server with more than 40 million downloads
--
Back in 2015 I worked for a start-up as a GPGPU programmer, writing OpenCL kernels for clusters of AMD graphics adapters. We needed WebSockets they told me, many of them. Well what the fuck is a WebSocket and where can I get many of them?
I started testing and benchmarking a few alternatives such as libwebsockets, WebSocket++ and ws (for Node.js). The results were way off my expectations — I knew one TCP socket would be roughly a handful of bytes in terms of user space memory footprint, yet these servers were giving me WebSockets requiring multiple kilobytes of user space memory. Something was way off, could it really be that people were unaware of this waste? Did people not care?
WebSocket++ was quite fast, but very heavy on the memory. libwebsockets was slow but more lightweight. ws was both slow and heavy on the memory, and by far the most popular.
Because Node.js had the most inefficient WebSockets I could find, had the most popularity and because the company I worked for was stubborn about using Node.js, I decided to create a little project called lws.
lws was a Node.js native addon wrapping libwebsockets, the name was supposed to mean “lightweight ws” as a punch to ws. It was well received, however with time it became obvious that libwebsockets was far from optimal. It had a parser working on one single byte a time, making it incredibly slow when parsing lots of data. It wasn’t really that optimal in memory footprint either.
Fuck it I said, I’ll just write my own implementation. I wanted it to be seamlessly compatible with ws, yet so much more efficient. The name uws came to mind, a second play on ws, “micro ws”. So I wrote it, marketed it and with time it was quite popular. It performed in memory and time significantly better than the three before mentioned implementations.
Problem is, when something popular spreads everyone want to capitalize. The reason why we have trademark laws is because companies need a way to protect their brand from damage. If you take a popular brand known for something good, and you misuse that brand by slapping it on something really bad, it creates damage to the brand. Think about opening a restaurant, calling it “Gordon Ramsay’s burgers” and then serving cold McDonalds burgers there.
When Socket.IO, the most inefficient piece of server software written by man kind, started to market itself as “using uws as the WebSocket engine”, people thought they were getting the true, raw uws. In reality they got cold McDondalds burgers, just like before. Socket.IO is such an incredibly bloated and inefficient project that it doesn’t matter what kind of software you bundle with it — it’s always going to bottleneck any improvement you strap on to it. It’s essentially like a black hole of inefficiency.
Of course, some reported a 5% increase or something small like that, and took it as the uws improvement and went on with their day, even though true, raw uws is more of a 500–1000% increase over Socket.IO. This majorly damaged the brand of uws and people still to this day informs me about how they use Socket.IO with uws — it’s the worst outcome a brand can have. To be associated with Socket.IO, one of the very core reasons why I started this work — to show how incredibly flawed the design of many of the most popular Node.js projects are.
From this I needed to make a break, a clean cut, I started a complete rewrite of everything and changed license to Apache License 2.0 which holds a very clear clause about trademark — you are not allowed to use my brand, basically. I wanted to make this new variant entirely incompatible with anything Socket.IO and changed the entire API to my own design. It was no longer modeled after ws but from my own design. I expanded the marketed names to “µWebSockets.js”, “µWebSockets” and “µSockets” — as three separate projects. µWebSockets.js for Node.js users, instead of the old uws name.
With this rewrite I made things yet more efficient, better structured and with more features such as its own Http server and router, pub/sub support for WebSockets, etc. It was meant to be an entire replacement to Socket.IO rather than a lower level component for it. That’s the reasoning for breaking compatibility with older versions and deprecating them — they had started a path on the wrong way. uws v0.14 had to transform into µWebSockets.js v0.15 to counter this major brand damage.
With the change from zlib license to Apache License 2.0 I also made the decision to stop publishing to NPM as a way to further minimize legal issues — you see NPM requires you to be infinitely liable for anything you upload, yet doesn’t allow you to decide what to delete, essentially resulting in blackmail. A firm titty twist I have no interest in accepting.
Anyways, because these new versions have their own Http server, they are not dependent on anything Node.js. Prior versions relied upon the Node.js Http server, causing a crack between the C++ version and the Node.js version. They had differing functionality and differing paths of execution leading to bugs being fixed for Node.js not always reaching the C++ version. Because everything is shared now in the new versions (v0.15+), everything you do in the C++ project you can do in Node.js and the other way around.
The project is in other words now also a competent C++ project, something not possible with the old code. This means the most to me; to have made something usable for people like me.
With a solid C++ core and a tiny V8 wrapper every bug discovered by Node.js users will affect C++ users as well, leading to a fix being developed for both universes at the same pace. This of course also means that it would be a lot easier to create a competent Python release as well, µWebSockets.py, without introducing a whole slew of new bugs.
This is the story of my project so far, up to version v0.17, the 17th major release. If you want to read more you can go to the project page https://github.com/uNetworking/uWebSockets
There are quite the bit of speculation and “fake news” surrounding this break from v0.14 forward, so I hope this clears things up for good.
Thanks