การดู : 0

04/03/2026 08:51น.

EP.40 การเพิ่มฟีเจอร์อัปโหลดไฟล์ใน WebSocket Chat

EP.40 การเพิ่มฟีเจอร์อัปโหลดไฟล์ใน WebSocket Chat

#Chat Media Upload

#Firebase Storage

#AWS S3

#GraphQL File Upload

#WebSocket File Sharing

#Real-Time Chat

#Golang

#Go

#WebSocket

#File Upload

ทำไมต้องมีฟีเจอร์อัปโหลดไฟล์ใน WebSocket Chat?

ในระบบแชทที่ทันสมัย ผู้ใช้ต้องการสามารถ แชร์ไฟล์ รูปภาพ และเอกสาร ระหว่างกันได้ การเพิ่มฟีเจอร์ อัปโหลดไฟล์ผ่าน WebSocket ทำให้ผู้ใช้สามารถส่งไฟล์ได้แบบเรียลไทม์โดยไม่ต้องโหลดหน้าใหม่ ซึ่งเหมาะสำหรับ:

  • ระบบแชทภายในองค์กร ที่ต้องแชร์เอกสารและไฟล์งาน
  • แพลตฟอร์มโซเชียลมีเดีย ที่ให้ผู้ใช้ส่งรูปภาพและวิดีโอ
  • บริการสนับสนุนลูกค้า ที่ต้องส่งไฟล์แนบหรือภาพถ่ายปัญหาต่างๆ

โครงสร้างของระบบอัปโหลดไฟล์ใน WebSocket Chat

  1. WebSocket Server - รับไฟล์จากผู้ใช้และกระจายไปยังผู้ใช้ที่เกี่ยวข้อง
  2. GraphQL API - ใช้เพื่อจัดการการอัปโหลดไฟล์และเก็บเมตะดาต้า
  3. File Storage - จัดเก็บไฟล์ในเซิร์ฟเวอร์หรือ Cloud Storage (เช่น AWS S3 หรือ Firebase Storage)
  4. Database (PostgreSQL / MongoDB) - เก็บข้อมูลไฟล์ เช่น URL และข้อมูลผู้ส่ง

ติดตั้งไลบรารีที่จำเป็น

go get github.com/gorilla/websocket
go get github.com/minio/minio-go/v7

การตั้งค่าฐานข้อมูลสำหรับเก็บข้อมูลไฟล์

ไฟล์ schema.sql

CREATE TABLE chat_files (
    id SERIAL PRIMARY KEY,
    room_id INTEGER NOT NULL,
    sender TEXT NOT NULL,
    file_url TEXT NOT NULL,
    file_name TEXT NOT NULL,
    file_type TEXT NOT NULL,
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

การสร้าง GraphQL Schema สำหรับการอัปโหลดไฟล์

ไฟล์ schema.graphql

type Mutation {
  uploadFile(roomID: ID!, sender: String!, fileName: String!, fileType: String!, fileContent: String!): ChatFile!
}

type ChatFile {
  id: ID!
  roomID: ID!
  sender: String!
  fileURL: String!
  fileName: String!
  fileType: String!
  timestamp: String!
}

การสร้าง Resolver สำหรับการอัปโหลดไฟล์

ไฟล์ resolver.go

package main

import (
    "context"
    "encoding/base64"
    "fmt"
    "os"
    "path/filepath"
    "time"
)

type ChatFile struct {
    ID        int       `json:"id"`
    RoomID    int       `json:"roomID"`
    Sender    string    `json:"sender"`
    FileURL   string    `json:"fileURL"`
    FileName  string    `json:"fileName"`
    FileType  string    `json:"fileType"`
    Timestamp time.Time `json:"timestamp"`
}

func (r *Resolver) Mutation_uploadFile(ctx context.Context, roomID int, sender string, fileName string, fileType string, fileContent string) (ChatFile, error) {
    decoded, err := base64.StdEncoding.DecodeString(fileContent)
    if err != nil {
        return ChatFile{}, err
    }

    savePath := filepath.Join("uploads", fileName)
    err = os.WriteFile(savePath, decoded, 0644)
    if err != nil {
        return ChatFile{}, err
    }

    fileURL := fmt.Sprintf("/uploads/%s", fileName)
    file := ChatFile{RoomID: roomID, Sender: sender, FileURL: fileURL, FileName: fileName, FileType: fileType, Timestamp: time.Now()}
    return file, nil
}

การส่งไฟล์ผ่าน WebSocket

ไฟล์ websocket_server.go

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "github.com/gorilla/websocket"
)

type FileMessage struct {
    RoomID    int    `json:"roomID"`
    Sender    string `json:"sender"`
    FileName  string `json:"fileName"`
    FileType  string `json:"fileType"`
    FileURL   string `json:"fileURL"`
}

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

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
    conn, _ := upgrader.Upgrade(w, r, nil)
    defer conn.Close()
    fmt.Println("Client connected")

    for {
        _, msg, err := conn.ReadMessage()
        if err != nil {
            break
        }
        var fileMsg FileMessage
        json.Unmarshal(msg, &fileMsg)
        fmt.Printf("Received file: %s from %s\n", fileMsg.FileName, fileMsg.Sender)
    }
}

func main() {
    http.HandleFunc("/ws", handleWebSocket)
    fmt.Println("WebSocket Server Running on Port 8080")
    http.ListenAndServe(":8080", nil)
}

การอัปโหลดไฟล์จากฝั่ง Client

ไฟล์ client.js

async function uploadFile(file) {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = async () => {
        const base64Content = reader.result.split(",")[1];
        const response = await fetch("/graphql", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
                query: `mutation { uploadFile(roomID: 1, sender: "JohnDoe", fileName: "${file.name}", fileType: "${file.type}", fileContent: "${base64Content}" ) { fileURL } }`
            })
        });
        console.log(await response.json());
    };
}

ท้าให้ลอง!

ลองเพิ่ม ระบบแสดงตัวอย่างไฟล์ก่อนอัปโหลด เพื่อให้ผู้ใช้สามารถดูไฟล์ก่อนกดส่งไปยังห้องแชท


EP ถัดไป

ใน EP.41, เราจะเพิ่ม ฟีเจอร์แสดงสถานะการพิมพ์ (Typing Indicator) ใน WebSocket Chat 🚀