Skip to content

Commit ba1df29

Browse files
authored
Add solution for Challenge 8 by aruncs (#1894)
Auto-merged after 2 days with all checks passing. PR: #1894 Author: @aruncs
1 parent 6c8f735 commit ba1df29

1 file changed

Lines changed: 149 additions & 0 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
// Package challenge8 contains the solution for Challenge 8: Chat Server with Channels.
2+
package challenge8
3+
4+
import (
5+
"errors"
6+
"sync"
7+
// Add any other necessary imports
8+
)
9+
10+
type Message struct {
11+
Sender string
12+
Receiver string
13+
Message string
14+
}
15+
16+
// Client represents a connected chat client
17+
type Client struct {
18+
// TODO: Implement this struct
19+
// Hint: username, message channel, mutex, disconnected flag
20+
username string
21+
outChannel chan Message
22+
inChannel chan Message
23+
connected bool
24+
}
25+
26+
// Send sends a message to the client
27+
func (c *Client) Send(message string) {
28+
// TODO: Implement this method
29+
// Hint: thread-safe, non-blocking send
30+
31+
}
32+
33+
// Receive returns the next message for the client (blocking)
34+
func (c *Client) Receive() string {
35+
// TODO: Implement this method
36+
// Hint: read from channel, handle closed channel
37+
message := <-c.inChannel
38+
return message.Message
39+
}
40+
41+
// ChatServer manages client connections and message routing
42+
type ChatServer struct {
43+
// TODO: Implement this struct
44+
// Hint: clients map, mutex
45+
mu sync.RWMutex
46+
clients map[string]*Client
47+
}
48+
49+
// NewChatServer creates a new chat server instance
50+
func NewChatServer() *ChatServer {
51+
// TODO: Implement this function
52+
return &ChatServer{
53+
clients: make(map[string]*Client, 10),
54+
}
55+
}
56+
57+
// Connect adds a new client to the chat server
58+
func (s *ChatServer) Connect(username string) (*Client, error) {
59+
// TODO: Implement this method
60+
// Hint: check username, create client, add to map
61+
s.mu.Lock()
62+
defer s.mu.Unlock()
63+
if s.isUsernameExists(username) {
64+
return nil, ErrUsernameAlreadyTaken
65+
}
66+
67+
client := &Client{
68+
username: username,
69+
inChannel: make(chan Message, 10),
70+
outChannel: make(chan Message, 10),
71+
connected: true,
72+
}
73+
74+
s.clients[username] = client
75+
76+
return client, nil
77+
}
78+
79+
// Disconnect removes a client from the chat server
80+
func (s *ChatServer) Disconnect(client *Client) {
81+
// TODO: Implement this method
82+
// Hint: remove from map, close channels
83+
s.mu.Lock()
84+
defer s.mu.Unlock()
85+
86+
delete(s.clients, client.username)
87+
close(client.inChannel)
88+
close(client.outChannel)
89+
90+
client.connected = false
91+
}
92+
93+
// Broadcast sends a message to all connected clients
94+
func (s *ChatServer) Broadcast(sender *Client, message string) {
95+
// TODO: Implement this method
96+
// Hint: format message, send to all clients
97+
s.mu.RLock()
98+
defer s.mu.RUnlock()
99+
100+
for _, receiver := range s.clients {
101+
if receiver.username == sender.username {
102+
continue
103+
}
104+
receiver.inChannel <- Message{
105+
Sender: sender.username,
106+
Receiver: receiver.username,
107+
Message: message,
108+
}
109+
}
110+
111+
}
112+
113+
// PrivateMessage sends a message to a specific client
114+
func (s *ChatServer) PrivateMessage(sender *Client, recipient string, message string) error {
115+
// TODO: Implement this method
116+
// Hint: find recipient, check errors, send message
117+
s.mu.RLock()
118+
defer s.mu.RUnlock()
119+
120+
if !sender.connected {
121+
return ErrClientDisconnected
122+
}
123+
124+
receiver, exists := s.clients[recipient]
125+
126+
if !exists {
127+
return ErrRecipientNotFound
128+
}
129+
130+
receiver.inChannel <- Message{
131+
Sender: sender.username,
132+
Receiver: recipient,
133+
Message: message,
134+
}
135+
return nil
136+
}
137+
138+
func (s *ChatServer) isUsernameExists(username string) bool {
139+
_, exists := s.clients[username]
140+
return exists
141+
}
142+
143+
// Common errors that can be returned by the Chat Server
144+
var (
145+
ErrUsernameAlreadyTaken = errors.New("username already taken")
146+
ErrRecipientNotFound = errors.New("recipient not found")
147+
ErrClientDisconnected = errors.New("client disconnected")
148+
// Add more error types as needed
149+
)

0 commit comments

Comments
 (0)