راه‌اندازی برنامه Websocket


وب‌سوکت (WebSocket) یک فناوری ارتباطی در وب است که به سرور و مرورگر اجازه می‌دهد از طریق یک اتصال دوطرفه دائمی، داده‌ها را به صورت تعاملی ارسال و دریافت کنند. در واقع مرورگر می‌تواند داده‌ها را بفرستد و دریافت کند بدون اینکه نیازی به بارگیری دوباره صفحه وب (refresh) باشد. این ویژگی به برنامه‌های تعاملی مانند چت‌های زنده و بازی‌های آنلاین کمک می‌کند. در ادامه، به نحوه ایجاد برنامه WebSocket در go با استفاده از ماژول websocket و همچنین نحوه استقرار آن در لیارا، پرداخته شده است.

ساخت برنامه WebSocket در Go

پروژه‌ در پیش‌رو، یک چت‌روم تحت وب در go است که کاربران می‌توانند در آن به صورت Realtime (با تکیه بر WebSocket) به گفتگو بپردازند. در ابتدا، بایستی با اجرای دستور زیر، یک پروژه جدید go را، ایجاد کنید:

کپی
go mod init realtime-chat

‌پس از اجرای دستور فوق، کافیست تا دستور زیر را اجرا کنید تا ماژول‌ websocket برای‌تان نصب شود:

کپی
go get -u github.com/gorilla/websocket

حال، بایستی یک فایل به نام main.go ایجاد کنید و قطعه کد زیر را درون آن، قرار دهید:

کپی
package main

import (
"log"
"net/http"
"sync"

"github.com/gorilla/websocket"
)

// WebSocket upgrader
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
	return true
},
}

// Client structure
type Client struct {
ID       string
Username string
Conn     *websocket.Conn
}

// Message structure
type Message struct {
SenderID string `json:"senderID"`
Username string `json:"username"`
Text     string `json:"text"`
}

var (
clients   = make(map[string]*Client)
clientsMu sync.Mutex
broadcast = make(chan Message)
)

// Handle WebSocket connections
func handleConnections(w http.ResponseWriter, r *http.Request) {
// Upgrade the HTTP connection to WebSocket
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
	log.Printf("Error upgrading connection: %v", err)
	return
}
defer conn.Close()

// Receive the username as the first message
var initMessage Message
err = conn.ReadJSON(&initMessage)
if err != nil {
	log.Printf("Error reading initial message: %v", err)
	return
}

client := &Client{
	ID:       conn.RemoteAddr().String(),
	Username: initMessage.Username,
	Conn:     conn,
}

// Add the client to the list
clientsMu.Lock()
clients[client.ID] = client
clientsMu.Unlock()

log.Printf("New client connected: %s (%s)", client.ID, client.Username)

// Listen for messages from the client
for {
	var msg Message
	err := conn.ReadJSON(&msg)
	if err != nil {
		log.Printf("Error reading JSON: %v", err)
		break
	}
	msg.SenderID = client.ID
	msg.Username = client.Username
	broadcast <- msg
}

// Remove the client from the list when disconnected
clientsMu.Lock()
delete(clients, client.ID)
clientsMu.Unlock()
log.Printf("Client disconnected: %s (%s)", client.ID, client.Username)
}

// Broadcast messages to all clients
func handleMessages() {
for {
	msg := <-broadcast
	clientsMu.Lock()
	for _, client := range clients {
		err := client.Conn.WriteJSON(msg)
		if err != nil {
			log.Printf("Error sending message: %v", err)
			client.Conn.Close()
			delete(clients, client.ID)
		}
	}
	clientsMu.Unlock()
}
}

func main() {
// Serve static files (like index.html)
http.Handle("/", http.FileServer(http.Dir("./static")))

// WebSocket handler
http.HandleFunc("/ws", handleConnections)

// Start the server
log.Println("Server started on :8080")
go handleMessages()
err := http.ListenAndServe(":8080", nil)
if err != nil {
	log.Fatalf("Server failed: %v", err)
}
}

در ادامه، کافیست تا در مسیر اصلی پروژه، یک دایرکتوری به اسم static ایجاد کرده و درون این دایرکتوری، یک فایل به نام index.html ایجاد کنید و قطعه کد زیر را درون آن، قرار دهید:

کپی
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Real-Time Chat</title>
</head>
<body>
  <!-- Login Section -->
  <div id="login-container">
      <h2>Welcome to Chat</h2>
      <input type="text" id="username" placeholder="Enter your username" />
      <button onclick="joinChat()">Join Chat</button>
  </div>

  <!-- Chat Section -->
  <div id="chat-container">
      <div id="messages"></div>
      <div id="message-input">
          <input type="text" id="message" placeholder="Type a message..." />
          <button onclick="sendMessage()">Send</button>
      </div>
  </div>

  <script>
      let socket;
      let username;

      // Join Chat
      function joinChat() {
          username = document.getElementById("username").value.trim();
          if (!username) {
              alert("Please enter a username!");
              return;
          }

          // Connect to WebSocket
          socket = new WebSocket("ws://localhost:8080/ws");

          // Send initial message with username
          socket.onopen = () => {
              socket.send(JSON.stringify({ username }));
              document.getElementById("login-container").style.display = "none";
              document.getElementById("chat-container").style.display = "flex";
          };

          // Handle incoming messages
          socket.onmessage = (event) => {
              const msg = JSON.parse(event.data);
              const msgDiv = document.createElement("div");
              msgDiv.classList.add("message", msg.senderID === username ? "sent" : "received");

              // Create the username section
              const usernameDiv = document.createElement("div");
              usernameDiv.classList.add("username");
              usernameDiv.textContent = msg.username;

              // Create the message text section
              const textDiv = document.createElement("div");
              textDiv.textContent = msg.text;

              msgDiv.appendChild(usernameDiv);
              msgDiv.appendChild(textDiv);
              document.getElementById("messages").appendChild(msgDiv);
              document.getElementById("messages").scrollTop = document.getElementById("messages").scrollHeight;
          };
      }

      // Send Message
      function sendMessage() {
          const input = document.getElementById("message");
          if (input.value.trim()) {
              socket.send(JSON.stringify({ text: input.value }));
              input.value = "";
          }
      }
  </script>
</body>
</html>

تمامی کارها انجام شده است و اکنون می‌توانید با اجرای دستور زیر، برنامه‌تان را اجرا کرده و از آن استفاده کنید:

کپی
go run main.go

استقرار برنامه Go WebSocket در لیارا

برای استقرار برنامه‌های وب‌سوکت Go در لیارا، نیازی به انجام تغییر خاصی نیست. صرفاً باید به جای استفاده از آدرس ws، عبارت wss را به کار ببرید تا اتصال، ایمن و سازگار باشد.

سورس کامل یک برنامه Go WebSocket آماده استقرار در اینجا موجود است که می‌توانید از آن استفاده کنید.