package main import ( "encoding/json" "fmt" "io" "log" "net/http" "sync" "time" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{} var wsBroadcast = make(chan []byte, 100) const TIMEOUT = 6 const IDLE_TIMEOUT = TIMEOUT * time.Second const PING_INTERVAL = (TIMEOUT - 1) * time.Second type WSConnection struct { conn *websocket.Conn writeLock sync.Mutex ReadChan chan string WriteChan chan string } func (ws *WSConnection) messageReader() { log.Printf("Reading messages") for { _, message, err := ws.conn.ReadMessage() ws.conn.SetReadDeadline(time.Now().Add(IDLE_TIMEOUT)) if err != nil { return } log.Printf("Received: %s", message) ws.ReadChan <- string(message) } } func (ws *WSConnection) messageSender() { log.Printf("Sending messages") for { msg := <-ws.WriteChan ws.writeLock.Lock() ws.conn.SetWriteDeadline(time.Now().Add(IDLE_TIMEOUT)) log.Printf("Sending: %s", msg) err := ws.conn.WriteMessage(websocket.TextMessage, []byte(msg)) if err != nil { log.Printf("Error during message writing: %v", err) return } ws.writeLock.Unlock() } } func (ws *WSConnection) pinger() { log.Printf("Starting pinger, sleeping for %v", PING_INTERVAL) for { time.Sleep(PING_INTERVAL) // log.Printf("Ping") ws.writeLock.Lock() err := ws.conn.WriteMessage(websocket.PingMessage, nil) if err != nil { log.Println("Error during ping:", err) return } ws.writeLock.Unlock() } } func (ws *WSConnection) Open() { log.Printf("Client connected") ws.ReadChan = make(chan string, 1024) ws.WriteChan = make(chan string, 1024) ws.conn.SetReadLimit(1024) ws.conn.SetReadDeadline(time.Now().Add(IDLE_TIMEOUT)) ws.conn.SetWriteDeadline(time.Now().Add(IDLE_TIMEOUT)) ws.conn.SetPongHandler(func(string) error { // log.Println("Pong") ws.conn.SetReadDeadline(time.Now().Add(IDLE_TIMEOUT)) ws.conn.SetWriteDeadline(time.Now().Add(IDLE_TIMEOUT)) return nil }) go ws.messageReader() go ws.messageSender() go ws.pinger() } func wsHandler(responseWriter http.ResponseWriter, request *http.Request) { conn, err := upgrader.Upgrade(responseWriter, request, nil) if err != nil { fmt.Println("Error during connection upgrade:", err) return } ws := new(WSConnection) ws.conn = conn ws.Open() } type DownloadReq struct { Link string `json:"link"` } func handleDownload(responseWriter http.ResponseWriter, request *http.Request) { body, err := io.ReadAll(request.Body) if err != nil { log.Printf("Error reading request body: %v", err) http.Error(responseWriter, "Error reading request body", http.StatusBadRequest) return } defer request.Body.Close() req := DownloadReq{} err = json.Unmarshal(body, &req) if err != nil { log.Printf("Error parsing JSON: %v", err) http.Error(responseWriter, "Error parsing JSON", http.StatusBadRequest) return } log.Printf("Received download request: %s", req.Link) wsBroadcast <- []byte(req.Link) } func main() { log.SetFlags(log.Lmicroseconds) http.HandleFunc("/ws", wsHandler) http.HandleFunc("/download", handleDownload) log.Println("Server starting on :8080") err := http.ListenAndServe(":8080", nil) if err != nil { log.Println("Error starting server:", err) } }