Commits

Alexander Dinu committed 2b8416f

initial commit

Comments (0)

Files changed (1)

+(module redis racket
+  (define redis-client%
+    (class object%
+
+      (init hostname port)
+
+      (define-struct connection (in out cust))
+      (define-struct exn:redis (message))
+
+      (define this-hostname hostname)
+      (define this-port port)
+      (define this-connection '())
+      (define this-cust '())
+
+      (super-new)
+
+      (define/public (connect!)
+        (set! this-cust (make-custodian))
+        (let-values ([(in out) (tcp-connect this-hostname this-port)])
+          (set! this-connection (make-connection in out this-cust))))
+
+      (define/public (disconnect!)
+        (with-handlers ([exn:fail:network? void])
+          (close-output-port (connection-out this-connection)))
+        (with-handlers ([exn:fail:network? void])
+          (close-input-port (connection-in this-connection))))
+
+      (define/public (send-command . commands)
+        (let ([out (connection-out this-connection)]
+              [in (connection-in this-connection)])
+          (fprintf out (format "*~a\r\n" (length commands)))
+          (fprintf out
+                   (foldr string-append ""
+                          (map (lambda (command)
+                                 (format "$~a\r\n~a\r\n"
+                                         (bytes-length
+                                          (string->bytes/utf-8 command))
+                                         command))
+                               (map (lambda (command)
+                                      (cond
+                                       [(symbol? command) (symbol->string command)]
+                                       [(number? command) (number->string command)]
+                                       [else command])) commands))))
+          (flush-output out)
+          (read-reply in)))
+
+      (define/private (read-reply in)
+        (match (read-bytes 1 in)
+               [#"+" (read-line in 'return-linefeed)]
+               [#"-" (read-line in 'return-linefeed)]
+               [#":" (string->number (read-line in 'return-linefeed))]
+               [#"$" (read-bulk-reply in)]
+               [#"*" (read-multi-bulk-reply in)]
+               [_ (raise (make-exn:redis (format "invalid character in reply: ~a"
+                                                 (read-byte in))))]))
+
+      (define/private (read-bulk-reply in)
+        (flush-output)
+        (let ([length (string->number (read-line in 'return-linefeed))])
+          (begin0 (read-bytes length in)
+            (read-line in 'return-linefeed))))
+
+      (define/private (read-multi-bulk-reply in)
+        (let ([length (string->number (read-line in 'return-linefeed))])
+          (flush-output)
+          (build-list length (lambda (_) (read-reply in))))))))