~ajk/plant-control

ref: b76f8165477e0c21ed7b7117aba04791a67320cc plant-control/genera/redis.lisp -rw-r--r-- 2.3 KiB
b76f8165 — Andrew Kay Initial commit 3 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
;;; -*- Mode: LISP; Syntax: Common-Lisp; Package: PLANT-CONTROL; -*-
;;;
;;; NOTES
;;; -----
;;; * This client uses the "inline command" format for requests for simplicity of
;;;   implementation - this should be replaced with the real Redis protocol for
;;;   requests however given only GET and MGET are implemented this is not a problem
;;;   for now.
;;;
;;; * UNIX stream translation is used to ensure that <CR><LF> is not converted into
;;;   a single character as with ASCII translation as this causes the STRING-IN method
;;;   to fail as the length does not match.

(defun parse-response (response)
  (let ((type (char response 0))
        (data (subseq response 1)))
    (case type (#\+ (values :simple-string data))
               (#\- (values :error data))
               (#\: (values :integer data))
               (#\$ (values :bulk-string data))
               (#\* (values :array data))
               (otherwise (error "Unknown type")))))

(defun read-response (stream)
  (let ((response (read-line stream)))
    (multiple-value-bind (type data) (parse-response response)
      (case type (:simple-string data)
                 (:error (error data))
                 (:integer (parse-integer data))
                 (:bulk-string (read-bulk-string stream (parse-integer data)))
                 (:array (read-array stream (parse-integer data)))))))

(defun read-bulk-string (stream length)
  (when (eq -1 length) (return-from read-bulk-string nil))
  (let ((bulk-string (make-array length :element-type 'character)))
    (send stream ':string-in "Unexpected EOF" bulk-string 0 length)
    (read-char stream) (read-char stream)
    bulk-string))

(defun read-array (stream length)
  (when (eq -1 length) (return-from read-array nil))
  (loop repeat length collect (read-response stream)))

;;

(tcp:add-tcp-port-for-protocol :redis 6379)

(net:define-protocol :redis (:redis :byte-stream)
  (:invoke-with-stream-and-close ((stream :translation :unix :character t) request)
    (write-line request stream)
    (send stream ':force-output)
    (read-response stream)))

(defun redis-execute (host request)
  (let ((host (net:parse-host host)))
    (net:invoke-service-on-host :redis host request)))

(defun redis-get (host key)
  (redis-execute host (format nil "GET ~a" key)))

(defun redis-mget (host keys)
  (redis-execute host (format nil "MGET ~{~a~^ ~}" keys)))