Skip to content

Add solution for Challenge 8 by aruncs#1894

Merged
github-actions[bot] merged 1 commit into
RezaSi:mainfrom
aruncs:challenge-8-aruncs
Jul 17, 2026
Merged

Add solution for Challenge 8 by aruncs#1894
github-actions[bot] merged 1 commit into
RezaSi:mainfrom
aruncs:challenge-8-aruncs

Conversation

@aruncs

@aruncs aruncs commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Challenge 8 Solution

Submitted by: @aruncs
Challenge: Challenge 8

Description

This PR contains my solution for Challenge 8.

Changes

  • Added solution file to challenge-8/submissions/aruncs/solution-template.go

Testing

  • Solution passes all test cases
  • Code follows Go best practices

Thank you for reviewing my submission! 🚀

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds a Go Challenge 8 chat server template with channel-based clients, synchronized connection management, broadcast and private message routing, and exported error values.

Changes

Chat server implementation

Layer / File(s) Summary
Client and message contracts
challenge-8/submissions/aruncs/solution-template.go
Defines Message and channel-backed Client types; Receive reads inbound messages while Send remains a TODO.
Server initialization and connection lifecycle
challenge-8/submissions/aruncs/solution-template.go
Initializes the client registry, enforces unique usernames, tracks connection state, and closes channels on disconnect.
Broadcast and private routing
challenge-8/submissions/aruncs/solution-template.go
Delivers broadcast messages to other connected clients and private messages to named recipients, returning exported routing errors when validation fails.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Sender
  participant ChatServer
  participant Recipient
  Sender->>ChatServer: Broadcast or PrivateMessage
  ChatServer->>Recipient: Send Message to inChannel
  Recipient->>Recipient: Receive message
Loading

Possibly related PRs

Poem

A bunny hops through channels bright,
Sending messages left and right.
Names stay unique, connections glow,
Private whispers safely flow.
Broadcast carrots fill the air—
Chat server magic everywhere!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding a Challenge 8 solution by aruncs.
Description check ✅ Passed The description is directly related to the submitted Challenge 8 solution and its implementation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
challenge-8/submissions/aruncs/solution-template.go (2)

10-14: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove redundant Message struct.

Since Receive() strips all metadata and only returns the message body string, the Sender and Receiver fields add no value. You can simplify the codebase by using chan string directly for message passing.


67-72: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Update Client initialization to reflect channel changes.

Update the struct initialization to remove the unused outChannel and change inChannel to chan string, aligning with the suggested Client refactor above.

♻️ Proposed refactor
 	client := &Client{
 		username:   username,
-		inChannel:  make(chan Message, 10),
-		outChannel: make(chan Message, 10),
+		inChannel:  make(chan string, 10),
 		connected:  true,
 	}

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 124c07ce-390e-4446-b0a5-0aa38f9daf3e

📥 Commits

Reviewing files that changed from the base of the PR and between 8522a72 and 77f909a.

📒 Files selected for processing (1)
  • challenge-8/submissions/aruncs/solution-template.go

Comment on lines +16 to +39
// Client represents a connected chat client
type Client struct {
// TODO: Implement this struct
// Hint: username, message channel, mutex, disconnected flag
username string
outChannel chan Message
inChannel chan Message
connected bool
}

// Send sends a message to the client
func (c *Client) Send(message string) {
// TODO: Implement this method
// Hint: thread-safe, non-blocking send

}

// Receive returns the next message for the client (blocking)
func (c *Client) Receive() string {
// TODO: Implement this method
// Hint: read from channel, handle closed channel
message := <-c.inChannel
return message.Message
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Implement thread-safe Send and fix Receive channel handling.

There are several critical functional and stability issues here:

  • Send is entirely unwritten, meaning messages are never dispatched through the client's public API.
  • The Client struct lacks a mutex, leaving the connected flag vulnerable to data races.
  • outChannel is declared but never utilized.
  • Receive does not verify if the channel is closed, which can cause erratic behavior on disconnect.

Refactor the client to use a single chan string, a mutex, and a non-blocking Send method.

🛠️ Proposed refactor for Client
 // Client represents a connected chat client
 type Client struct {
-	// TODO: Implement this struct
-	// Hint: username, message channel, mutex, disconnected flag
 	username   string
-	outChannel chan Message
-	inChannel  chan Message
+	inChannel  chan string
+	mu         sync.Mutex
 	connected  bool
 }

 // Send sends a message to the client
 func (c *Client) Send(message string) {
-	// TODO: Implement this method
-	// Hint: thread-safe, non-blocking send
-
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	if !c.connected {
+		return
+	}
+	select {
+	case c.inChannel <- message:
+	default:
+		// Channel full, drop message to prevent blocking
+	}
 }

 // Receive returns the next message for the client (blocking)
 func (c *Client) Receive() string {
-	// TODO: Implement this method
-	// Hint: read from channel, handle closed channel
-	message := <-c.inChannel
-	return message.Message
+	msg, ok := <-c.inChannel
+	if !ok {
+		return ""
+	}
+	return msg
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Client represents a connected chat client
type Client struct {
// TODO: Implement this struct
// Hint: username, message channel, mutex, disconnected flag
username string
outChannel chan Message
inChannel chan Message
connected bool
}
// Send sends a message to the client
func (c *Client) Send(message string) {
// TODO: Implement this method
// Hint: thread-safe, non-blocking send
}
// Receive returns the next message for the client (blocking)
func (c *Client) Receive() string {
// TODO: Implement this method
// Hint: read from channel, handle closed channel
message := <-c.inChannel
return message.Message
}
// Client represents a connected chat client
type Client struct {
username string
inChannel chan string
mu sync.Mutex
connected bool
}
// Send sends a message to the client
func (c *Client) Send(message string) {
c.mu.Lock()
defer c.mu.Unlock()
if !c.connected {
return
}
select {
case c.inChannel <- message:
default:
// Channel full, drop message to prevent blocking
}
}
// Receive returns the next message for the client (blocking)
func (c *Client) Receive() string {
msg, ok := <-c.inChannel
if !ok {
return ""
}
return msg
}

Comment on lines +79 to +91
// Disconnect removes a client from the chat server
func (s *ChatServer) Disconnect(client *Client) {
// TODO: Implement this method
// Hint: remove from map, close channels
s.mu.Lock()
defer s.mu.Unlock()

delete(s.clients, client.username)
close(client.inChannel)
close(client.outChannel)

client.connected = false
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Prevent double-close panic and data races during disconnect.

If Disconnect is called twice for the same client, close(client.inChannel) will trigger a runtime panic. Additionally, to avoid data races with the Send method (which reads client.connected and writes to the channel), you must synchronize this block using the client's mutex.

🔒️ Proposed fix to synchronize and guard against panics
 func (s *ChatServer) Disconnect(client *Client) {
-	// TODO: Implement this method
-	// Hint: remove from map, close channels
 	s.mu.Lock()
 	defer s.mu.Unlock()

+	client.mu.Lock()
+	defer client.mu.Unlock()
+
+	if !client.connected {
+		return
+	}
+
 	delete(s.clients, client.username)
 	close(client.inChannel)
-	close(client.outChannel)

 	client.connected = false
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Disconnect removes a client from the chat server
func (s *ChatServer) Disconnect(client *Client) {
// TODO: Implement this method
// Hint: remove from map, close channels
s.mu.Lock()
defer s.mu.Unlock()
delete(s.clients, client.username)
close(client.inChannel)
close(client.outChannel)
client.connected = false
}
// Disconnect removes a client from the chat server
func (s *ChatServer) Disconnect(client *Client) {
s.mu.Lock()
defer s.mu.Unlock()
client.mu.Lock()
defer client.mu.Unlock()
if !client.connected {
return
}
delete(s.clients, client.username)
close(client.inChannel)
client.connected = false
}

Comment on lines +104 to +108
receiver.inChannel <- Message{
Sender: sender.username,
Receiver: receiver.username,
Message: message,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Use non-blocking Send to prevent server deadlocks.

Direct blocking channel sends while holding the server's RLock() can deadlock the entire server if a client's channel fills up (which blocks the send, thereby starving write locks like Disconnect). The shared root cause is bypassing the client's non-blocking Send method.

  • challenge-8/submissions/aruncs/solution-template.go#L104-L108: replace the blocking Message send with a call to the non-blocking receiver.Send(message).
  • challenge-8/submissions/aruncs/solution-template.go#L130-L134: replace the blocking Message send with a call to the non-blocking receiver.Send(message).
📍 Affects 1 file
  • challenge-8/submissions/aruncs/solution-template.go#L104-L108 (this comment)
  • challenge-8/submissions/aruncs/solution-template.go#L130-L134

@github-actions
github-actions Bot merged commit ba1df29 into RezaSi:main Jul 17, 2026
6 checks passed
@github-actions

Copy link
Copy Markdown

🎉 Auto-merged!

This PR was automatically merged after 2 days with all checks passing.

Thank you for your contribution, @aruncs!

📊 Scoreboards and badges will be updated shortly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant