diff --git a/internal/config/data/config.example.yml b/internal/config/data/config.example.yml new file mode 100644 index 0000000..24065dd --- /dev/null +++ b/internal/config/data/config.example.yml @@ -0,0 +1,24 @@ +# Octoplex is a live stream multiplexer. +--- +# +sources: + # Currently the only source type is RTMP server. + rtmp: + enabled: yes + # Your local stream key. Defaults to "live". + # + # rtmp://localhost:1935/live + streamkey: live +# +logfile: + # Change to yes to log to system location. + enabled: no + # Or, log to this absolute path: + # path: octoplex.log +# +# Define your destinations here. +destinations: + # - name: YouTube + # url: rtmp://rtmp.youtube.com/myYoutubeStreamKey + # - name: Twitch + # url: rtmp://ingest.global-contribute.live-video.net/app/myTwitchStreamKey diff --git a/internal/config/service.go b/internal/config/service.go index 9efc9b5..e0cbce8 100644 --- a/internal/config/service.go +++ b/internal/config/service.go @@ -1,6 +1,7 @@ package config import ( + _ "embed" "errors" "fmt" "os" @@ -11,6 +12,9 @@ import ( "gopkg.in/yaml.v3" ) +//go:embed data/config.example.yml +var exampleConfig []byte + // Service provides configuration services. type Service struct { userConfigDir string @@ -85,23 +89,16 @@ func (s *Service) readConfig() (cfg Config, _ error) { return cfg, nil } -func (s *Service) createConfig() (cfg Config, _ error) { +func (s *Service) createConfig() (Config, error) { if err := os.MkdirAll(s.appConfigDir, 0744); err != nil { - return cfg, fmt.Errorf("mkdir: %w", err) + return Config{}, fmt.Errorf("mkdir: %w", err) } - s.setDefaults(&cfg) - - yamlBytes, err := yaml.Marshal(cfg) - if err != nil { - return cfg, fmt.Errorf("marshal: %w", err) + if err := os.WriteFile(s.Path(), exampleConfig, 0644); err != nil { + return Config{}, fmt.Errorf("write file: %w", err) } - if err = os.WriteFile(s.Path(), yamlBytes, 0644); err != nil { - return cfg, fmt.Errorf("write file: %w", err) - } - - return cfg, nil + return Config{}, nil } func (s *Service) Path() string { diff --git a/internal/config/service_test.go b/internal/config/service_test.go index ffcded5..dce8538 100644 --- a/internal/config/service_test.go +++ b/internal/config/service_test.go @@ -33,16 +33,23 @@ var configMultipleInvalidDestinationURLs []byte func TestConfigServiceCreateConfig(t *testing.T) { suffix := "read_or_create_" + shortid.New().String() - service, err := config.NewService(configDirFunc(suffix)) + systemConfigDirFunc := buildSystemConfigDirFunc(suffix) + systemConfigDir, _ := systemConfigDirFunc() + + service, err := config.NewService(systemConfigDirFunc) require.NoError(t, err) + t.Cleanup(func() { require.NoError(t, os.RemoveAll(systemConfigDir)) }) + cfg, err := service.ReadOrCreateConfig() require.NoError(t, err) require.Empty(t, cfg.LogFile, "expected no log file") - p := filepath.Join(configDir(suffix), "config.yaml") - _, err = os.Stat(p) + p := filepath.Join(systemConfigDir, "octoplex", "config.yaml") + cfgBytes, err := os.ReadFile(p) require.NoError(t, err, "config file was not created") + // Ensure the example config file is written: + assert.Contains(t, string(cfgBytes), "# Octoplex is a live stream multiplexer.") } func TestConfigServiceReadConfig(t *testing.T) { @@ -114,12 +121,17 @@ func TestConfigServiceReadConfig(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { suffix := "read_or_create_" + shortid.New().String() - dir := configDir(suffix) - require.NoError(t, os.MkdirAll(dir, 0744)) - configPath := filepath.Join(dir, "config.yaml") + systemConfigDirFunc := buildSystemConfigDirFunc(suffix) + systemConfigDir, _ := systemConfigDirFunc() + appConfigDir := buildAppConfigDir(suffix) + + require.NoError(t, os.MkdirAll(appConfigDir, 0744)) + t.Cleanup(func() { require.NoError(t, os.RemoveAll(systemConfigDir)) }) + + configPath := filepath.Join(appConfigDir, "config.yaml") require.NoError(t, os.WriteFile(configPath, tc.configBytes, 0644)) - service, err := config.NewService(configDirFunc(suffix)) + service, err := config.NewService(buildSystemConfigDirFunc(suffix)) require.NoError(t, err) cfg, err := service.ReadOrCreateConfig() @@ -134,11 +146,15 @@ func TestConfigServiceReadConfig(t *testing.T) { } } -func configDir(suffix string) string { +// buildAppConfigDir returns a temporary directory which mimics +// $XDG_CONFIG_HOME/octoplex. +func buildAppConfigDir(suffix string) string { return filepath.Join(os.TempDir(), "config_test_"+suffix, "octoplex") } -func configDirFunc(suffix string) func() (string, error) { +// buildSystemConfigDirFunc returns a function that creates a temporary +// directory which mimics $XDG_CONFIG_HOME. +func buildSystemConfigDirFunc(suffix string) func() (string, error) { return func() (string, error) { return filepath.Join(os.TempDir(), "config_test_"+suffix), nil }