pixelebbe - a look at janky infra.
so, what even is pixelebbe?
pixelebbe is a slower alternative to the pixelflut project. what makes us different is the human aspect - at pixelflut, you battle against other players programming complicated machines, at pixelebbe, you battle with other humans directly, together, to create a work of art.
the idea
for a while now, @luap42 and i have been thinking about running a small project at chaos events, an installation that gives us something to do to pass the time. we've been looking around for a while and besides hosting a talk ourselves, there wasn't really anything else that caught our eyes. and thus, we were searching for quick, cheap and easy ways to create something that people could interact and play with.
inspiration struck when i was watching a video about the reddit event r/place - a massive multiplayer online game canvas that allows users to set pixels with an indexed color space.
this allows communities to collaborate on artworks and manifest their place on the canvas for the world to see.
that couldn't be that hard to replicate, can it?
we know that if we were to open this up to a massive amount of chaotic individuals, we would need some form of rate limiting - after all, we don't want a single player to flood the canvas in milliseconds - we aren't pixelflut after all!
and so we came to choose a name for the project - pixelebbe. named after the opposite of "flut" (flood) being ebb, in german ebbe. i was happy to see that pixeleb.be was available as a domain, so i begrudgingly supported capitalism and set up a quick site.
a quick aside: how is it possible that some registries only reveal that they will need additional data fromm you only after you already paid for a domain? the registrar for the belgian .be TLD appearantly wants a copy of some form of official ID to make sure you're a real person. had i known this, i would have picked an easier to get TLD.
i was in the legal process of changing my name and thus had no official government ID with my correct name. to get this domain i had to send a very redacted copy of my birth certificate to belgium. but oh well, the other parts of our infra worked mostly first try!
the process of setting a pixel
as stated above, we needed some sort of rate limiting to prevent someone from just flooding the whole canvas. that meant setting a pixel as a user on the site itself was out of the question. we didn't want any captchas though - if someone spends their time to code a bot that can "defeat" our rate limiting, they should get credit for that. as such, we decided on a proof-of-work approach.
after some thinking, we settled on the following ways to set a pixel:
- pixelweb - look at the current state of the canvas. also hosts our admin tools for event management.
- pixelpost - send us a handwritten (for spam protection) postcard via chaospost.
- pixelfon - set a pixel by calling us directly and asking politely.
- pixelbeep - call our automatic help hotline via DECT and dial your way to enter a pixel.
- pixelfax - fill out a paper form and fax it to our ocr script.
- pixelbot - wait for a place in the queue to talk to our voice-assistant phone bot.
- pixeldust - morse your pixel data via smoke signals, why not?
we quickly decided on some easy ones to start off with: pixelfon, pixelbeep, pixelpost and pixelfax.
pixelweb, pixelpost and pixelfon - basic operation
being told a pixel and setting that pixel on a globally available canvas should be pretty easy. but to achieve that, we needed a canvas to set pixels on. software to the rescue!
within a couple hours of work, @luap42 cooked up a python3 + flask web app called pixelweb that supports multiple users, groups, permission management, multiple concurrent events and manages grids of pixels.
using a page in the admin tools allows us to manually set pixels on the canvas by entering a coordinate, a color and optionally a player name tag (for statistics, more on that later.)
this gives us all the functionality that we need to handle chaospost pixel submissions - pixels sent through chaospost are entered manually by us as soon as we find enough time.
this also basically fulfills all the requirements to set up our organic DECT hotline. players call us and if they ask politely enough, we will set the pixel.
but.. we're just (more or less) humans and also sometimes need to follow the 621 rule (not to be confused with the e621 rule), so we can't really be online 24/... 4? (depending on the event) to receive calls.
so it was time to optimize and automate.
after a lot of work, we had a setup script that manages to set up the full backend on a fresh debian install within minutes.
some more feature revisions later, we have a UI that allows admins to edit events, manage pixel submission workflows and appoint event angels that are able to set pixels for us.
so, despite what the page looks like, the software is fairly complex and allows for some truly mindboggling debugging experiences if anything blows up that our sophisticated error handling can't handle.
try:
do_stuff()
except Exception as e:
...
(excerpt 1: error handling structure)
pixelbeep
our pixel storage backend has a very simple api that allows for settings single pixels, so all i had to do was pick up a call, play a quick message, detect dtmf tones, set the pixel using the api, report if all previous steps had worked successfully, then hang up the call.
this phase of the project is what i will refer to as "SIP hell".
SIP stands for "Session Initiation Protocol" and it is a pretty easy to grasp protocol for creating digital streams for data communication, including voice, video and fax calls.
since SIP is a pretty old standard, there should be plenty of libraries to support it, right?
yes, but every single one i managed to find is either unmaintained, not compatible with the languages that i have basic knowledge on, or don't install on any usable OSes, so the only option i had was a library called pyVoIP.
it's a pretty simple to use, pure python library, enabling SIP calls to a network target to be answered automatically.
it then allows the programmer to play audio, receive and decode DTMF tones and some other functionality that we didn't use.
after a bit of tinkering, i got number input working and was submitting api requests to our backend and setting pixels - all in under 100 lines of code!
getting audio feedback to the user was a bit more tricky though - audio playback is sometimes handled asynchronously, allowing the user to input data before they are meant to and plugging up the input with garbage data, causing their requests to fail.
i needed a simple, but stable protocol to differentiate valid inputs from just random button mashing, so i decided to prefix every number with a pound symbol (or hashtag, for us zoomers) and close the message with a star. that way, entering pixels should be possible on almost every time of phone (yes, most rotary phones don't support # and )
fixing that required halting the program at certain points, flushing the decoded DTMF buffer and finally receiving the correct input - but hey, under 200 lines for a complete phone handler script is still pretty cool! (or at least i think so :3)
pixelfax
finally, almost all of our phone services are working correctly. only one last hurdle left - germany's favorite 90s technology - telefax.
laup42 designed a set of documents that should allow us to scan handwritten forms via OCR, and my favorite package (pyOCR) actually managed to scan it correctly! so the last pat was getting fax receiving to work.
as you might know, we weren't able to offer fax services at GPN22 - and it's not that we didn't try, but we were focused on the wrong thing.
appearantly, fax over SIP is hard to do - so hard to do in fact, that most software pacakges just try to force you to use a cloud subscription solution instead, but that's not an option for us.
after fighting for multiple weeks with various forks of FreeSWITCH, HylaFax, Asterisk and lots of others, I gave up on fax for now.
in my seemingly unbeatable battle trying to get various Software PBXes to connect to a remote SIP extension, i eventually contacted someone from eventphone during MRMCD25. their advice: stop trying to use SIP to receive FAXes, that that will be unstable at best - I should instead try using ISDN, as provided at Congress.
so, finally, that is the service that i am currently hoping to get running for congress - fax via ISDN to send us pixels.
the future
so, in case we get fax to work and find some time to implement the voice bot, what's next for pixeleb.be?
maybe a bigger canvas?
multiple dial-in numbers for voice bots?
we'll see. if you have any suggestions, feel free to tell us.