Picotronlike for backend
I’ve been spending some time trying to figure out a good design for how to let people build online services in the style of pico-8 or picotron.
If you are anything like me you want to see code before reading more:
MAX_MESSAGES = 5 function _serve(request, context, user) if not context then context = { messages = {} } end if request.query.post then local timestamp = os.date("%Y-%m-%d %H:%M:%S") if not user then user = { name = request.query.user } end user.last_post = timestamp local newMessage = { user = user.name, text = request.query.post, timestamp = timestamp } table.insert(context.messages, newMessage) if #context.messages > MAX_MESSAGES then table.remove(context.messages, 1) end end return { {body_object = { messages = context.messages }}, context, user } end |
So accessing this server would be a fetch to http://whereitsat:3000/chat/?context=123&user=offe&post=Hey
, assuming the project is called chat. Anything in the body_object of the first return value will be returned in JSON format. You can also just return a string in body.
Now there’s a first version of this server engine that I very much would like feedback on. The practical purpose is to simplify building things so picotron carts can have connectivity for collaboration tools and multiplayer games. People shouldn’t have to handle hosting, databases or cumbersome deployment. Also it's nice staying with Lua for the server as well.
The basic principle is that using this framework the developer writes a single Lua function that is called for every http request. The function is called _serve(), in line with pico-8 tradition. It’s possible to define more functions of course that can be called from _serve(). The handler is pure functional and does not have side effects. Instead the request information are given as input as well as two objects and the function returns the response and updated objects. The framework takes care of persisting the objects for future requests. Consistency is guaranteed even though the service can handle concurrent requests.
The developer does not have access to explicit database calls.
I don’t know if the interface is generic enough for actually building something very useful without fighting the design, but I hope that it will be simple and useful. It should support anyone who quickly wants to build a backend for turn based games, a game lobby, some kind of collaboration tool or a chat app. Since you code the request handler in Lua it’s easy to share code between the picotron app and the server which should be useful for some games.
The network interface is built to match picotron’s current fetch() behavior (GET with query parameters).
The interface
The two objects that are given as arguments and then returned modified are:
- Context. This can be used as a game session, or a game lobby room or chat channel. Something where different clients share information with each other.
- User. This represents the client. This allows the developer to manage authentication or storing information that needs to be transferred between different contexts.
To support these parameters there are two special query parameter:
- context = the string id of the context
- user = the string id of the user
These are available to the service like normal query parameters, but they are also used to read from the database. So for each combination of projectId and contextId there can be an object in the database.
The server is probably very buggy at the moment. I’d really like if someone wanted to try it out and build something. I want to at least see if one person can make it work for them before letting more people hurt themselves, I'm expecting to fix a couple of sharp edges.
The developer experience and debugging functionality is very basic so far. I haven’t built a front end. So far the system only supports two things:
- Accepting requests and running the Lua script
- There’s an endpoint where people can upload new versions of the Lua script to a project if they have the project’s secret token:
curl -X POST "http://whereitsat:3000/api/projects/chat/uploadScript" \ -H "Authorization: Bearer KH3XtSnWdCZB8iJnXnQmRjwcM0cv6OmtRteZ8z5w53Y1SAYK" \ -H "Content-Type: application/octet-stream" \ --data-binary "@chatserver.lua" |
Other than that I’ll initially need to manage everything else manually.
If someone wants to try it out, please let me know what your service should be called (that’s the beginning of the path, "chat" in the examples above), and your email address (to [email protected]) so I can send you a project token allowing you to upload your script.
[Please log in to post a comment]