2008-02-02

My first look at Clojure: Source

Here's the resulting source code from my experimentation.
(import '(java.net BindException ServerSocket Socket)
        '(java.lang.reflect InvocationTargetException)
        '(java.util Date)
        '(java.io InputStream OutputStream)
        '(java.util.concurrent Executors))


;;; Utility functions

(defn current-time []
  (. (new Date) (toString)))

(defn byte-arr-from-string [str]
  (. str (getBytes)))

(defn test-byte-array-from-string
  ([]
   (test-byte-array-from-string (current-time)))
  ([str]
   (let [barr (byte-arr-from-string str)
         bseq (map (comp char (appl aget barr))
                   (range (alength barr)))
         chseq (map char str)]
     (and (== (alength barr)
              (count bseq)
              (count chseq))
          (nil? (first (filter false?
                               (map eql?
                                    bseq
                                    chseq))))))))

(defn string-from-byte-sequence [coll]
  (reduce strcat
          (map char coll)))


;;; Listener functions
;;; These control the server

(defn listener-new [port]
  (try (new ServerSocket port)
       (catch BindException except
              (println "Address is already in use."))))

(defn listener-wait [listener]
  (. listener (accept)))

(defn listener-close [listener]
  (. listener (close)))

(defn listener-send [lsocket] 
  (.. lsocket
      (getOutputStream)
      (write (byte-arr-from-string (current-time))))
  (.. lsocket (getOutputStream) (close))
  lsocket)

(defn listener-run [listener port]
  (loop [socket nil]
    (if (. listener (isClosed))
      listener
      (do (when socket
            (. (listener-send socket) (close)))
          (recur (listener-wait listener))))))

(defn listener-run-in-background [port]
  (let [listener (listener-new port)
        exec (. Executors (newSingleThreadExecutor))
        run (appl listener-run listener port)]
    (when listener
      (. exec (submit run)))
    listener))

;;; Connection functions
;;; These control the client.

(defn connection-new
  ([port]
   (connection-new "127.0.0.1" port))
  ([address port]
   (try (doto (new Socket address port)
          (setSoTimeout 5000))
        (catch InvocationTargetException except
               (println (strcat "Could not connect to "
                                address
                                " on port "
                                port))))))

(defn connection-read [conn]
  (let [instream (. conn (getInputStream))
        reader (fn [] (try (. instream (read))
                           (catch InvocationTargetException except
                                  -1)))]
    (loop [bytes nil
           current-byte (reader)]
      (if (== current-byte -1)
        bytes
        (recur (concat bytes (list current-byte))
               (reader))))))

(defn connection-close [conn]
  (. conn (close)))

(defn connection-run [port]
  (let [conn (connection-new port)
        str (when conn
              (string-from-byte-sequence (connection-read conn)))]
    (when conn 
      (connection-close conn))
    str))

No comments:

Post a Comment