Skip to content

pxp9/beam_chat

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BeamChat

A distributed chat system built to teach GenServers, OTP, and distributed Elixir.

Your Exercise

The file lib/beam_chat/server.ex contains a skeleton with all the function signatures, types, and detailed TODO comments — but no implementation.

Your task: implement the GenServer callbacks and helper functions so that the tests pass and the chat system works end-to-end.

When you're done, you can check your work against the solution branch:

git diff main..solution -- lib/beam_chat/server.ex

Architecture

  Terminal 1 (Server Node)         Terminal 2 (Client Node)         Terminal 3 (Client Node)
  ┌─────────────────────┐         ┌─────────────────────┐         ┌─────────────────────┐
  │                     │         │  BeamChat.TUI       │         │  BeamChat.TUI       │
  │  BeamChat.Server    │◄────────│  BeamChat.Client    │         │  BeamChat.Client    │
  │  (GenServer)        │────────►│  (GenServer)        │         │  (GenServer)        │
  │                     │         │                     │         │                     │
  │  - tracks clients   │◄────────┤                     │         │                     │
  │  - broadcasts msgs  │────────►│                     │         │                     │
  │  - keeps history    │         └─────────────────────┘         └─────────────────────┘
  │                     │                                                    ▲ │
  │                     │◄───────────────────────────────────────────────────┘ │
  │                     │─────────────────────────────────────────────────────►│
  └─────────────────────┘

Step-by-Step Guide

Step 1: Read the existing code

Before writing anything, read these files to understand how the system works:

  1. lib/beam_chat/server.ex — Read the Client API functions (already done). They tell you exactly what messages each callback will receive.
  2. lib/beam_chat/client.ex — See how the client joins, sends messages, and handles incoming {:new_message, msg} tuples.
  3. test/beam_chat_test.exs — The tests define the expected behavior.

Step 2: Implement the helpers first

Start with the private functions at the bottom of server.ex:

  1. build_message/2 — Build a %{user: ..., text: ..., timestamp: ...} map
  2. find_client/2 — Search a MapSet for a tuple matching a PID
  3. already_joined?/2 — Check if a PID is in the clients MapSet
  4. broadcast/2 — Send a message to every client PID

Step 3: Implement the callbacks

Work through these in order:

  1. init/1 — Set up the initial state
  2. handle_call(:get_history, ...) — Return the history (easiest callback)
  3. handle_call({:join, username}, ...) — Join logic with monitoring
  4. handle_cast({:send_message, ...}, ...) — Message relay
  5. handle_cast({:leave, ...}, ...) — Graceful disconnect
  6. handle_info({:DOWN, ...}, ...) — Crash detection

Step 4: Run the tests

mix test

All 6 tests should pass.

Step 5: Try it for real

# Terminal 1 — Server
./start_server.sh

# Terminal 2 — Alice
./start_client.sh Alice

# Terminal 3 — Bob
./start_client.sh Bob

Key Concepts

handle_call vs handle_cast vs handle_info

Callback Triggered by Returns Use when
handle_call GenServer.call/2 {:reply, value, state} You need a response
handle_cast GenServer.cast/2 {:noreply, state} Fire-and-forget
handle_info send/2 or system {:noreply, state} External/unexpected messages

Process Monitoring

ref = Process.monitor(pid)    # Start watching a process
Process.demonitor(ref, [:flush])  # Stop watching
# If pid dies -> you receive {:DOWN, ref, :process, pid, reason}

File Guide

File Status What it teaches
lib/beam_chat/server.ex TODO Core GenServer: state, call, cast, info, monitors
lib/beam_chat/client.ex Done GenServer as a client: connecting, receiving pushes
lib/beam_chat/tui.ex Done I/O, ANSI codes, separating UI from logic
lib/beam_chat/application.ex Done OTP Application, supervision trees
lib/beam_chat.ex Done Entry point, distributed node connection
test/beam_chat_test.exs Done Testing GenServers with spawn + assert_receive

Bonus Exercises

Once you finish the server, try these extensions:

  1. Add /users command — Query the server for the list of connected usernames
  2. Add private messages — Implement /msg Bob Hey there! to send only to Bob
  3. Add a message limit — Only keep the last 100 messages in history
  4. Handle server crash — What happens to clients when the server dies? Add reconnect logic

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors