diff --git a/main.go b/main.go index 113eaee..240b943 100644 --- a/main.go +++ b/main.go @@ -43,7 +43,8 @@ func (s *Server) handleSession(roomName string, sess *webtransport.Session) { room.conns[sess] = true room.mu.Unlock() - log.Printf("Joined room: %s", roomName) + log.Printf("Joined room: %s | Total: %d", roomName, len(room.conns)) + defer func() { room.mu.Lock() delete(room.conns, sess) @@ -61,6 +62,7 @@ func (s *Server) handleSession(roomName string, sess *webtransport.Session) { } func (s *Server) handleStream(room *Room, sender *webtransport.Session, stream *webtransport.Stream) { + defer stream.Close() buf := make([]byte, 4096) for { n, err := stream.Read(buf) @@ -74,6 +76,7 @@ func (s *Server) handleStream(room *Room, sender *webtransport.Session, stream * if conn == sender { continue } + // Отправляем данные другим участникам go func(c *webtransport.Session, d []byte) { out, err := c.OpenStream() if err != nil { @@ -91,52 +94,71 @@ func main() { domain := "qgo-server.quizer.space" email := "serverussnap@outlook.com" - // Настройка CertMagic (как в вашем рабочем коде) + // 1. Настройка CertMagic certmagic.DefaultACME.Email = email certmagic.DefaultACME.Agreed = true - certmagic.Default.Storage = &certmagic.FileStorage{Path: "/root/.local/share/certmagic"} + + cfg, err := certmagic.TLS([]string{domain}) + if err != nil { + log.Fatal(err) + } + // Важно для QUIC: устанавливаем NextProtos + cfg.NextProtos = []string{"h3", "h2", "http/1.1"} server := NewServer() - // Настройка WebTransport + // 2. Инициализация WebTransport сервера wt := &webtransport.Server{ - H3: &http3.Server{ - Addr: ":443", - EnableDatagrams: true, // Важно для WebTransport - }, CheckOrigin: func(r *http.Request) bool { return true }, } mux := http.NewServeMux() mux.HandleFunc("/room/", func(w http.ResponseWriter, r *http.Request) { - // 1. Обязательно даем понять браузеру, что тут есть HTTP/3 (UDP 443) + // Сообщаем браузеру о наличии HTTP/3 w.Header().Set("Alt-Svc", `h3=":443"; ma=86400`) - // 2. Если это не CONNECT (не WebTransport), а обычный GET - if r.Method != http.MethodConnect { - log.Printf("Received GET request on %s. Sending Alt-Svc to client...", r.URL.Path) - w.WriteHeader(http.StatusOK) - w.Write([]byte("To use WebTransport, the browser needs to see this Alt-Svc header first. Try connecting again now.")) + if r.Method == http.MethodConnect { + sess, err := wt.Upgrade(w, r) + if err != nil { + log.Printf("Upgrade error: %v", err) + return + } + roomName := strings.TrimPrefix(r.URL.Path, "/room/") + go server.handleSession(roomName, sess) return } - // 3. Если это CONNECT, пробуем апгрейд - sess, err := wt.Upgrade(w, r) - if err != nil { - log.Printf("Upgrade error: %v", err) - return - } - - roomName := strings.TrimPrefix(r.URL.Path, "/room/") - go server.handleSession(roomName, sess) + w.WriteHeader(http.StatusOK) + w.Write([]byte("Waiting for WebTransport connection...")) }) - log.Printf("Starting server on %s", domain) + // 3. HTTP/3 Сервер (UDP) + h3Server := &http3.Server{ + Addr: ":443", + Handler: mux, + TLSConfig: cfg, + EnableDatagrams: true, + } + wt.H3 = h3Server - // Используем certmagic.HTTPS, который сам создаст нужный TLSConfig - // и запустит HTTP/3 (UDP) + HTTPS (TCP) корректно. - err := certmagic.HTTPS([]string{domain}, mux) - if err != nil { - log.Fatalf("Server failed: %v", err) + // 4. Обычный HTTPS Сервер (TCP) — обязателен для первого запроса и Alt-Svc + tcpServer := &http.Server{ + Addr: ":443", + Handler: mux, + TLSConfig: cfg, + } + + log.Printf("Starting Server on %s (TCP/UDP 443)", domain) + + // Запускаем TCP сервер в фоне + go func() { + if err := tcpServer.ListenAndServeTLS("", ""); err != nil { + log.Printf("TCP Server error: %v", err) + } + }() + + // Запускаем HTTP/3 сервер (основной поток) + if err := h3Server.ListenAndServe(); err != nil { + log.Fatalf("H3 Server failed: %v", err) } }