Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions challenge-1/submissions/brenoamin/solution-template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"fmt"
)

func main() {
var a, b int
// Read two integers from standard input
_, err := fmt.Scanf("%d, %d", &a, &b)
if err != nil {
fmt.Println("Error reading input:", err)
return
}

// Call the Sum function and print the result
result := Sum(a, b)
fmt.Println(result)
}

// Sum returns the sum of a and b.
func Sum(a int, b int) int {
return a + b
}
189 changes: 189 additions & 0 deletions challenge-8/submissions/brenoamin/solution-template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// Package challenge8 contains the solution for Challenge 8: Chat Server with Channels.
package challenge8

import (
"errors"
"fmt"
"log"
"net"
"strings"
"sync"
// Add any other necessary imports
)

// Client represents a connected chat client
type Client struct {
Username string
Conn net.Conn
Outgoing chan string
Disconnected bool
mu sync.Mutex
}

// Send sends a message to the client
func (c *Client) Send(message string) {
c.mu.Lock()
if c.Disconnected {
c.mu.Unlock()
return
}
c.mu.Unlock()

select {
case c.Outgoing <- message:
default:

}
}

// Receive returns the next message for the client (blocking)
func (c *Client) Receive() string {
msg, ok := <-c.Outgoing
if !ok {
return ""
}
return msg
}

// ChatServer manages client connections and message routing
type ChatServer struct {
// Hint: clients map, mutex
clients map[*Client]bool
broadcast chan string
join chan *Client
leave chan *Client
mu sync.Mutex
}

// NewChatServer creates a new chat server instance
func NewChatServer() *ChatServer {
return &ChatServer{
clients: make(map[*Client]bool),
broadcast: make(chan string),
}
}

// Connect adds a new client to the chat server
func (s *ChatServer) Connect(username string) (*Client, error) {
log.Printf("[connect] username=%s", username)

s.mu.Lock()
defer s.mu.Unlock()

for client := range s.clients {
if client.Username == username {
log.Printf("[connect-failed] username=%s reason=already_taken", username)
return nil, ErrUsernameAlreadyTaken
}
}

client := &Client{
Username: username,
Conn: nil,
Outgoing: make(chan string, 8),
Disconnected: false,
}
s.clients[client] = true
log.Printf("[connect-success] username=%s total_clients=%d", username, len(s.clients))

return client, nil
}

// Disconnect removes a client from the chat server
func (s *ChatServer) Disconnect(client *Client) {
s.mu.Lock()
_, exists := s.clients[client]
if !exists {
s.mu.Unlock()
return
}
delete(s.clients, client)
remaining := len(s.clients)
s.mu.Unlock()

client.mu.Lock()
if !client.Disconnected {
close(client.Outgoing)
client.Disconnected = true
}
client.mu.Unlock()
log.Printf("[disconnect] username=%s remaining_clients=%d", client.Username, remaining)
}

// Broadcast sends a message to all connected clients
func (s *ChatServer) Broadcast(sender *Client, message string) {
message = strings.TrimSpace(message)
if message == "" {
log.Printf("[broadcast-ignored] sender=%s reason=empty_message", sender.Username)
return
}

sender.mu.Lock()
if sender.Disconnected {
log.Printf("[broadcast-ignored] sender=%s reason=disconnected", sender.Username)
return
}
sender.mu.Unlock()
Comment on lines +121 to +126
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Mutex deadlock on early return.

When sender.Disconnected is true, the function returns at line 124 without releasing the lock acquired at line 121. This will cause a deadlock on any subsequent operation involving sender.

 	sender.mu.Lock()
 	if sender.Disconnected {
 		log.Printf("[broadcast-ignored] sender=%s reason=disconnected", sender.Username)
+		sender.mu.Unlock()
 		return
 	}
 	sender.mu.Unlock()
📝 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
sender.mu.Lock()
if sender.Disconnected {
log.Printf("[broadcast-ignored] sender=%s reason=disconnected", sender.Username)
return
}
sender.mu.Unlock()
sender.mu.Lock()
if sender.Disconnected {
log.Printf("[broadcast-ignored] sender=%s reason=disconnected", sender.Username)
sender.mu.Unlock()
return
}
sender.mu.Unlock()
🤖 Prompt for AI Agents
In challenge-8/submissions/brenoamin/solution-template.go around lines 121 to
126, the code acquires sender.mu.Lock() then returns early when
sender.Disconnected is true, causing a mutex deadlock; fix by ensuring the mutex
is always released before any return — either check sender.Disconnected without
holding the lock (move the check before acquiring the mutex), or immediately
defer sender.mu.Unlock() right after locking so the lock is released on all
return paths, and remove the premature return while locked.


formatted := fmt.Sprintf("%s, %s", sender.Username, message)

s.mu.Lock()
count := 0
for client := range s.clients {
if client != sender {
client.Send(formatted)
count++
}
}
s.mu.Unlock()
log.Printf("[broadcast-success] sender=%s count=%d", sender.Username, count)
}

// PrivateMessage sends a message to a specific client
func (s *ChatServer) PrivateMessage(sender *Client, recipient string, message string) error {
message = strings.TrimSpace(message)
if message == "" {
return ErrEmptyMessage
}

sender.mu.Lock()
if sender.Disconnected {
return ErrSenderDisconnected
}
sender.mu.Unlock()
Comment on lines +149 to +153
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Mutex deadlock on early return.

Same issue as in Broadcast: when sender.Disconnected is true, the function returns at line 151 without releasing the lock acquired at line 149.

 	sender.mu.Lock()
 	if sender.Disconnected {
+		sender.mu.Unlock()
 		return ErrSenderDisconnected
 	}
 	sender.mu.Unlock()
📝 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
sender.mu.Lock()
if sender.Disconnected {
return ErrSenderDisconnected
}
sender.mu.Unlock()
sender.mu.Lock()
if sender.Disconnected {
sender.mu.Unlock()
return ErrSenderDisconnected
}
sender.mu.Unlock()
🤖 Prompt for AI Agents
In challenge-8/submissions/brenoamin/solution-template.go around lines 149 to
153, the code acquires sender.mu.Lock() then returns early when
sender.Disconnected is true, causing a mutex deadlock; fix by ensuring the lock
is always released before any return — either unlock explicitly before returning
or use defer sender.mu.Unlock() immediately after acquiring the lock so the
mutex is released on all control paths.


s.mu.Lock()
var rC *Client
for client := range s.clients {
if client.Username == recipient {
rC = client
break
}
}
s.mu.Unlock()

if rC == nil {
return ErrRecipientNotFound
}

rC.mu.Lock()
disconnected := rC.Disconnected
rC.mu.Unlock()
if disconnected {
return ErrRecipientDisconnected
}

formatted := fmt.Sprintf("%s, %s", sender.Username, message)
rC.Send(formatted)

return nil
}

// Common errors that can be returned by the Chat Server
var (
ErrUsernameAlreadyTaken = errors.New("username already taken")
ErrRecipientNotFound = errors.New("recipient not found")
ErrSenderDisconnected = errors.New("sender disconnected")
ErrRecipientDisconnected = errors.New("recipient disconnected")
ErrEmptyMessage = errors.New("empty message")
)
Loading