git.fiddlerwoaroof.com
gemini-client.lisp
7b4bc9b9
 (defpackage :gemini.client
   (:use :cl))
 (in-package :gemini.client)
 
 (defun ssl-connection (host port)
   (flexi-streams:make-flexi-stream
    (comm:open-tcp-stream host port :ssl-ctx t)
    :external-format :utf-8))
 
 (defun crlf (s)
   (princ #\return s)
   (princ #\newline s))
 
 (defun request (uri s)
   (puri:render-uri uri s)
   (crlf s))
 
 (fw.lu:defclass+ link ()
   ((url :initarg :url :reader url)
    (text :initarg :text :reader text))))
 (defmethod print-object ((it link) s)
   (print-unreadable-object (it s :type t :identity t)
     (format s "target: ")
     (puri:render-uri (url it) s))
 
 (defun parse-link (base-uri line)
   (let* ((raw (subseq line 2))
          (raw (serapeum:trim-whitespace raw))
          (split (split-sequence:split-sequence-if #'serapeum:whitespacep raw)))
     (destructuring-bind (first . rest) split
       (link (puri:merge-uris (puri:uri first)
                              base-uri)
             (when rest (car rest))))))
 
 (defun gemini (uri s)
   (let* ((uri (puri:uri uri))
          (buffer (make-string 1024 :element-type 'character)))
     (with-open-stream (conn (ssl-connection (puri:uri-host uri) 1965))
       (request uri conn)
       (finish-output conn)
0cf3cc2e
       (loop for read = (read-sequence buffer conn)
7b4bc9b9
             while (= read (length buffer))
             do (write-sequence buffer s)
             finally (write-sequence buffer conn :end read))
       uri)))
 
 (defun gemini-byline (uri s)
   (let* ((uri (puri:uri uri))
          (links ()))
     (with-open-stream (conn (ssl-connection (puri:uri-host uri) 1965))
       (request uri conn)
       (finish-output conn)
       (loop with preformatted = nil
             for read = (read-line conn nil)
             while read
             do
             (write-sequence read s)
             (terpri s)
             when (equal read "```") do (setf preformatted (not preformatted))
             when (and (not preformatted) (> (length read) 2) (equal (subseq read 0 2) "=>"))
             do (push (parse-link uri read) links))
0cf3cc2e
       (values uri links))))