Serialize configuration updates and writes

This commit is contained in:
Brandon McGinty (chatgpt)
2026-08-10 00:18:42 -04:00
committed by Brandon McGinty
parent 874cbb7818
commit 118799d112
2 changed files with 46 additions and 2 deletions
+28 -2
View File
@@ -10,9 +10,11 @@ import (
"os"
"strconv"
"strings"
"sync"
)
type Config struct {
mu sync.Mutex
config *exportableConfig
fn string
}
@@ -49,6 +51,12 @@ type eUser struct {
// SaveConfig atomically replaces the persisted configuration. Errors are
// returned so an unavailable directory cannot crash the client.
func (c *Config) SaveConfig() error {
c.mu.Lock()
defer c.mu.Unlock()
return c.saveConfigLocked()
}
func (c *Config) saveConfigLocked() error {
data, err := toml.Marshal(c.config)
if err != nil {
return err
@@ -254,18 +262,24 @@ func (c *Config) findUser(address string, username string) *eUser {
}
func (c *Config) ToggleMute(u *gumble.User) {
c.mu.Lock()
defer c.mu.Unlock()
j := c.findUser(u.GetClient().Config.Address, u.Name)
j.LocallyMuted = !j.LocallyMuted
u.SetLocallyMuted(j.LocallyMuted)
c.SaveConfig()
_ = c.saveConfigLocked()
}
func (c *Config) SetMicVolume(v float32) {
c.mu.Lock()
defer c.mu.Unlock()
t := float32(v)
c.config.MicVolume = &t
}
func (c *Config) GetMicVolume() float32 {
c.mu.Lock()
defer c.mu.Unlock()
if c.config.MicVolume == nil {
return 1.0
}
@@ -308,6 +322,8 @@ func (c *Config) GetCertificate() *string {
}
func (c *Config) GetNoiseSuppressionEnabled() bool {
c.mu.Lock()
defer c.mu.Unlock()
if c.config.NoiseSuppressionEnabled == nil {
return false
}
@@ -315,11 +331,15 @@ func (c *Config) GetNoiseSuppressionEnabled() bool {
}
func (c *Config) SetNoiseSuppressionEnabled(enabled bool) {
c.mu.Lock()
defer c.mu.Unlock()
c.config.NoiseSuppressionEnabled = &enabled
c.SaveConfig()
_ = c.saveConfigLocked()
}
func (c *Config) GetRecordingFormat() string {
c.mu.Lock()
defer c.mu.Unlock()
if c.config.RecordingFormat == nil {
return "flac"
}
@@ -327,6 +347,8 @@ func (c *Config) GetRecordingFormat() string {
}
func (c *Config) GetRecordingDirectory() string {
c.mu.Lock()
defer c.mu.Unlock()
if c.config.RecordingDirectory == nil {
return resolvePath("~/Audio")
}
@@ -334,6 +356,8 @@ func (c *Config) GetRecordingDirectory() string {
}
func (c *Config) UpdateUser(u *gumble.User) {
c.mu.Lock()
defer c.mu.Unlock()
var j *eUser
var uc *gumble.Client
uc = u.GetClient()
@@ -349,6 +373,8 @@ func (c *Config) UpdateUser(u *gumble.User) {
}
func (c *Config) UpdateConfig(u *gumble.User) {
c.mu.Lock()
defer c.mu.Unlock()
var j *eUser
j = c.findUser(u.GetClient().Config.Address, u.Name)
j.Boost = u.Boost()
+18
View File
@@ -2,6 +2,7 @@ package config
import (
"path/filepath"
"sync"
"testing"
)
@@ -14,3 +15,20 @@ func TestSaveConfigReturnsWriteError(t *testing.T) {
t.Fatal("expected configuration write error")
}
}
func TestConcurrentConfigurationUpdatesAndWrites(t *testing.T) {
path := filepath.Join(t.TempDir(), "barnard.toml")
cfg := NewConfig(&path)
var wg sync.WaitGroup
for i := 0; i < 20; i++ {
wg.Add(1)
go func(enabled bool) {
defer wg.Done()
cfg.SetNoiseSuppressionEnabled(enabled)
if err := cfg.SaveConfig(); err != nil {
t.Errorf("SaveConfig: %v", err)
}
}(i%2 == 0)
}
wg.Wait()
}