Creating a Discord threads notification bot for Slack using Val Town.
Val Town positions themselves as “If GitHub Gists could run And AWS Lambda were fun”. I found myself with a holiday code itch, and decided to scratch it by taking Val Town for a spin.
In this post, I'll share my experience.
Our company uses Slack internally, but Discord for our community. Consolidating everything in a single platform is, at this point, a pipe dream: Slack is not great for communities, but many of our peers will use Slack connect, so for company business it is a lot better.
The problem then is that it is too hard for most people in the organization to pay attention to both platforms. Engineers are mostly on slack talking to each other and solving problems, but we want to make sure our users always receive top treatment and get their questions and concerns answered in a timely manner.
For most of last year, I would just be on Discord the whole time myself, and then manually post questions that I couldn't answer on Slack, tagging the people I found relevant. This quickly became a bit annoying.
What if I wrote a simple bot to just notify people when there are new messages? I code very little these days in my new job, so I figured it would be a good way to at least do some cool, self-contained project that is at least fun. But then I realized that I'd have to somehow keep this running, deploy it somewhere, set up a GitHub repository, maybe even actions, and since I essentially only had a day or two I could devote to that, I felt like giving up.
I caught myself thinking: “Damn, if only there was a way for me to just throw some code around and make it executable, running every now and then, then this would be more doable”.
And then I immediately remembered that in fact, there is. Val Town is a platform that does exactly that. I have a good relationship with their founder, and always loved the idea. So let's put it to the test!
Val.Town offers a way to execute scheduled functions periodically, so that was perfect for me. I quickly found out that it felt easier to split the code into the higher level logic and an inner function that I can then iterate and test in isolation. This is also something that I saw other people do in their own vals, so let's do that!
The main entry point of my bot is:
The interesting bits are in getThreadsActivity
:
The logic I wanted to implement was very simple: Discord has an API that allows you to fetch all active threads. Those are defined as threads that were either explicitly marked as active, or seen a message in the last 3 days.
We reach out to discord to query a list of active threads, see if we had already handled that particular thread, and if not, send a message to Slack containing enough details about the message (the title) so people can figure out if it is relevant for them, and the link to the message on Discord.
To keep track of which messages were already handled across invocations, we have to use some form of persistent storage. Thankfully, Val.town exposes a SQLite API, which happens to be powered by Turso. Each user, upon signing up to Val.town, receives a SQLite database!
We will use our SQLite database for persistence. Because Discord's API already returns just the active threads, there is no need to do any cleanup of old messages. That keeps the algorithm simple: Since we have SQL at our disposal, just transactionally delete all data on that table and write it again with the message information we got from Discord. Here's an example message from Discord to Slack:
Using Val.town was an absolute blast. The project took me more time than I wanted mainly because I was fighting the Discord API: as I came to find out, there is no way to get new messages: channels and threads have a fundamentally different API. To be able to notify our employees about new messages in channels and new messages in threads would create a complication that I didn't want to maintain for this project. So after a lot of research, I just kept it simple.
Which means I iterated a lot, and actually did all of my development inside Val. The one thing I missed was a more interactive way to inspect the SQLite database: the method I used (and later found out to the be one indeed recommended by Val) is to just use a Val to execute SQLite commands, like so:
Actual example of me inspecting the database, and seeing if the number of entries matched my expectation. It did!
While that works, it's a lot of typing where in a shell I could just issue SQLite commands directly. Not to mention the shell usually will offer higher level primitives like .schema
, .dump
and other things that you can use that goes beyond SQLite commands.
Other than that, it was an incredible experience. My bot is running and updating people on new messages, from what is essentially a GitHub gist, with database access and everything. Totally recommended!
If you are in the market for a simple way to just write code and be done with it, I can't recommend Val.Town enough. It did the trick for me, a joyful experience from start to finish.
Val.town offers each of their users a database by integrating with Turso. If you have a platform that, like Val.Town, wants to give each of your users a database that integrates deeply with your product, sign up for Turso today and see what it can do for you!