-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
135 lines (118 loc) · 3.19 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"fmt"
"log"
"net/http"
"sync"
"time"
"github.com/gorilla/websocket"
)
// WebSocket upgrader to convert HTTP connections to WebSocket
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true // Allow all origins
},
}
// Global variables to manage connected clients and broadcasting messages
var (
clients = make(map[*websocket.Conn]bool) // Tracks active WebSocket connections
broadcast = make(chan struct {
sender *websocket.Conn
message []byte
})
mutex sync.Mutex // Mutex for safe access to shared data
)
// WebSocket handler: Manages individual client connections
func wsHandler(w http.ResponseWriter, r *http.Request) {
// Upgrade HTTP connection to WebSocket
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("WebSocket upgrade error:", err)
return
}
defer func() {
mutex.Lock()
delete(clients, conn) // Remove client on disconnect
mutex.Unlock()
conn.Close()
log.Println("Client disconnected")
}()
// Register the new client
mutex.Lock()
clients[conn] = true
mutex.Unlock()
log.Println("New client connected")
// Send a welcome message
if err := conn.WriteMessage(websocket.TextMessage, []byte("Welcome to the WebSocket server!")); err != nil {
log.Println("Error sending welcome message:", err)
return
}
// Continuously read messages from the client
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Error reading message:", err)
break
}
log.Println("Received message:", string(message))
broadcast <- struct {
sender *websocket.Conn
message []byte
}{sender: conn, message: message} // Send sender info with the message
}
}
// Broadcasts messages to all connected clients
func handleBroadcast() {
for {
// Receive message from the broadcast channel
data := <-broadcast
sender := data.sender
message := data.message
mutex.Lock()
for client := range clients {
if client != sender { // Skip sending back to the sender
if err := client.WriteMessage(websocket.TextMessage, message); err != nil {
log.Println("Error broadcasting message:", err)
client.Close()
delete(clients, client) // Remove disconnected clients
}
}
}
mutex.Unlock()
}
}
// Sends periodic ping messages to maintain WebSocket connections
func keepAlive() {
ticker := time.NewTicker(30 * time.Second) // Pings every 30 seconds
defer ticker.Stop()
for {
<-ticker.C
mutex.Lock()
for client := range clients {
if err := client.WriteMessage(websocket.PingMessage, nil); err != nil {
log.Println("Ping error:", err)
client.Close()
delete(clients, client) // Remove unresponsive clients
}
}
mutex.Unlock()
}
}
// Simple HTTP handler for the home page
func homePage(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Welcome to the WebSocket Server!")
}
// Set up HTTP routes
func setupRoutes() {
http.HandleFunc("/", homePage)
http.HandleFunc("/ws", wsHandler)
}
func main() {
fmt.Println("WebSocket server running on :8080")
// Start the broadcaster and keep-alive mechanisms
go handleBroadcast()
go keepAlive()
// Set up routes and start the HTTP server
setupRoutes()
log.Fatal(http.ListenAndServe(":8080", nil))
}