Files
go_webtransport/main.go
2026-03-30 17:26:59 +00:00

111 lines
3.6 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"
"crypto/tls"
"fmt"
"io"
"log"
"net/http"
"os"
"github.com/pion/webtransport"
"github.com/quic-go/quic-go/http3"
)
func main() {
// 1. Настройка TLS (обязательно для WebTransport/QUIC)
// Поскольку SSL терминация на VPS, здесь мы используем самоподписанный сертификат
// для внутренней связи (Dokploy <-> Caddy). Nixpacks соберет это.
// Но для простоты примера мы просто слушаем обычный HTTP, так как Caddy проксирует.
// ОДНАКО: WebTransport ТРЕБУЕТ TLS. Внутренний TLS тоже нужен.
// Мы сгенерируем его на лету, чтобы не возиться с файлами.
cert, err := generateSelfSignedCert()
if err != nil {
log.Fatal(err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
NextProtos: []string{"h3"}, // HTTP/3
}
// 2. Настройка WebTransport Handler
server := webtransport.Server{
H3: http3.Server{
Addr: ":8080", // Порт внутри контейнера
TLSConfig: tlsConfig,
},
CheckOrigin: func(r *http.Request) bool { return true }, // Разрешить все Origin для теста
}
// Раздаем index.html
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
})
http.HandleFunc("/wt", func(w http.ResponseWriter, r *http.Request) {
log.Println("New WebTransport request from:", r.RemoteAddr)
sess, err := server.Upgrade(w, r)
if err != nil {
log.Printf("Upgrade failed: %v", err)
return
}
// Обработка сессии в отдельной горутине
go handleSession(sess)
})
log.Println("WebTransport server listening on https://localhost:8080/wt (via Caddy)")
// Запускаем HTTP/3 сервер
if err := server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}
// Обработка одной WebTransport сессии
func handleSession(sess *webtransport.Session) {
defer sess.CloseWithError(0, "session closed")
for {
// Читаем датаграммы (самый быстрый и ненадежный способ, как UDP)
msg, err := sess.ReadDatagram(context.Background())
if err != nil {
if err != io.EOF {
log.Printf("ReadDatagram error: %v", err)
}
return
}
fmt.Printf("Received Datagram from %v: %s\n", sess.RemoteAddr(), string(msg))
}
}
// Вспомогательная функция для генерации внутреннего SSL
// (Для связи Caddy -> Dokploy по Wireguard)
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"time"
)
func generateSelfSignedCert() (tls.Certificate, error) {
priv, _ := rsa.GenerateKey(rand.Reader, 2048)
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{Organization: []string{"Pion WebTransport Test"}},
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour * 24 * 365),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
derBytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
return tls.X509KeyPair(certPEM, keyPEM)
}