-- Leo's gemini proxy

-- Connecting to ainent.xyz:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini; charset=utf-8; lang=en

smolver development log, part 2


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:


2022-01-12-smolver-development-log.gmi


Depending on how long this series becomes, I may end up creating a dedicated page for them all.


Alpha 2


Overview


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.


Details


Requests


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.


Responses


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.


Logging


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?).


Routing


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 :)


`main.swift` (pre-existing, but now much cleaner)


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


Conclusion


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