Skip to content

alexdma/chaykin

Repository files navigation

Chaykin: Linked Data over the Small Web

A Linked Data server in Rust that makes the Semantic Web available over the Small Web (or "smolweb") through a variety of protocols:

More on this in docs/about.md.

Features

  • Multi-Protocol Server: Custom Tokio+Rustls implementation handling Gemini and Titan natively over TLS, alongside plaintext Spartan and Nex/NPS TCP listeners. Enabled protocols and ports can be configured.
  • Linked Data Store: Consumes RDF data in Turtle via rio_turtle and holds them into an in-memory store.
  • Gemtext Mapping: A proposed serialization of RDF to the hypertext format of Gemini, offering a recursively browsable knowledge graph. A condensed syntax, which groups predicates by property, is also supported. The specification is documented at docs/rdf_gemtext_spec.md.
  • External Proxy: Acts as a browser for all the Linked Open Data out there.
    • Encoded URLs in the request path are fetched via reqwest.
    • Accept: text/turtle is used for Content Negotiation.
    • Fetched RDF is parsed and rendered.
    • Links to other external resources are re-encoded to point back to the proxy.
    • You can provide a custom TLS certificate via the --cert flag.

Setup & Running

Pretty standard stuff:

  1. Dependencies: Mainly tokio, rustls, rio_turtle, rio_api, and reqwest.

  2. Build:

    cd server
    cargo build

    Or, if you want to build it as a Docker image:

    docker build -t chaykin .

    (the above will build an image with a self-signed certificate)

  3. Run: Either launch the chaykin executable in server/target, or

    cargo run

    The server listens on 127.0.0.1:1965 by default (for Gemini/Titan). Go there with your favourite Gemini client, like Lagrange (simple, stylish, with support for Spartan but not Titan) or Alhena (not as fancy, but flexible and multi-protocol).

    To run it in a Docker container (mapping the Spartan port to one that doesn't require a super user):

    docker run -p 1965:1965 -p 3300:300 -p 1900:1900 -p 1915:1915 chaykin

Configuration

You can configure the server using command-line arguments:

cargo run -- --help

Arguments:

  • --host: IP address to bind to (default: 127.0.0.1)
  • --gemini-port: Port number for Gemini/Titan to bind to (default: 1965)
  • --spartan-port: Port number for Spartan (default: 300)
  • --nex-port: Port number for Nex (default: 1900)
  • --nps-port: Port number for NPS (default: 1915)
  • --protocols: Comma-separated list of enabled protocols. Run cargo run -- list-protocols to see the list (default: all)
  • --disable-titan: Disable Titan (assumes Gemini is enabled)
  • --disable-nps: Disable NPS (assumes Nex is enabled)
  • --file: Path to an initial RDF data file (default: sample_data.ttl)
  • --cert: Path to TLS certificate (PEM)
  • --key: Path to TLS private key (PEM)
  • --lang: Preferred language for language-tagged literals in Gemtext (e.g. en, fr, de)

If no certificate/key is provided, a self-signed certificate is generated for development.

Usage & Verification

The homepage at localhost for each protocol provides helpful hints on where to go from there. To try each protocol straight away:

1. Gemini (Port 1965)

Fetch a local resource:

printf "gemini://localhost/me\r\n" | openssl s_client -connect 127.0.0.1:1965 -quiet

Proxy an external resource (e.g. Another World on Wikidata), which must be URL-encoded:

printf "gemini://localhost/http%3A%2F%2Fwww.wikidata.org%2Fentity%2FQ257469\r\n" | openssl s_client -connect 127.0.0.1:1965 -quiet

2. Titan (Port 1965, Gemini must be enabled)

Upload a URI to inspect via Titan payload:

{ printf "titan://localhost/;size=33;mime=text/plain\r\nhttp://www.wikidata.org/entity/Q257469"; sleep 1; } | openssl s_client -crlf -verify_quiet -connect localhost:1965

3. Spartan (Port 300)

NOTE: Binding to ports below 1024 (like 300) may require root privileges on Linux/Unix systems.

Connect and pass the target URI as the Spartan payload:

printf "localhost / 35\r\nhttp://www.wikidata.org/entity/Q257469" | nc localhost 300

4. Nex (Port 1900)

Input the URL-encoded path to get a raw text breakdown:

echo -e "/http%3A%2F%2Fwww.wikidata.org%2Fentity%2FQ257469\n" | nc localhost 1900

5. NPS (Port 1915, Nex must be enabled)

The following (taken from https://nightfall.city/nps/info/nps) opens a temporary file in your default editor (specified by the $EDITOR environment variable): enter your entity URI and save, and it will be sent to the NPS server.

T=`mktemp` && $EDITOR $T && echo "." >> $T && nc localhost 1915 < $T

TODO

Lots and lots, but mainly:

  • Move to RDF support via Sophia and access existing triple stores.
  • SPARQL API? Only if it can be implemented without compromising the basic principles of the Small Web.
  • Gemtext serialization improvements:
    • Support for quads, blank node expansion, RDF-star.
    • Context-sensitive links in Gemtext: make them spartan:// or gemini:// depending on the client request.
    • Where possible, add support for language-specific labels per client request (we don't have the luxury of an Accept-Language header here).
  • Not every Linked Data server offers Turtle: support negotiation of at least RDF/XML, too.
  • Investigate whether it's worth supporting good old Gopher, too.
  • Consider Chaykin extensions to existing Small Web servers in Rust, like Agate.

Rights

Copyright (c) 2023-2026 Alessandro Adamou.

Chaykin is licensed under either of:

at your option.

About

Linked Data over the "smolweb" cur-gen protocols: Gemini, Titan, Spartan, Nex, and NPS

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Contributors