package cloudflare import ( "context" "fmt" "sync-live/gen" ) // Provider 暴露 Cloudflare Realtime 后端的能力信息,并持有底层 REST 客户端。 type Provider struct { client *Client appID string stun string configured bool } func NewProvider(appID, appSecret, baseURL, stun string) *Provider { return &Provider{ client: NewClient(appID, appSecret, baseURL), appID: appID, stun: stun, configured: appID != "" && appSecret != "", } } func (p *Provider) Name() string { return "cloudflare" } func (p *Provider) Primary() bool { return true } func (p *Provider) Configured() bool { return p.configured } func (p *Provider) Kind() string { return "cf" } func (p *Provider) Forward(ctx context.Context, room, stream string) (*ForwardResult, error) { if !p.configured { return nil, fmt.Errorf("cloudflare not configured") } if room == "" || stream == "" { return nil, fmt.Errorf("room and stream required") } // Stub: actual relay would create a CF session and push stream via WHIP/tracks. // Return forwarding status with a placeholder URL that frontend can use to detect readiness. return &ForwardResult{Kind: "cf", URL: fmt.Sprintf("/api/cf/forward/%s", stream), Status: "forwarding"}, nil } type ForwardResult struct { Kind string URL string Status string } func (p *Provider) Client() *Client { return p.client } func (p *Provider) AppID() string { return p.appID } func (p *Provider) Stun() string { if p.stun == "" { return "stun:stun.cloudflare.com:3478" } return p.stun } func (p *Provider) ApplyConfig(appID, appSecret, baseURL, stun string) { p.appID = appID // recreate client with new credentials/base p.client = NewClient(appID, appSecret, baseURL) if stun != "" { p.stun = stun } p.configured = appID != "" && appSecret != "" } func (p *Provider) BackendInfo() *gen.BackendInfo { return &gen.BackendInfo{ Kind: gen.BackendKind_BACKEND_KIND_CLOUDFLARE, Name: "Cloudflare Realtime", Configured: p.configured, Primary: true, } }