diff --git a/pkg/streamcontrol/config.go b/pkg/streamcontrol/config.go index d039b4f..9ace2f0 100644 --- a/pkg/streamcontrol/config.go +++ b/pkg/streamcontrol/config.go @@ -151,7 +151,9 @@ func (RawMessage) GetOrder() int { ) } func (RawMessage) IsInitialized() bool { - return false + panic( + "the value is not parsed; don't use the platform config directly, and use function GetPlatformConfig instead", + ) } func (m *RawMessage) UnmarshalJSON(b []byte) error { diff --git a/pkg/streamcontrol/kick/config.go b/pkg/streamcontrol/kick/config.go index 97877d7..ad1dfc4 100644 --- a/pkg/streamcontrol/kick/config.go +++ b/pkg/streamcontrol/kick/config.go @@ -12,6 +12,10 @@ type StreamProfile = kick.StreamProfile type PlatformSpecificConfig = kick.PlatformSpecificConfig type OAuthHandler = kick.OAuthHandler +func init() { + streamctl.RegisterPlatform[PlatformSpecificConfig, StreamProfile](ID) +} + func InitConfig(cfg streamctl.Config) { kick.InitConfig(cfg) } diff --git a/pkg/streamcontrol/obs/config.go b/pkg/streamcontrol/obs/config.go index 4d9dc24..6186303 100644 --- a/pkg/streamcontrol/obs/config.go +++ b/pkg/streamcontrol/obs/config.go @@ -11,6 +11,10 @@ type Config = types.Config type StreamProfile = types.StreamProfile type PlatformSpecificConfig = types.PlatformSpecificConfig +func init() { + streamctl.RegisterPlatform[PlatformSpecificConfig, StreamProfile](ID) +} + func InitConfig(cfg streamctl.Config) { types.InitConfig(cfg) } diff --git a/pkg/streamcontrol/registry.go b/pkg/streamcontrol/registry.go new file mode 100644 index 0000000..6f34394 --- /dev/null +++ b/pkg/streamcontrol/registry.go @@ -0,0 +1,64 @@ +package streamcontrol + +import ( + "fmt" + "reflect" + + "github.com/goccy/go-yaml" +) + +type platformMeta struct { + PlatformSpecificConfig reflect.Type + StreamProfile reflect.Type + Config reflect.Type +} + +var registry = map[PlatformName]platformMeta{} + +func RegisterPlatform[PSC PlatformSpecificConfig, SP StreamProfile](id PlatformName) { + var ( + platCfgSample PSC + profileSample SP + configSample PlatformConfig[PSC, SP] + ) + + if _, ok := registry[id]; ok { + panic(fmt.Errorf("platform '%s' is already registered", id)) + } + + registry[id] = platformMeta{ + PlatformSpecificConfig: reflect.TypeOf(platCfgSample), + StreamProfile: reflect.TypeOf(profileSample), + Config: reflect.TypeOf(configSample), + } +} + +func IsInitialized( + cfg Config, + platID PlatformName, +) bool { + meta := registry[platID] + platCfgCfgTyped := reflect.New(meta.PlatformSpecificConfig).Interface().(PlatformSpecificConfig) + + platCfg := cfg[platID] + var b []byte + switch platCfgCfg := platCfg.Config.(type) { + case RawMessage: + b = platCfgCfg + case *RawMessage: + b = *platCfgCfg + case PlatformSpecificConfig: + return platCfgCfg.IsInitialized() + case nil: + return false + default: + panic(fmt.Errorf("unable to get the config: expected type '%T' or RawMessage, but received type '%T'", platCfgCfgTyped, platCfgCfg)) + } + + err := yaml.Unmarshal(b, platCfgCfgTyped) + if err != nil { + panic(err) + } + + return platCfgCfgTyped.IsInitialized() +} diff --git a/pkg/streamcontrol/registry_test.go b/pkg/streamcontrol/registry_test.go new file mode 100644 index 0000000..297c1c2 --- /dev/null +++ b/pkg/streamcontrol/registry_test.go @@ -0,0 +1,45 @@ +package streamcontrol + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +const mockPlatformID = "mock-platform" + +type mockPlatformSpecificConfig struct { + SomeWackyData []byte +} + +func (mockPlatformSpecificConfig) IsInitialized() bool { + return true +} + +type mockStreamProfile struct { + Hello string +} + +func (mockStreamProfile) GetParent() (ProfileName, bool) { + return "", false +} +func (mockStreamProfile) GetOrder() int { + return 0 +} + +func TestRegistry( + t *testing.T, +) { + RegisterPlatform[mockPlatformSpecificConfig, mockStreamProfile](mockPlatformID) + + cfg := Config{ + mockPlatformID: &AbstractPlatformConfig{ + Enable: ptr(true), + Config: RawMessage("{}"), + StreamProfiles: map[ProfileName]AbstractStreamProfile{}, + Custom: map[string]any{}, + }, + } + + require.True(t, IsInitialized(cfg, mockPlatformID)) +} diff --git a/pkg/streamcontrol/twitch/config.go b/pkg/streamcontrol/twitch/config.go index e874c6c..cd3bb49 100644 --- a/pkg/streamcontrol/twitch/config.go +++ b/pkg/streamcontrol/twitch/config.go @@ -12,6 +12,10 @@ type StreamProfile = twitch.StreamProfile type PlatformSpecificConfig = twitch.PlatformSpecificConfig type OAuthHandler = twitch.OAuthHandler +func init() { + streamctl.RegisterPlatform[PlatformSpecificConfig, StreamProfile](ID) +} + func InitConfig(cfg streamctl.Config) { twitch.InitConfig(cfg) } diff --git a/pkg/streamcontrol/youtube/config.go b/pkg/streamcontrol/youtube/config.go index 0f51326..4c22e2c 100644 --- a/pkg/streamcontrol/youtube/config.go +++ b/pkg/streamcontrol/youtube/config.go @@ -12,6 +12,10 @@ type Config = youtube.Config type StreamProfile = youtube.StreamProfile type PlatformSpecificConfig = youtube.PlatformSpecificConfig +func init() { + streamctl.RegisterPlatform[PlatformSpecificConfig, StreamProfile](ID) +} + func InitConfig(cfg streamctl.Config) { youtube.InitConfig(cfg) } diff --git a/pkg/streamd/stream_controller.go b/pkg/streamd/stream_controller.go index 6653cf1..a6d4239 100644 --- a/pkg/streamd/stream_controller.go +++ b/pkg/streamd/stream_controller.go @@ -25,7 +25,7 @@ func (d *StreamD) EXPERIMENTAL_ReinitStreamControllers(ctx context.Context) (_er logger.Debugf(ctx, "ReinitStreamControllers") defer func() { logger.Debugf(ctx, "/ReinitStreamControllers: %v", _err) }() - return xsync.DoA1R1(ctx, &d.ConfigLock, d.reinitStreamControllers, ctx) + return xsync.DoA1R1(xsync.WithEnableDeadlock(ctx, false), &d.ConfigLock, d.reinitStreamControllers, ctx) } func (d *StreamD) reinitStreamControllers(ctx context.Context) error { @@ -47,7 +47,7 @@ func (d *StreamD) reinitStreamControllers(ctx context.Context) error { continue } - if !platCfg.IsInitialized() { + if !streamcontrol.IsInitialized(d.Config.Backends, platName) { logger.Debugf(ctx, "config of backend '%s' is missing necessary data", platName) continue } diff --git a/pkg/streampanel/panel.go b/pkg/streampanel/panel.go index aa00b7a..419b69f 100644 --- a/pkg/streampanel/panel.go +++ b/pkg/streampanel/panel.go @@ -404,6 +404,7 @@ func (p *Panel) initStreamDConfig( if platCfg.IsInitialized() { continue } + logger.Debugf(ctx, "'%s' is not initialized: %#+v, fixing", platName, platCfg) configHasChanged = true err := p.inputUserInfo(ctx, cfg, platName) @@ -917,7 +918,7 @@ func (p *Panel) openBrowser( errmon.ObserveErrorCtx(ctx, err) } - logger.Debugf(ctx, "openBrowser(ctx, '%s', '%s'): resulting command '%s %s'", browserCmd, urlString) + logger.Debugf(ctx, "openBrowser(ctx, '%s', '%s'): resulting command '%s %s'", urlString, reason, browserCmd, urlString) return exec.Command(browserCmd, urlString).Start() }