Login
cl-remigemini
Login

CL-RemiGemini

CL-RemiGemini is a small and lightweight library for interfacing with the Gemini Protocol using Common Lisp. It includes classes that aid in the implementation of clients and servers that can handle multiple concurrent connections.

Wanna support Remilia? Buy me a coffee on Ko-Fi, or support me through Liberapay.

Buy Me a Coffee at ko-fi.com Donate using Liberapay

How do I get set up?

Most dependencies can be installed using QuickLisp (though this hasn't been tested). The exception is the CL-SDM library, which can be obtained here.

You will need Fossil installed to clone this repo.

Place this library (and the CL-SDM dependency) somewhere where ASDF can find them, then run this in your REPL:

(asdf:load-system :cl-remigemini)

Usage

There are a few examples in the root of the repository.

Example client:

(gemini:response-body-str (gemini:client-get "gemini://gemini.circumlunar.space/"))

Example server:

;; Simple server that listens on localhost.  If the user navigates to
;; /file then a binary file is served.  Otherwise, "Hello World" is
;; returned.
(defun run-server ()
  (let ((lparallel:*kernel* (lparallel:make-kernel 4)))
    (cl-remigemini:with-server (server '("127.0.0.1")
                                       "/path/to/key.pem"
                                       "/path/to/cert.pem")
        ;; This is the handler function.  This is called for each connection
        ;; request.
        #'(lambda (req)
            ;; If the request is for /file then serve a file.
            (if (string= (quri:uri-path (cl-remigemini:request-uri req)) "/file")
                ;; Open the file stream.
                (cl-remigemini:make-response :body (open #P"/path/to/some/file"
                                                         :direction :input
                                                         :element-type '(unsigned-byte 8)))

                ;; All other pages get this
                (cl-remigemini:with-output-to-success-response (out)
                  (format out "Hello, world!~%"))))

      ;; Wait for the server to finish.
      (loop while (cl-remigemini:server-listening-p server)
            for msg = (lparallel:receive-result (cl-remigemini:server-handler-chan server))
            when msg do (print msg)))))
            
(run-server)

Generating Gemtext:

(use-package :gemini)

(with-output-to-gemtext (t)
  (put-h1 "Hello, world!~%")

  (put-line "foo~%")

  (put-quote "Hello~%")
  (put-quote "World")

  (put-line "~%yep, ~a~%" "this is lisp")

  (put-quote "quoted")

  (put-line "")
  (put-list 1 2 3)

  (put-line "")
  (put-pre "this is
a
test"))

Development

Style info

I use a slightly unorthodox style for my code. Aside from these differences, please use normal Lisp formatting.

How do I contribute?

  1. Go to https://chiselapp.com/user/MistressRemilia/repository/cl-remigemini and clone the Fossil repository.
  2. Create a new branch for your feature.
  3. Push locally to the new branch.
  4. Create a bundle with Fossil that contains your changes.
  5. Get in contact with me.

Contributors

Links and Licenses

CL-RemiGemini is under the GNU Affero General Public License version 3.