live-sfu-demo/internal/server/server.go

92 lines
2.7 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 server
import (
"bytes"
"embed"
"io/fs"
"net"
"net/http"
"time"
"google.golang.org/grpc"
"gospeak-live-sfu-demo/gen"
"gospeak-live-sfu-demo/internal/config"
"gospeak-live-sfu-demo/internal/sfu/cloudflare"
"gospeak-live-sfu-demo/internal/sfu/srs"
)
//go:embed static
var staticFS embed.FS
// Server 聚合控制面(gRPC + JSON 网关)、媒体面反向代理与静态 UI。
type Server struct {
cfg *config.Config
svc *Service
hub *roomHub
srsProxy http.Handler
cfProxy http.Handler
}
func New(cfg *config.Config) *Server {
hub := newRoomHub()
cf := cloudflare.NewProvider(cfg.CFAppID, cfg.CFAppSecret, cfg.CFBaseURL, cfg.CFStunURL)
srsP := srs.NewProvider(cfg.SRSBaseURL, cfg.SRSApp, cfg.SRSSecret, cfg.SRSCandidate)
svc := NewService(cfg, cf, srsP, hub)
s := &Server{cfg: cfg, svc: svc, hub: hub}
s.srsProxy = s.srsProxyHandler()
s.cfProxy = s.cfProxyHandler()
return s
}
// StartGRPC 启动 gRPC 控制面(protobuf 契约的服务端实现)。
func (s *Server) StartGRPC() error {
lis, err := net.Listen("tcp", ":"+s.cfg.GRPCPort)
if err != nil {
return err
}
gs := grpc.NewServer()
gen.RegisterLiveSFUServer(gs, NewGRPCServer(s.svc))
go func() { _ = gs.Serve(lis) }()
return nil
}
// Handler 返回 HTTP 路由:静态 UI、JSON 网关、SSE、SRS/Cloudflare 媒体反代。
func (s *Server) Handler() http.Handler {
mux := http.NewServeMux()
sub, _ := fs.Sub(staticFS, "static")
mux.Handle("GET /", s.fileServer("static/index.html"))
mux.Handle("GET /publish", s.fileServer("static/publish.html"))
mux.Handle("GET /watch", s.fileServer("static/watch.html"))
mux.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.FS(sub))))
mux.HandleFunc("GET /api/config", s.handleConfig)
mux.HandleFunc("GET /api/rooms", s.handleRooms)
mux.HandleFunc("POST /api/publish", s.handlePublish)
mux.HandleFunc("POST /api/subscribe", s.handleSubscribe)
mux.HandleFunc("POST /api/stop", s.handleStop)
mux.HandleFunc("GET /api/srs/streams", s.handleSRSStreams)
mux.Handle("GET /api/room/{room}/events", http.HandlerFunc(s.handleRoomEvents))
mux.Handle("GET /rtc/v1/", s.srsProxy)
mux.Handle("POST /rtc/v1/", s.srsProxy)
mux.Handle("PUT /rtc/v1/", s.srsProxy)
mux.Handle("DELETE /rtc/v1/", s.srsProxy)
mux.Handle("GET /api/cf/", s.cfProxy)
mux.Handle("POST /api/cf/", s.cfProxy)
mux.Handle("PUT /api/cf/", s.cfProxy)
mux.Handle("DELETE /api/cf/", s.cfProxy)
return mux
}
func (s *Server) fileServer(name string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
data, err := staticFS.ReadFile(name)
if err != nil {
http.Error(w, "not found", http.StatusNotFound)
return
}
http.ServeContent(w, r, name, time.Time{}, bytes.NewReader(data))
}
}