delete moq, create transport rooms
All checks were successful
Create and publish a Docker image 🚀 / build-and-push-image (push) Successful in 1m48s

This commit is contained in:
Smile Rex
2026-03-04 00:34:43 +03:00
parent c2163436a4
commit 49086f7322
6 changed files with 148 additions and 194 deletions

View File

@@ -1,57 +0,0 @@
package main
import (
"crypto/tls"
"log/slog"
"strings"
"github.com/caddyserver/certmagic"
"github.com/okdaichi/gomoqt/moqt"
"qgo/internal/relay"
)
func main() {
domain := "qgo-server.quizer.space"
email := "serverussnap@outlook.com"
certmagic.DefaultACME.Email = email
certmagic.DefaultACME.Agreed = true
certmagic.Default.Storage = &certmagic.FileStorage{
Path: "/root/.local/share/certmagic",
}
tlsConf, err := certmagic.TLS([]string{domain})
if err != nil {
slog.Error("TLS failed", "err", err)
return
}
tlsConf.NextProtos = []string{"h3"}
tlsConf.MinVersion = tls.VersionTLS13
relayServer := relay.New()
moqt.HandleFunc("/relay/", func(w moqt.SetupResponseWriter, r *moqt.SetupRequest) {
room := strings.TrimPrefix(r.Path, "/relay/")
mux := relayServer.GetMux(room)
_, err := moqt.Accept(w, r, mux)
if err != nil {
slog.Error("accept failed", "err", err)
w.Reject(moqt.InternalSessionErrorCode)
return
}
slog.Info("session connected", "room", room)
})
slog.Info("Mini-SFU running",
"url", "https://"+domain+"/relay/{room}",
)
if err := moqt.ListenAndServe(":443", tlsConf); err != nil {
slog.Error("server failed", "err", err)
}
}

10
go.mod
View File

@@ -4,23 +4,18 @@ go 1.25.0
require (
github.com/caddyserver/certmagic v0.25.2
github.com/okdaichi/gomoqt v0.10.7
github.com/quic-go/quic-go v0.59.0
github.com/quic-go/webtransport-go v0.10.0
)
require (
github.com/caddyserver/zerossl v0.1.5 // indirect
github.com/davecgh/go-spew v1.1.1 // 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/pmezard/go-difflib v1.0.0 // indirect
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/quic-go/webtransport-go v0.10.0 // indirect
github.com/stretchr/objx v0.5.3 // indirect
github.com/stretchr/testify v1.11.1 // 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
@@ -32,5 +27,4 @@ require (
golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.34.0 // indirect
golang.org/x/tools v0.42.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

13
go.sum
View File

@@ -14,10 +14,6 @@ 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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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=
@@ -28,8 +24,6 @@ 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/okdaichi/gomoqt v0.10.7 h1:+2fEG8BgBkPPvUorwpaWd9k4IZrtUx+Nr4EDuz8BpYc=
github.com/okdaichi/gomoqt v0.10.7/go.mod h1:a85xgBn+vYbsWTn+cH7YQlnmvSE5m8XptIbP1wEz9v0=
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=
@@ -38,10 +32,6 @@ github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SA
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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
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=
@@ -74,8 +64,5 @@ 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/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -1,31 +0,0 @@
package relay
import (
"sync"
"github.com/okdaichi/gomoqt/moqt"
)
type Relay struct {
mu sync.RWMutex
rooms map[string]*moqt.TrackMux
}
func New() *Relay {
return &Relay{
rooms: make(map[string]*moqt.TrackMux),
}
}
func (r *Relay) GetMux(room string) *moqt.TrackMux {
r.mu.Lock()
defer r.mu.Unlock()
if mux, ok := r.rooms[room]; ok {
return mux
}
mux := moqt.NewTrackMux()
r.rooms[room] = mux
return mux
}

146
main.go Normal file
View File

@@ -0,0 +1,146 @@
package main
import (
"context"
"crypto/tls"
"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.Println("joined room:", roomName)
defer func() {
room.mu.Lock()
delete(room.conns, sess)
room.mu.Unlock()
log.Println("left room:", 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
}
room.mu.Lock()
for conn := range room.conns {
if conn == sender {
continue
}
go func(c *webtransport.Session) {
out, err := c.OpenStream()
if err != nil {
return
}
defer out.Close()
out.Write(buf[:n])
}(conn)
}
room.mu.Unlock()
}
}
func main() {
domain := "qgo-server.quizer.space"
email := "serverussnap@outlook.com"
certmagic.DefaultACME.Email = email
certmagic.DefaultACME.Agreed = true
certmagic.Default.Storage = &certmagic.FileStorage{
Path: "/root/.local/share/certmagic",
}
tlsConf, err := certmagic.TLS([]string{domain})
if err != nil {
log.Fatal(err)
}
tlsConf.NextProtos = []string{"h3"}
tlsConf.MinVersion = tls.VersionTLS13
server := NewServer()
mux := http.NewServeMux()
wtServer := &webtransport.Server{
H3: &http3.Server{
Addr: ":443",
TLSConfig: tlsConf,
},
}
mux.HandleFunc("/room/", func(w http.ResponseWriter, r *http.Request) {
roomName := strings.TrimPrefix(r.URL.Path, "/room/")
sess, err := wtServer.Upgrade(w, r)
if err != nil {
log.Println("upgrade error:", err)
return
}
go server.handleSession(roomName, sess)
})
wtServer.H3.Handler = mux
log.Println("Relay running on https://" + domain + "/room/{room}")
log.Fatal(wtServer.ListenAndServe())
}

View File

@@ -1,85 +0,0 @@
package main
import (
"crypto/tls"
"fmt"
"log/slog"
"net/http"
"github.com/caddyserver/certmagic"
"github.com/okdaichi/gomoqt/moqt"
"github.com/okdaichi/gomoqt/quic"
)
func main() {
domain := "qgo-server.quizer.space"
email := "serverussnap@outlook.com"
// 1. Настройка CertMagic
certmagic.DefaultACME.Email = email
certmagic.DefaultACME.Agreed = true
certmagic.Default.Storage = &certmagic.FileStorage{Path: "/root/.local/share/certmagic"}
// Создаем TLS конфигурацию
tlsConfig, err := certmagic.TLS([]string{domain})
if err != nil {
slog.Error("failed to setup TLS", "error", err)
return
}
// Поддержка протоколов для браузера и MoQ
tlsConfig.NextProtos = []string{"h3"}
tlsConfig.MinVersion = tls.VersionTLS13
// 2. Инициализация MoQ сервера
moqServer := moqt.Server{
Addr: ":443",
TLSConfig: tlsConfig,
QUICConfig: &quic.Config{
Allow0RTT: true,
EnableDatagrams: true,
},
}
path := "/relay"
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Alt-Svc", `h3=":443"; ma=2592000`)
if r.URL.Path == path {
err := moqServer.HandleWebTransport(w, r)
if err != nil {
slog.Error("WebTransport error", "error", err)
}
return
}
fmt.Fprintf(w, "MoQ Server is active at %s", path)
})
moqt.HandleFunc(path, func(w moqt.SetupResponseWriter, r *moqt.SetupRequest) {
sess, err := moqt.Accept(w, r, nil)
if err != nil {
return
}
go handleSession(sess)
})
slog.Info("Starting MoQ server", "url", "https://"+domain)
go func() {
err := certmagic.HTTPS([]string{domain}, http.DefaultServeMux)
if err != nil {
slog.Error("TCP/HTTPS Server failed", "error", err)
}
}()
if err := moqServer.ListenAndServe(); err != nil {
slog.Error("MoQ UDP Server failed", "error", err)
}
}
func handleSession(sess *moqt.Session) {
slog.Info("MoQ session established", "remote", sess.RemoteAddr())
<-sess.Context().Done()
slog.Info("MoQ session closed")
}