100 lines
2.1 KiB
Go
100 lines
2.1 KiB
Go
package warp
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/adriancable/webtransport-go"
|
|
"github.com/kixelated/invoker"
|
|
"github.com/lucas-clemente/quic-go"
|
|
"github.com/lucas-clemente/quic-go/logging"
|
|
"github.com/lucas-clemente/quic-go/qlog"
|
|
)
|
|
|
|
type Server struct {
|
|
inner *webtransport.Server
|
|
media *Media
|
|
socket *Socket
|
|
|
|
sessions invoker.Tasks
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
Addr string
|
|
CertFile string
|
|
KeyFile string
|
|
LogDir string
|
|
}
|
|
|
|
func NewServer(config ServerConfig, media *Media) (s *Server, err error) {
|
|
s = new(Server)
|
|
|
|
// Listen using a custom socket that simulates congestion.
|
|
s.socket, err = NewSocket(config.Addr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create socket: %w", err)
|
|
}
|
|
|
|
quicConfig := &quic.Config{}
|
|
|
|
if config.LogDir != "" {
|
|
quicConfig.Tracer = qlog.NewTracer(func(p logging.Perspective, connectionID []byte) io.WriteCloser {
|
|
path := fmt.Sprintf("%s-%s.qlog", p, hex.EncodeToString(connectionID))
|
|
|
|
f, err := os.Create(filepath.Join(config.LogDir, path))
|
|
if err != nil {
|
|
// lame
|
|
panic(err)
|
|
}
|
|
|
|
return f
|
|
})
|
|
}
|
|
|
|
s.inner = &webtransport.Server{
|
|
Listen: s.socket,
|
|
TLSCert: webtransport.CertFile{Path: config.CertFile},
|
|
TLSKey: webtransport.CertFile{Path: config.KeyFile},
|
|
QuicConfig: quicConfig,
|
|
}
|
|
|
|
s.media = media
|
|
|
|
http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
|
|
session, ok := r.Body.(*webtransport.Session)
|
|
if !ok {
|
|
log.Print("http requests not supported")
|
|
return
|
|
}
|
|
|
|
ss, err := NewSession(session, s.media, s.socket)
|
|
if err != nil {
|
|
// TODO handle better?
|
|
log.Printf("failed to create warp session: %v", err)
|
|
return
|
|
}
|
|
|
|
// Run the session in parallel, logging errors instead of crashing
|
|
s.sessions.Add(func(ctx context.Context) (err error) {
|
|
err = ss.Run(ctx)
|
|
if err != nil {
|
|
log.Printf("terminated session: %s", err)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
})
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func (s *Server) Run(ctx context.Context) (err error) {
|
|
return invoker.Run(ctx, s.inner.Run, s.socket.Run, s.sessions.Repeat)
|
|
}
|