Files
gluetun/internal/storage/read.go
Quentin McGaw 4bde50fb3a chore(all): use casers instead of strings.Title
- Add `golang.org/x/text` dependency
- Update code to use `cases.Title(language.English)`
2022-05-27 16:29:41 +00:00

104 lines
3.0 KiB
Go

package storage
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"github.com/qdm12/gluetun/internal/constants/providers"
"github.com/qdm12/gluetun/internal/models"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
// readFromFile reads the servers from server.json.
// It only reads servers that have the same version as the hardcoded servers version
// to avoid JSON unmarshaling errors.
func (s *Storage) readFromFile(filepath string, hardcoded models.AllServers) (
servers models.AllServers, err error) {
file, err := os.Open(filepath)
if os.IsNotExist(err) {
return servers, nil
} else if err != nil {
return servers, err
}
b, err := io.ReadAll(file)
if err != nil {
return servers, err
}
if err := file.Close(); err != nil {
return servers, err
}
return s.extractServersFromBytes(b, hardcoded)
}
func (s *Storage) extractServersFromBytes(b []byte, hardcoded models.AllServers) (
servers models.AllServers, err error) {
rawMessages := make(map[string]json.RawMessage)
if err := json.Unmarshal(b, &rawMessages); err != nil {
return servers, fmt.Errorf("cannot decode servers: %w", err)
}
// Note schema version is at map key "version" as number
allProviders := providers.All()
servers.ProviderToServers = make(map[string]models.Servers, len(allProviders))
titleCaser := cases.Title(language.English)
for _, provider := range allProviders {
hardcoded, ok := hardcoded.ProviderToServers[provider]
if !ok {
panic(fmt.Sprintf("provider %s not found in hardcoded servers map", provider))
}
rawMessage, ok := rawMessages[provider]
if !ok {
// If the provider is not found in the data bytes, just don't set it in
// the providers map. That way the hardcoded servers will override them.
// This is user provided and could come from different sources in the
// future (e.g. a file or API request).
continue
}
mergedServers, versionsMatch, err := s.readServers(provider, hardcoded, rawMessage, titleCaser)
if err != nil {
return models.AllServers{}, err
} else if !versionsMatch {
// mergedServers is the empty struct in this case, so don't set the key
// in the providerToServers map.
continue
}
servers.ProviderToServers[provider] = mergedServers
}
return servers, nil
}
var (
errDecodeProvider = errors.New("cannot decode servers for provider")
)
func (s *Storage) readServers(provider string, hardcoded models.Servers,
rawMessage json.RawMessage, titleCaser cases.Caser) (servers models.Servers,
versionsMatch bool, err error) {
provider = titleCaser.String(provider)
var persistedServers models.Servers
err = json.Unmarshal(rawMessage, &persistedServers)
if err != nil {
return servers, false, fmt.Errorf("%w: %s: %s", errDecodeProvider, provider, err)
}
versionsMatch = hardcoded.Version == persistedServers.Version
if !versionsMatch {
s.logVersionDiff(provider, hardcoded.Version, persistedServers.Version)
return servers, versionsMatch, nil
}
return persistedServers, versionsMatch, nil
}