- Simplify formatting CLI - Simplify updater code - Simplify filter choices for config validation - Simplify all servers deep copying - Custom JSON marshaling methods for `AllServers` - Simplify provider constructor switch - Simplify storage merging - Simplify storage reading and extraction - Simplify updating code
101 lines
2.8 KiB
Go
101 lines
2.8 KiB
Go
package storage
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/qdm12/gluetun/internal/constants/providers"
|
|
"github.com/qdm12/gluetun/internal/models"
|
|
)
|
|
|
|
// 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))
|
|
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)
|
|
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) (servers models.Servers, versionsMatch bool, err error) {
|
|
provider = strings.Title(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
|
|
}
|