diff --git a/go.mod b/go.mod index f65281e..f2e058e 100644 --- a/go.mod +++ b/go.mod @@ -2,29 +2,12 @@ module qgo go 1.25.0 -require ( - github.com/caddyserver/certmagic v0.25.2 - github.com/quic-go/quic-go v0.59.0 - github.com/quic-go/webtransport-go v0.10.0 -) +require github.com/quic-go/quic-go v0.59.0 require ( - github.com/caddyserver/zerossl v0.1.5 // indirect - github.com/dunglas/httpsfv v1.1.0 // indirect - github.com/klauspost/cpuid/v2 v2.3.0 // indirect - github.com/libdns/libdns v1.1.1 // indirect - github.com/mholt/acmez/v3 v3.1.6 // indirect - github.com/miekg/dns v1.1.72 // indirect github.com/quic-go/qpack v0.6.0 // indirect - github.com/zeebo/blake3 v0.2.4 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.1 // indirect - go.uber.org/zap/exp v0.3.0 // indirect golang.org/x/crypto v0.48.0 // indirect - golang.org/x/mod v0.33.0 // indirect golang.org/x/net v0.50.0 // indirect - golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.42.0 // indirect ) diff --git a/go.sum b/go.sum index b6c16d2..22fb2e7 100644 --- a/go.sum +++ b/go.sum @@ -1,68 +1,22 @@ -code.pfad.fr/check v1.1.0 h1:GWvjdzhSEgHvEHe2uJujDcpmZoySKuHQNrZMfzfO0bE= -code.pfad.fr/check v1.1.0/go.mod h1:NiUH13DtYsb7xp5wll0U4SXx7KhXQVCtRgdC96IPfoM= -github.com/caddyserver/certmagic v0.25.2 h1:D7xcS7ggX/WEY54x0czj7ioTkmDWKIgxtIi2OcQclUc= -github.com/caddyserver/certmagic v0.25.2/go.mod h1:llW/CvsNmza8S6hmsuggsZeiX+uS27dkqY27wDIuBWg= -github.com/caddyserver/zerossl v0.1.5 h1:dkvOjBAEEtY6LIGAHei7sw2UgqSD6TrWweXpV7lvEvE= -github.com/caddyserver/zerossl v0.1.5/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dunglas/httpsfv v1.1.0 h1:Jw76nAyKWKZKFrpMMcL76y35tOpYHqQPzHQiwDvpe54= -github.com/dunglas/httpsfv v1.1.0/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg= -github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= -github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= -github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= -github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh5YzC3JVwU= -github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk= -github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U= -github.com/letsencrypt/pebble/v2 v2.10.0/go.mod h1:Sk8cmUIPcIdv2nINo+9PB4L+ZBhzY+F9A1a/h/xmWiQ= -github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U= -github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= -github.com/mholt/acmez/v3 v3.1.6 h1:eGVQNObP0pBN4sxqrXeg7MYqTOWyoiYpQqITVWlrevk= -github.com/mholt/acmez/v3 v3.1.6/go.mod h1:5nTPosTGosLxF3+LU4ygbgMRFDhbAVpqMI4+a4aHLBY= -github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= -github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= -github.com/quic-go/webtransport-go v0.10.0 h1:LqXXPOXuETY5Xe8ITdGisBzTYmUOy5eSj+9n4hLTjHI= -github.com/quic-go/webtransport-go v0.10.0/go.mod h1:LeGIXr5BQKE3UsynwVBeQrU1TPrbh73MGoC6jd+V7ow= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= -github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= -github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= -github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= -github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= -go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 240b943..6adf668 100644 --- a/main.go +++ b/main.go @@ -1,164 +1,65 @@ package main import ( - "context" - "log" + "crypto/tls" + "fmt" "net/http" - "strings" - "sync" - "github.com/caddyserver/certmagic" "github.com/quic-go/quic-go/http3" - "github.com/quic-go/webtransport-go" + "golang.org/x/crypto/acme/autocert" ) -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 | Total: %d", roomName, len(room.conns)) - - 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) { - defer stream.Close() - 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" - - // 1. Настройка CertMagic - certmagic.DefaultACME.Email = email - certmagic.DefaultACME.Agreed = true - - cfg, err := certmagic.TLS([]string{domain}) - if err != nil { - log.Fatal(err) - } - // Важно для QUIC: устанавливаем NextProtos - cfg.NextProtos = []string{"h3", "h2", "http/1.1"} - - server := NewServer() - - // 2. Инициализация WebTransport сервера - wt := &webtransport.Server{ - CheckOrigin: func(r *http.Request) bool { return true }, + // 1. Настройка менеджера сертификатов + certManager := autocert.Manager{ + Prompt: autocert.AcceptTOS, + HostPolicy: autocert.HostWhitelist("qgo-server.quizer.space"), // ЗАМЕНИТЕ НА ВАШ ДОМЕН + Cache: autocert.DirCache("certs"), // Папка для хранения ключей } mux := http.NewServeMux() - mux.HandleFunc("/room/", func(w http.ResponseWriter, r *http.Request) { - // Сообщаем браузеру о наличии HTTP/3 - w.Header().Set("Alt-Svc", `h3=":443"; ma=86400`) + mux.HandleFunc("/api/hello", func(w http.ResponseWriter, r *http.Request) { + // Добавляем CORS для вашего фронтенда + w.Header().Set("Access-Control-Allow-Origin", "https://your-svelte-app.com") + w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS") + w.Header().Set("Alt-Svc", `h3=":443"; ma=86400`) // Порт 443 стандартный для HTTPS - 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 - } - - w.WriteHeader(http.StatusOK) - w.Write([]byte("Waiting for WebTransport connection...")) + fmt.Printf("Запрос по протоколу: %s\n", r.Proto) + w.Write([]byte(`{"message": "Работает через Let's Encrypt и QUIC!"}`)) }) - // 3. HTTP/3 Сервер (UDP) - h3Server := &http3.Server{ - Addr: ":443", - Handler: mux, - TLSConfig: cfg, - EnableDatagrams: true, - } - wt.H3 = h3Server - - // 4. Обычный HTTPS Сервер (TCP) — обязателен для первого запроса и Alt-Svc - tcpServer := &http.Server{ - Addr: ":443", - Handler: mux, - TLSConfig: cfg, + // Настройка TLS конфигурации для QUIC + tlsConfig := &tls.Config{ + GetCertificate: certManager.GetCertificate, + NextProtos: []string{"h3", "h3-29"}, // Поддержка разных версий HTTP/3 } - log.Printf("Starting Server on %s (TCP/UDP 443)", domain) - - // Запускаем TCP сервер в фоне + // 2. Запуск HTTP/3 (UDP) на порту 443 go func() { - if err := tcpServer.ListenAndServeTLS("", ""); err != nil { - log.Printf("TCP Server error: %v", err) + server := &http3.Server{ + Addr: ":443", + Handler: mux, + TLSConfig: tlsConfig, + } + fmt.Println("Запуск QUIC на :443 UDP...") + if err := server.ListenAndServe(); err != nil { + fmt.Printf("Ошибка QUIC: %v\n", err) } }() - // Запускаем HTTP/3 сервер (основной поток) - if err := h3Server.ListenAndServe(); err != nil { - log.Fatalf("H3 Server failed: %v", err) + // 3. Запуск стандартного HTTPS (TCP) на порту 443 + // Это также необходимо для выдачи сертификатов через ACME + fmt.Println("Запуск HTTPS на :443 TCP...") + httpsServer := &http.Server{ + Addr: ":443", + Handler: mux, + TLSConfig: tlsConfig, + } + + // Важно: для Let's Encrypt также нужен сервер на порту 80 (HTTP) + go http.ListenAndServe(":80", certManager.HTTPHandler(nil)) + + if err := httpsServer.ListenAndServeTLS("", ""); err != nil { + panic(err) } }