Meta(
    title: "Agis 0.4 release",
    summary: Some("Agis is a multithreaded Spartan protocol server written in Rust with CGI and ScriptAlias support"),
    published: Some(Time(
        year: 2022,
        month: 11,
        day: 23,
        hour: 3,
        minute: 4,
        second: 0,
    )),
    tags: [
        "spartan",
        "rust",
        "software",
    ],
)
---
I release version 0.4 of Agis this evening. This release adds a number of new features as well as greater stability. Agis has been serving this capsule over the Spartan protocol for the past six months.

## Release notes
* Ability to override config file location on the command line
* Bind to optional second address to support ipv4 and ipv6 at the same time
* Handle percent encoded url's properly
* Fall back to stdout/stderr if logs cannot be opened for writing
* Make logging less verbose
* Share worker pool among both tcp listeners if bound to a second address
* Shut down worker pool cleanly rather than just exiting when termination signal is received
* Log startup and shutdown messages rather than printing to stdout

=> https://codeberg.org/jeang3nie/agis/releases/tag/v0.4.0

Binaries are available for the following platforms:
* x86_64 Linux GNU
* x86_64 Linux Musl
* x86_64 FreeBSD
* aarch64 Linux GNU

This has been a great learning project for me since it's inception. Rust provides some great networking and threading primitives in it's standard library and it's been nice to step away from the gui programming I do a lot of and work on something much more low level. It does, however, strain the brain sometimes when the compiler gets picky about eg. whether or not a certain type can be shared between threads. Indeed, I struggled with that initially when I attempted to add a requested feature - the ability to listen on both ipv4 and ipv6 addresses simultaneously. My original implementation required a separate thread pool for each address. This release wraps the thread pool in an `Arc<Mutex<_>>` wrapper, which can be cloned and sent into a new thread. Each listener runs in it's own thread, sharing the worker thread pool. I'm sure there are other ways of accomplishing the task.