feat(config): create example configuration file on first launch

This commit is contained in:
Rob Watson 2025-03-25 21:19:15 +01:00
parent f6b893d89c
commit b508632e70
3 changed files with 58 additions and 21 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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
}