git.fiddlerwoaroof.com
Browse code

feat: gemini client

Ed Langley authored on 01/09/2020 02:30:43
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,62 @@
1
+(defpackage :gemini.client
2
+  (:use :cl))
3
+(in-package :gemini.client)
4
+
5
+(defun ssl-connection (host port)
6
+  (flexi-streams:make-flexi-stream
7
+   (comm:open-tcp-stream host port :ssl-ctx t)
8
+   :external-format :utf-8))
9
+
10
+(defun crlf (s)
11
+  (princ #\return s)
12
+  (princ #\newline s))
13
+
14
+(defun request (uri s)
15
+  (puri:render-uri uri s)
16
+  (crlf s))
17
+
18
+(fw.lu:defclass+ link ()
19
+  ((url :initarg :url :reader url)
20
+   (text :initarg :text :reader text))))
21
+(defmethod print-object ((it link) s)
22
+  (print-unreadable-object (it s :type t :identity t)
23
+    (format s "target: ")
24
+    (puri:render-uri (url it) s))
25
+
26
+(defun parse-link (base-uri line)
27
+  (let* ((raw (subseq line 2))
28
+         (raw (serapeum:trim-whitespace raw))
29
+         (split (split-sequence:split-sequence-if #'serapeum:whitespacep raw)))
30
+    (destructuring-bind (first . rest) split
31
+      (link (puri:merge-uris (puri:uri first)
32
+                             base-uri)
33
+            (when rest (car rest))))))
34
+
35
+(defun gemini (uri s)
36
+  (let* ((uri (puri:uri uri))
37
+         (buffer (make-string 1024 :element-type 'character)))
38
+    (with-open-stream (conn (ssl-connection (puri:uri-host uri) 1965))
39
+      (request uri conn)
40
+      (finish-output conn)
41
+      (loop for read = (read-line buffer conn)
42
+            while (= read (length buffer))
43
+            do (write-sequence buffer s)
44
+            finally (write-sequence buffer conn :end read))
45
+      uri)))
46
+
47
+(defun gemini-byline (uri s)
48
+  (let* ((uri (puri:uri uri))
49
+         (links ()))
50
+    (with-open-stream (conn (ssl-connection (puri:uri-host uri) 1965))
51
+      (request uri conn)
52
+      (finish-output conn)
53
+      (loop with preformatted = nil
54
+            for read = (read-line conn nil)
55
+            while read
56
+            do
57
+            (write-sequence read s)
58
+            (terpri s)
59
+            when (equal read "```") do (setf preformatted (not preformatted))
60
+            when (and (not preformatted) (> (length read) 2) (equal (subseq read 0 2) "=>"))
61
+            do (push (parse-link uri read) links))
62
+      (values uri links))))
0 63
\ No newline at end of file