Skip to content

Instantly share code, notes, and snippets.

@kqr
Last active August 29, 2015 14:11
Show Gist options
  • Save kqr/88780d6743fc6e80a5c1 to your computer and use it in GitHub Desktop.
Save kqr/88780d6743fc6e80a5c1 to your computer and use it in GitHub Desktop.
; A with-socket macro for a network application I began writing
; in Clojure. Since the application never got finished but I
; sometimes refer to this macro I put it here for posterity.
(defmacro with-socket
"The way to interact with a socket. Given a socket name and
ip + port, will connect to the server and run stmts in an
environment where the socket is connected. Always closes
the socket, even if exceptions happen.
The returned map consists of a :readln entry and a :writeln
entry, both of which work as the docstrings for readln and
writeln indicate."
[sock [ip port] & stmts]
(let [socket-obj (gensym 'socket)]
`(let [~socket-obj (Socket.)]
(try
(.setSoTimeout ~socket-obj 2000)
(.connect ~socket-obj (InetSocketAddress. ~ip ~port))
(let [~sock {:readln (partial readln (BufferedReader. (InputStreamReader. (.getInputStream ~socket-obj))))
:writeln (partial writeln (PrintWriter. (.getOutputStream ~socket-obj)))}]
~@stmts)
(finally (.close ~socket-obj))))))
(defn readln
"Reads a line from the BufferedReader, stripping \\r\\n. If
read is semi-blocking, this function returns nil when the
read times out."
[reader]
(try (.readLine reader)
(catch SocketTimeoutException e nil)))
(defn writeln
"Writes a line to the PrintWriter, appending \\n."
[writer msg]
(.println writer msg)
(.flush writer))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment