Meta(
    title: "A Spartan to Gemini proxy server",
    summary: Some("I\'m writing a Spartan to Gemini proxy server, but it has me thinking"),
    published: Some(Time(
        year: 2022,
        month: 11,
        day: 30,
        hour: 1,
        minute: 16,
        second: 47,
    )),
    tags: [
        "spartan",
        "gemini",
        "software",
        "rust",
    ],
)
---
For a few days now I've been hacking in my spare time on another idea of mine. My own capsule has been happily running on Agate since it's inception and I've never had an issue with it. When I decided to bihost it on Spartan I wrote the Agis server and have been quite happy with it.
=> https://github.com/mbrubeck/agate Agate Gemini server
=> https://codeberg.org/jeang3nie/agis Agis Spartan server

I'm always looking for ways to run things more efficiently, and for fun new projects. Now, Agate is a great high performance server, but Agis uses significantly less memory at idle than Agate. The biggest difference I believe is that Agate is using the Tokio async runtime. Tokio is great. It's really high performance, and you can build monstrously high capacity web services with it. But that's just it. It's overkill. Instead of using async code everywhere and pulling in everything that Tokio requires, when I built Agis I did so with a simple threadpool model and four worker threads handling requests. This is configurable of course, but let's be honest and assume that for most of us four simultaneous requests is wishful thinking on Gemini. But let's stick with four worker threads vs the whole async runtime and check out the momory usage.
```
% pgrep agate
645
% pgrep agis 
14423
% sudo pmap 645 | tail -n 1; sudo pmap 14423 | tail -n 1
total kB         1156800    6644    9756    4332       0
total kB          410912    2556    1358     364       0
```
So yeah, we're looking at less than half the memory usage at idle. It definitely won't scale well compared with the async version but my opinion is that it really doesn't have to. There is plenty of performance with four worker threads and there's the added bonus of simpler code.

## The project
My first pass project is to create a simple reverse proxy server that just takes in gemini requests and forwards them to a Spartan server, then forwards the response back through Gemini. It's not fully cooked yet, but it's close. The library portion of the code knows how to handle each connection. It just needs the actual binary which will only have to get the config, start up the worker threads and begin listening for connections to forward to them.

Writing it has so far been pretty easy, especially considering how much code I already have available for reuse. I had already begun stripping the client code for various smolweb protocols out of GemView and putting them into a modular library crate called Bucky. Bucky is the first time I've used cargo workspaces, and this tweak makes it so that each protocol lives in it's own crate, with one crate of common code that they share. So the proxy server is able to just use the bucky-spartan crate to talk Spartan. So basically, I had to write a Gemini server, without the server having to care about how to get the data being requested. That's the job of the Spartan server. So the proxy server itself can be pretty dumb.

=> https://codeberg.org/jeang3nie/bucky Bucky smolweb client library

I think I'm going to finish it at least to the point where it's able to do what it was written for, but it's giving me other ideas in the meantime.

## Other idea #1
So I was thinking to myself, that while this is likely going to significantly reduce the memory usage of the overall stack, I could reclaim even more memory if I just had a single server which can speak both protocols to begin with. Agis would be a great start if I went this route. It already has virtual hosting, CGI and ScriptAlias support. For my use case I'm running the same static content on both Spartan and Gemini, which is even easier to handle than any type of dynamic pages.

## Other idea #2
The proxy could also be expanded to proxy Gopher content over Gemini. Since Bucky already has a Gopher client, this would mostly involve writing a converter that takes in a Gopher map and spits out Gemtext, and then putting it all together. I think that sort of program might have a wider audience than my original proxy idea, which was mainly for my own benefit.

## In the meantime
Right now those other ideas are pretty much just speculation. The proxy server might be ready in a couple more hours work, but I'm not sure when I'll get back to it. The code will be public and freely licensed once it's working, but until now it's sitting in a private repo on my own Gitea instance.
