init commit
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
;;; ChatRoom — process-based chat room using spawn/send/receive
|
||||
;;;
|
||||
;;; This is a single-VM demo showing BEAM concurrency primitives.
|
||||
;;; Run with: mix clje.run examples/chat_room.clje
|
||||
;;;
|
||||
;;; For a multi-terminal chat experience, see:
|
||||
;;; examples/tcp_chat_server.clje and examples/tcp_chat_client.clje
|
||||
|
||||
(ns ChatRoom
|
||||
(:require [clje.core :refer :all]
|
||||
[Enum] [IO] [Map] [Process] [String]))
|
||||
|
||||
;; ── Room loop ─────────────────────────────────────────────────────
|
||||
;; Manages members map of {username → pid} and broadcasts messages.
|
||||
|
||||
(defn run-loop [state]
|
||||
(receive
|
||||
[:join username pid]
|
||||
(let [members (assoc (:members state) username pid)]
|
||||
(send pid #el[:welcome username (count members)])
|
||||
;; Notify existing members
|
||||
(doseq [[_name member-pid] (:members state)]
|
||||
(send member-pid #el[:system (str username " joined the room")]))
|
||||
(recur (assoc state :members members)))
|
||||
|
||||
[:message from body] :guard [(is-binary body)]
|
||||
(do
|
||||
(doseq [[_name pid] (:members state)]
|
||||
(send pid #el[:chat from body]))
|
||||
(recur state))
|
||||
|
||||
[:leave username]
|
||||
(let [new-members (dissoc (:members state) username)]
|
||||
(doseq [[_name pid] new-members]
|
||||
(send pid #el[:system (str username " left the room")]))
|
||||
(recur (assoc state :members new-members)))
|
||||
|
||||
[:who reply-pid]
|
||||
(do
|
||||
(send reply-pid #el[:members (Map/keys (:members state))])
|
||||
(recur state))
|
||||
|
||||
:shutdown
|
||||
(do
|
||||
(doseq [[_name pid] (:members state)]
|
||||
(send pid :room-closed))
|
||||
:ok)
|
||||
|
||||
:after 5000
|
||||
(if (== (count (:members state)) 0)
|
||||
:empty-timeout
|
||||
(recur state))))
|
||||
|
||||
;; ── User listener ─────────────────────────────────────────────────
|
||||
;; Collects messages received by a user and prints them.
|
||||
|
||||
(defn listen [username messages]
|
||||
(receive
|
||||
[:welcome _name member-count]
|
||||
(do
|
||||
(println (str " [" username " sees: Welcome! " member-count " user(s) here]"))
|
||||
(ChatRoom/listen username messages))
|
||||
|
||||
[:chat from body]
|
||||
(do
|
||||
(println (str " [" username " sees: " from "> " body "]"))
|
||||
(ChatRoom/listen username (cons #el[from body] messages)))
|
||||
|
||||
[:system text]
|
||||
(do
|
||||
(println (str " [" username " sees: * " text "]"))
|
||||
(ChatRoom/listen username messages))
|
||||
|
||||
:room-closed
|
||||
(println (str " [" username " sees: room closed]"))
|
||||
|
||||
:dump
|
||||
messages
|
||||
|
||||
:after 2000
|
||||
(do
|
||||
(println (str " [" username " done listening]"))
|
||||
messages)))
|
||||
|
||||
;; ── Run the demo ────────────────────────────────────────────────────
|
||||
|
||||
(println "=== ChatRoom Demo ===\n")
|
||||
|
||||
;; Start the room
|
||||
(let [room (spawn (fn [] (ChatRoom/run-loop {:owner "system" :members {}})))
|
||||
alice-listener (spawn (fn [] (ChatRoom/listen "alice" (list))))
|
||||
bob-listener (spawn (fn [] (ChatRoom/listen "bob" (list))))
|
||||
carol-listener (spawn (fn [] (ChatRoom/listen "carol" (list))))]
|
||||
|
||||
;; Alice joins
|
||||
(println "Alice joins...")
|
||||
(send room #el[:join "alice" alice-listener])
|
||||
(Process/sleep 100)
|
||||
|
||||
;; Bob joins
|
||||
(println "\nBob joins...")
|
||||
(send room #el[:join "bob" bob-listener])
|
||||
(Process/sleep 100)
|
||||
|
||||
;; Alice sends a message
|
||||
(println "\nAlice sends a message...")
|
||||
(send room #el[:message "alice" "Hello everyone!"])
|
||||
(Process/sleep 100)
|
||||
|
||||
;; Carol joins
|
||||
(println "\nCarol joins...")
|
||||
(send room #el[:join "carol" carol-listener])
|
||||
(Process/sleep 100)
|
||||
|
||||
;; Bob sends a message
|
||||
(println "\nBob sends a message...")
|
||||
(send room #el[:message "bob" "Hey Alice! Welcome Carol!"])
|
||||
(Process/sleep 100)
|
||||
|
||||
;; Carol sends a message
|
||||
(println "\nCarol sends a message...")
|
||||
(send room #el[:message "carol" "Thanks Bob!"])
|
||||
(Process/sleep 100)
|
||||
|
||||
;; Check who's online
|
||||
(println "\nWho's online?")
|
||||
(send room #el[:who *self*])
|
||||
(receive
|
||||
[:members names]
|
||||
(println (str " Online: " (Enum/join names ", "))))
|
||||
|
||||
;; Bob leaves
|
||||
(println "\nBob leaves...")
|
||||
(send room #el[:leave "bob"])
|
||||
(Process/sleep 100)
|
||||
|
||||
;; Shutdown the room
|
||||
(println "\nShutting down room...")
|
||||
(send room :shutdown)
|
||||
(Process/sleep 200)
|
||||
|
||||
(println "\n=== Demo complete ==="))
|
||||
Reference in New Issue
Block a user