Skip to content

Commit 05a423d

Browse files
committed
Some error handling
1 parent 952af19 commit 05a423d

File tree

1 file changed

+34
-7
lines changed

1 file changed

+34
-7
lines changed

src/chat_server/core.clj

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,50 @@
66

77
(def clients (ref []))
88

9-
(defn write-line [client message]
9+
(defn write-line
10+
"Write a single message to a client, returning the client."
11+
[client message]
1012
(socket/write-line (:socket client) message)
1113
client)
1214

1315
(defn error
16+
"Write an error to a socket, returning nil."
1417
[socket message]
1518
(socket/write-line socket (str "ERROR: " message)))
1619

1720
(defn nick-exists?
21+
"Return truthy if a nick is already in use, otherwise nil."
1822
[nick]
1923
(let [nicks (map #(-> % deref :nick) @clients)]
2024
(some #{nick} nicks)))
2125

22-
(defn set-nick [client nick]
26+
(defn set-nick
27+
"Set the nick of an existing client. This function is transactional."
28+
[client nick]
2329
(dosync
2430
(if (nick-exists? nick)
2531
(error (:socket @client) "nick already exists")
2632
(send-off client assoc :nick nick))))
2733

28-
(defn send-message [client message]
34+
(defn send-message
35+
"Send a message to all clients but the originating one."
36+
[client message]
2937
(doseq [d-client @clients]
3038
(when-not (= client d-client)
3139
(send-off d-client write-line (str (:nick @client) ": " message)))))
3240

3341
(defn terminate-client!
42+
"Close the socket and remove the client from the list."
3443
[client]
35-
(socket/close-socket (:socket @client))
36-
(dosync
37-
(alter clients (partial remove #{client}))))
44+
(try
45+
(socket/close-socket (:socket @client))
46+
(dosync
47+
(alter clients (partial remove #{client})))
48+
(catch Throwable e
49+
(println (.getMessage e)))))
3850

3951
(defn listen-client
52+
"Listen for and dispatch incoming messages from a client."
4053
[client]
4154
(let [{:keys [socket nick channels] :or {channels []}} @client]
4255
(loop [line (socket/read-line socket)]
@@ -49,13 +62,27 @@
4962
(when-not (.isClosed socket)
5063
(recur (socket/read-line socket))))))
5164

65+
(defn handle-client-error
66+
"Handle a client error."
67+
[the-agent exception]
68+
(let [s (:socket @the-agent)
69+
msg (.getMessage exception)]
70+
(when-not (.isClosed s)
71+
(error s msg))
72+
(println msg)
73+
(terminate-client! the-agent)))
74+
5275
(defn new-client
76+
"Takes a freshly opened socket connection, creates a new client and
77+
calls the dispatcher."
5378
[s]
5479
(loop [line (socket/read-line s)]
5580
(if-let [[_ nick] (re-matches #"USER (.*)" line)]
5681
(if-let [client (dosync
5782
(when-not (nick-exists? nick)
58-
(let [client (agent {:socket s :nick nick :channels []})]
83+
(let [client (agent {:socket s :nick nick :channels []}
84+
:error-mode :continue
85+
:error-handler handle-client-error)]
5986
(alter clients conj client)
6087
client)))]
6188
(listen-client client)

0 commit comments

Comments
 (0)