-- Leo's gemini proxy
-- Connecting to ainent.xyz:1965...
-- Connected
-- Sending request
-- Meta line: 20 text/gemini; charset=utf-8; lang=en
This is the second in a planned series of posts where I'll share my experience writing smolver, my Gemini server software, written in Swift.
You can find the previous iteration here:
Depending on how long this series becomes, I may end up creating a dedicated page for them all.
Last time, I noted how I was just getting started on the alpha 2 build. I just finished that build up last night, and it was a lot of fun. It has the same (barebones) feature parity as alpha 1, only this is scalable and not throwaway code. Consequently, I have removed the `#Warning` section from the main `README`.
For full implementation details on this release, see the annotation on the v0.0.10 tag. I plan to use semantic versioning once it is ready for v1.0.0, but until then, I'm generally following this approach to versioning:
Alpha releases will be tagged as v0.0.x, where x is for any changes whatsoever
Beta releases will be tagged as v0.x.y, where y is for bug fixes and refactorings
Until it reaches v1.0.0, do not expect any API or runtime stability. It does work in my use cases, but in the mean time, I have the following note in the `README`:
>smolver is alpha-quality software. Ergo, I will not be accepting merge requests at this time. I'll open those up once I am more satisfied with the progress and the architecture.
>
>The installation and usage instructions are ***aspirational***. At this point in the life cycle, if you want to use this, read the code.
Internally, what I ended up going with was just a few `struct`s (a value type in the Swift programming language) to encapsulate:
Incoming requests
Outgoing responses
Logging utility
A routing mechanism to find the right file after the request has been validated
As for the latter, I have, for now, called this `App`, but I may end up renaming that because it just seems wrong. An 'app' structure sounds, to me, like something that encapsulates the starting point of the application, whereas this is more for routing. Good enough for now, but maybe `Router` would be a better name?
As they say, naming is 1 of the 2 hardest things in computer science :P.
My `Request` `struct` is far from perfect. I'm not satisfied with the huge initializer which does all the work of validating an incoming request string. The logic itself is pretty simple, but just needs some helper methods.
For responses, I am much more satisfied at this point with my `Response` `struct`. I can see this growing as I start adding support for *every* Gemini response status code, but for now, it's still in a nice sweet spot. Right now I only have code for the following response codes:
10
20
30
40
50
60
Note that even though I have code for these, implemented as a basic `enum`, the entirety of the server software will not actually return all of these quite yet. I'll get to that in just a bit.
This is certainly enough to cover the basics, but my endgame is full compatibility Gemini's specification, so a refactor is in the future.
This is nothing more than a thin wrapper around Swift's standard `print` function, and will prefix the message with a timestamp and a string signifying the log level:
DEBUG
ERROR
INFO
WARN
DEBUG messages only actually log for debug builds, not release. In layman's terms, that just means that the system that lets you view this post won't ever actually log those; it will only do it if you run a test build.
At some point, I'd like to be able to log these to a file(s), but for now they just go to stdout (standard system output, I think is the full official name?).
As mentioned above, all the status codes I listed will not yet actually be used, despite the existing `enum` `case`s. Possible return values for the current production version will be:
20
30
50
The current implementation also only supports `.gmi` files; no other mime type will be returned, not even `.gemini`, which is technically part of the spec, but I just haven't gotten that far. Baby steps :)
For non-GUI (Graphical User Interface, for any less technical readers out there), applications, `main.swift` is the entry point for an executable Swift package.
All this file does for now is:
Points to the configuration directory, currently only looking for posts and TLS files
Creates a socket server
Forwards any requests to the aforementioned `App` `struct`
Performs some basic logging when the socket server calls the appropriate callbacks
Starts the socket server
This codebase still needs a lot of love, but it is coming along quite nicely, and has enabled me to have a nice creative/artistic outlet that I have never had, at least not seriously, before. I've tried blogging in the past but never really stuck with it. Perhaps the speed and arguably low-techness of Gemini is keeping my interest; perhaps it's writing and maintaining the full server stack; perhaps I just didn't like the bloated Wordpress software I've tried in the past; perhaps it is all 3! Regardless, I plan to continue glogging (gemlogging? what's the right verb here? do we have a convention for that in Geminispace? but I digress).
The artistic outlet comment above might warrant its own post in the future?
If you made it this far, thank you for reading.
- ainent
-- Response ended
-- Page fetched on Tue May 21 18:22:08 2024