Files
qgo-server/main.go
Smile Rex e11593eb06
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m42s
fix3
2026-03-04 01:27:30 +03:00

143 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"context"
"log"
"net/http"
"strings"
"sync"
"github.com/caddyserver/certmagic"
"github.com/quic-go/quic-go/http3"
"github.com/quic-go/webtransport-go"
)
type Room struct {
conns map[*webtransport.Session]bool
mu sync.Mutex
}
type Server struct {
rooms map[string]*Room
mu sync.Mutex
}
func NewServer() *Server {
return &Server{rooms: make(map[string]*Room)}
}
func (s *Server) getRoom(name string) *Room {
s.mu.Lock()
defer s.mu.Unlock()
if room, ok := s.rooms[name]; ok {
return room
}
room := &Room{conns: make(map[*webtransport.Session]bool)}
s.rooms[name] = room
return room
}
func (s *Server) handleSession(roomName string, sess *webtransport.Session) {
room := s.getRoom(roomName)
room.mu.Lock()
room.conns[sess] = true
room.mu.Unlock()
log.Printf("Joined room: %s", roomName)
defer func() {
room.mu.Lock()
delete(room.conns, sess)
room.mu.Unlock()
log.Printf("Left room: %s", roomName)
}()
for {
stream, err := sess.AcceptStream(context.Background())
if err != nil {
return
}
go s.handleStream(room, sess, stream)
}
}
func (s *Server) handleStream(room *Room, sender *webtransport.Session, stream *webtransport.Stream) {
buf := make([]byte, 4096)
for {
n, err := stream.Read(buf)
if err != nil {
return
}
data := append([]byte(nil), buf[:n]...)
room.mu.Lock()
for conn := range room.conns {
if conn == sender {
continue
}
go func(c *webtransport.Session, d []byte) {
out, err := c.OpenStream()
if err != nil {
return
}
defer out.Close()
out.Write(d)
}(conn, data)
}
room.mu.Unlock()
}
}
func main() {
domain := "qgo-server.quizer.space"
email := "serverussnap@outlook.com"
// Настройка CertMagic (как в вашем рабочем коде)
certmagic.DefaultACME.Email = email
certmagic.DefaultACME.Agreed = true
certmagic.Default.Storage = &certmagic.FileStorage{Path: "/root/.local/share/certmagic"}
server := NewServer()
// Настройка 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)
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."))
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)
})
log.Printf("Starting server on %s", domain)
// Используем certmagic.HTTPS, который сам создаст нужный TLSConfig
// и запустит HTTP/3 (UDP) + HTTPS (TCP) корректно.
err := certmagic.HTTPS([]string{domain}, mux)
if err != nil {
log.Fatalf("Server failed: %v", err)
}
}