init commit
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
;;; TCP Chat Client — connects to the TCP chat server
|
||||
;;;
|
||||
;;; Usage:
|
||||
;;; mix clje.run --no-halt examples/tcp_chat_client.clje -- <username>
|
||||
;;;
|
||||
;;; The server must be running first:
|
||||
;;; mix clje.run --no-halt examples/tcp_chat_server.clje
|
||||
;;;
|
||||
;;; Commands:
|
||||
;;; Type a message and press Enter to send
|
||||
;;; /who — list online users
|
||||
;;; /quit — disconnect and exit
|
||||
|
||||
(ns TcpChatClient
|
||||
(:require [clje.core :refer :all]
|
||||
[IO] [String] [System] [erlang] [gen_tcp]))
|
||||
|
||||
;; ── Receiver process ──────────────────────────────────────────────
|
||||
;; Listens for TCP messages from the server and prints them.
|
||||
|
||||
(defn receiver [socket parent]
|
||||
(receive
|
||||
[:tcp _sock data]
|
||||
(let [line (String/trim data)]
|
||||
(cond
|
||||
(String/starts-with? line "MSG:")
|
||||
(let [rest (String/slice line 4 (String/length line))
|
||||
parts (String/split rest ":" (list #el[:parts 2]))
|
||||
from (hd parts)
|
||||
text (hd (tl parts))]
|
||||
(IO/puts (str from "> " text))
|
||||
(TcpChatClient/receiver socket parent))
|
||||
|
||||
(String/starts-with? line "SYS:")
|
||||
(do
|
||||
(IO/puts (str "* " (String/slice line 4 (String/length line))))
|
||||
(TcpChatClient/receiver socket parent))
|
||||
|
||||
(String/starts-with? line "JOIN:")
|
||||
(do
|
||||
(IO/puts (str "* " (String/slice line 5 (String/length line)) " joined"))
|
||||
(TcpChatClient/receiver socket parent))
|
||||
|
||||
(String/starts-with? line "QUIT:")
|
||||
(do
|
||||
(IO/puts (str "* " (String/slice line 5 (String/length line)) " left"))
|
||||
(TcpChatClient/receiver socket parent))
|
||||
|
||||
:else
|
||||
(do
|
||||
(IO/puts line)
|
||||
(TcpChatClient/receiver socket parent))))
|
||||
|
||||
[:tcp_closed _sock]
|
||||
(do
|
||||
(IO/puts "* Connection closed by server.")
|
||||
(System/halt 0))
|
||||
|
||||
[:tcp_error _sock _reason]
|
||||
(do
|
||||
(IO/puts "* Connection error.")
|
||||
(System/halt 1))))
|
||||
|
||||
;; ── Input loop ────────────────────────────────────────────────────
|
||||
;; Reads from stdin and sends to the server.
|
||||
|
||||
(defn send-line [socket line]
|
||||
(gen_tcp/send socket line))
|
||||
|
||||
(defn input-loop [socket]
|
||||
(let [line (IO/gets "")]
|
||||
(cond
|
||||
(== line :eof)
|
||||
(do
|
||||
(TcpChatClient/send-line socket "QUIT\n")
|
||||
(gen_tcp/close socket)
|
||||
(System/halt 0))
|
||||
|
||||
:else
|
||||
(let [trimmed (String/trim line)]
|
||||
(cond
|
||||
(== trimmed "/quit")
|
||||
(do
|
||||
(TcpChatClient/send-line socket "QUIT\n")
|
||||
(gen_tcp/close socket)
|
||||
(IO/puts "Goodbye!")
|
||||
(System/halt 0))
|
||||
|
||||
(== trimmed "")
|
||||
(TcpChatClient/input-loop socket)
|
||||
|
||||
:else
|
||||
(do
|
||||
(TcpChatClient/send-line socket (str "MSG:" trimmed "\n"))
|
||||
(TcpChatClient/input-loop socket)))))))
|
||||
|
||||
;; ── Connect ───────────────────────────────────────────────────────
|
||||
|
||||
(defn start [username]
|
||||
(case (gen_tcp/connect (erlang/binary-to-list "127.0.0.1") 4040
|
||||
(list :binary #el[:active true] #el[:packet :line]))
|
||||
[:ok socket]
|
||||
(do
|
||||
;; Send JOIN
|
||||
(TcpChatClient/send-line socket (str "JOIN:" username "\n"))
|
||||
|
||||
;; Spawn receiver and hand it the socket
|
||||
(let [me *self*
|
||||
recv-pid (spawn (fn [] (TcpChatClient/receiver socket me)))]
|
||||
(gen_tcp/controlling-process socket recv-pid)
|
||||
|
||||
;; Run input loop in the main process
|
||||
(IO/puts (str "Connected as " username ". Type a message or /quit to exit."))
|
||||
(TcpChatClient/input-loop socket)))
|
||||
|
||||
[:error reason]
|
||||
(do
|
||||
(IO/puts (str "Could not connect: " reason))
|
||||
(IO/puts "Is the server running? Start it with:")
|
||||
(IO/puts " mix clje.run --no-halt examples/tcp_chat_server.clje")
|
||||
(System/halt 1))))
|
||||
|
||||
;; ── Entry point ─────────────────────────────────────────────────────
|
||||
|
||||
(let [args (System/argv)]
|
||||
(if (== (count args) 0)
|
||||
(do
|
||||
(IO/puts "Usage: mix clje.run --no-halt examples/tcp_chat_client.clje -- <username>")
|
||||
(System/halt 1))
|
||||
(TcpChatClient/start (hd args))))
|
||||
Reference in New Issue
Block a user