#gemini #client #command-line #actor #client-certificate #experimental #fun

bin+lib trotter

Trotter 🎠 is an experimental crate that aims to make writing Gemini clients fun and easy

11 releases (2 stable)

1.0.1 Mar 31, 2024
0.6.0 Nov 21, 2023
0.5.2 Nov 18, 2023
0.4.0 Nov 16, 2023
0.1.0 Nov 11, 2023

#564 in Network programming

Download history 63/week @ 2024-02-26 21/week @ 2024-03-11 227/week @ 2024-03-25 156/week @ 2024-04-01 22/week @ 2024-04-08 209/week @ 2024-04-15

614 downloads per month
Used in 3 crates (2 directly)

GPL-3.0-only

40KB
820 lines

🎠 Trotter

Trotter is an experimental crate that aims to make interacting with gemini servers fun and easy.

This crate comes with the trot command-line program that exposes most of its functionality. Install it with the command cargo install --features cli trotter.

There's also Fluffer, a crate for writing gemini server apps.

😊 Requests

Trotter seeks to be a feature-complete gemini client library, while also being easy to use.

Trot

If you're only here to send a quick request, refer to the ergonomic trot and trot_in methods.

#[tokio::main]
async fn main() {
    trotter::trot("geminiprotocol.net") // gemini:// prefix and root slash can be elided
        .await
        .unwrap();

    trotter::trot_in("localhost/input", "notice me!")
        .await
        .unwrap();
}

Actors

For more-detailed requests, you can use an Actor.

You can use the builder pattern to easily attach a user agent and client certificate to the actor.

Once you've built an Actor, you can call Actor::get to send a request with it.

use trotter::{Actor, UserAgent};

#[tokio::main]
async fn main() {
    let owo = Actor::default()
        .user_agent(UserAgent::Indexer)
        .cert_file("id/owo.crt")
        .key_file("id/owo.key");
        
    owo.get("localhost")
        .await
        .unwrap();
}

🤖 User-agents

Did you know there's a version of the robots.txt standard for gemini? (robots.txt for Gemini)

Trotter has robots functionality built-in. Once you set your user-agent, you will receive a RobotDenied error if you try to access a page you are disallowed from.

I strongly suggest you do this if you're using Trotter for a project that depends on other peoples' content.

🌕 Titan

Titan is a sister-protocol to gemini that allows clients to upload files. (read more)

To use titan, construct a Titan object, and pass it to the Actor::upload method.

use trotter::{Actor, Titan};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let g = Actor::default()
        .upload(
            "titan://localhost/",
            Titan {
                content:  "Example content :DDDDDDDDDDDDDDDDDDDD".into(),
                mimetype: "text/plain".into(),
                token:    None,
            },
        )
        .await?
        .gemtext()?;
    println!("{g}");

    Ok(())
}

🎁 Responses

Once you receive a structured Response, you can either weed through it yourself, or rely on the helper functions it implements to preform common operations.

📖 Parsing

Trotter also provides tools for parsing gemtext.

use trotter::parse::Gemtext;

fn main() {
    let txt = "# 💎
## Is
### So
> effing
* dope
man
=> /path/to/somewhere i can take u there
``` alt text goes here
Here's a table
| The | Best |
|-----|------|
| 😘  | 😪   |
```";

    let gemtext = Gemtext::parse(txt);

    println!("{gemtext:#?}");
}

Tips

Certificates

If you have access to a posix shell with openssl installed, you can define the following functions to easily generate and inspect x509 certificates.

certgen() { [ -f "${1:?usage: certgen [domain]}.key" ] || [ -f "$1.crt" ] || ( openssl req -new -subj "/CN=$1" -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -days 3650 -nodes -out "$1.crt" -keyout "$1.key" && printf '📜 Cert generated\n' ) ;}
certinfo(){ openssl x509 -noout -text < "${1:?usage: certinfo [file]}" ;}

Todo

For now, I want this to be a helpful tool for automating gemini requests. But ultimately, I would like for it to be robust enough to write a complete client with.

  • Write response to file
  • Get response as gemtext
  • robots.txt support
  • Custom errors
  • Cli binary 👀
  • Server certificates
  • Tofu store directory
  • Byte read/write timeout

Dependencies

~6–17MB
~238K SLoC