I am batman

This commit is contained in:
2026-07-12 20:26:16 -04:00
commit 5a3a6357cf
37 changed files with 2938 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
package chat_service
import (
"fmt"
"OpsMastery.v5/internal/utils"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/websocket/v2"
)
// Message struct definition
// This struct represents a chat message sent/received via WebSocket.
// It contains the message content and the sender's identifier (email).
type Message struct {
Content string `json:"content"` // The actual message text
Sender string `json:"sender"` // The sender's email or username
// Add more fields as needed (e.g., timestamp, chatId, etc.)
}
// clients is a map of active WebSocket connections.
// The key is the pointer to the websocket.Conn, the value is a boolean (always true).
// This allows us to keep track of all connected clients for broadcasting messages.
var clients = make(map[*websocket.Conn]bool)
// broadcastMessage sends a given Message to all connected clients.
// If a client connection fails, it is removed from the clients map.
func broadcastMessage(msg Message) {
for client := range clients {
// Send the message as JSON to the client
err := client.WriteJSON(msg)
if err != nil {
// If sending fails, print error, close connection, and remove client
fmt.Println("Error sending message:", err)
client.Close()
delete(clients, client)
}
}
}
// Start initializes and runs the chat WebSocket server.
func Start() {
// Create a new Fiber app instance
app := fiber.New()
// Serve static files from the ./public directory at /public
app.Static("/public", "./public")
// Middleware for /ws route to validate JWT token before allowing WebSocket upgrade
app.Use("/ws", func(c *fiber.Ctx) error {
// Extract token from query parameters
token := c.Query("token")
if token == "" {
// If no token, reject the request
return c.Status(fiber.StatusUnauthorized).SendString("Missing token")
}
// Validate the JWT token
claims, err := utils.ValidateJWT(token, false)
if err != nil {
// If token is invalid, reject the request
return c.Status(fiber.StatusUnauthorized).SendString("Invalid token")
}
// Store the user's email in Fiber's context locals for later use
c.Locals("userEmail", claims["email"])
// Proceed to the next handler (WebSocket upgrade)
return c.Next()
})
// WebSocket endpoint for chat communication
app.Get("/ws", websocket.New(func(c *websocket.Conn) {
// Retrieve the user's email from context locals
userEmail, _ := c.Locals("userEmail").(string)
// Register the new client connection
clients[c] = true
// Ensure client is removed and connection closed when handler exits
defer func() {
delete(clients, c)
c.Close()
}()
// Main loop: read messages from this client and broadcast to all clients
for {
var msg Message
// Try to read a JSON message from the client
err := c.ReadJSON(&msg)
if err != nil {
// If JSON parsing fails, try to read a raw message (e.g., plain text)
_, rawMsg, readErr := c.ReadMessage()
if readErr != nil {
// If reading fails, log and break the loop (disconnect client)
fmt.Println("WebSocket closed:", readErr)
break
}
// Construct a Message from the raw message and set sender
msg = Message{Content: string(rawMsg), Sender: userEmail}
} else {
// If JSON was parsed, set the sender field
msg.Sender = userEmail
}
// Broadcast the received message to all connected clients
broadcastMessage(msg)
}
}))
// Start the Fiber server on port 5000
app.Listen(":5000")
}