mirror of
https://github.com/qdm12/gluetun.git
synced 2026-06-14 23:43:56 +02:00
feat(storage): storage file structure changes (#3301)
- migrate persisted server data storage from `/gluetun/servers.json` to `/gluetun/servers/` - add `STORAGE_SERVERS_ENABLED=on` to enable or disable on-disk server data storage - add `STORAGE_SERVERS_DIRECTORY_PATH=/gluetun/servers` to configure where per-provider server files are stored - keep backward compatibility with legacy `STORAGE_FILEPATH=/gluetun/servers.json` - automatically read and migrate legacy `/gluetun/servers.json` into the new `/gluetun/servers/` layout when needed - try to remove the legacy servers file after a successful migration to the new storage directory - switch persisted server data from one large JSON file to a manifest plus per-provider JSON files - add `UPDATER_PREFER_DIRECT_DOWNLOAD` to allow preferring direct download of provider server data - keep deprecated updater flags `-enduser` and `-maintainer` as no-op warnings for backward compatibility - preserve compatibility checks so persisted server data is discarded when its schema version no longer matches the built-in data - allow preferred persisted provider data to override built-in data when versions match - servers data now lives at https://github.com/qdm12/gluetun-servers/tree/main/pkg/servers
This commit is contained in:
+79
-22
@@ -12,29 +12,30 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// readFromFile reads the servers from server.json.
|
||||
// readFromFile reads the servers data starting from the given manifest file path.
|
||||
// It only reads servers that have the same version as the hardcoded servers version
|
||||
// to avoid JSON decoding errors.
|
||||
func (s *Storage) readFromFile(filepath string, hardcodedVersions map[string]uint16) (
|
||||
servers models.AllServers, err error,
|
||||
func (s *Storage) readFromFile(manifestPath string, hardcodedVersions map[string]uint16) (
|
||||
servers models.AllServers, found bool, err error,
|
||||
) {
|
||||
file, err := os.Open(filepath)
|
||||
file, err := os.Open(manifestPath)
|
||||
if os.IsNotExist(err) {
|
||||
return servers, nil
|
||||
return servers, false, nil
|
||||
} else if err != nil {
|
||||
return servers, err
|
||||
return servers, false, err
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return servers, err
|
||||
return servers, true, err
|
||||
}
|
||||
|
||||
if err := file.Close(); err != nil {
|
||||
return servers, err
|
||||
return servers, true, err
|
||||
}
|
||||
|
||||
return s.extractServersFromBytes(b, hardcodedVersions)
|
||||
servers, err = s.extractServersFromBytes(b, hardcodedVersions)
|
||||
return servers, true, err
|
||||
}
|
||||
|
||||
func (s *Storage) extractServersFromBytes(b []byte, hardcodedVersions map[string]uint16) (
|
||||
@@ -46,6 +47,12 @@ func (s *Storage) extractServersFromBytes(b []byte, hardcodedVersions map[string
|
||||
}
|
||||
|
||||
// Note schema version is at map key "version" as number
|
||||
if rawVersion, ok := rawMessages["version"]; ok {
|
||||
err := json.Unmarshal(rawVersion, &servers.Version)
|
||||
if err != nil {
|
||||
return servers, fmt.Errorf("decoding servers schema version: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
allProviders := providers.All()
|
||||
servers.ProviderToServers = make(map[string]models.Servers, len(allProviders))
|
||||
@@ -86,25 +93,20 @@ func (s *Storage) readServers(provider string, hardcodedVersion uint16,
|
||||
) {
|
||||
provider = titleCaser.String(provider)
|
||||
|
||||
var versionObject struct {
|
||||
Version uint16 `json:"version"`
|
||||
var metadata struct {
|
||||
Version uint16 `json:"version"`
|
||||
Timestamp uint64 `json:"timestamp"`
|
||||
Filepath string `json:"filepath"`
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawMessage, &versionObject)
|
||||
err = json.Unmarshal(rawMessage, &metadata)
|
||||
if err != nil {
|
||||
return servers, false, fmt.Errorf("decoding servers version for provider %s: %w",
|
||||
provider, err)
|
||||
}
|
||||
|
||||
persistedVersion := versionObject.Version
|
||||
|
||||
versionsMatch = hardcodedVersion == persistedVersion
|
||||
if !versionsMatch {
|
||||
s.logger.Info(fmt.Sprintf(
|
||||
"%s servers from file discarded because they have "+
|
||||
"version %d and hardcoded servers have version %d",
|
||||
provider, persistedVersion, hardcodedVersion))
|
||||
return servers, versionsMatch, nil
|
||||
if metadata.Filepath != "" {
|
||||
return s.readServersFromFilepath(provider, metadata.Filepath, hardcodedVersion)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawMessage, &servers)
|
||||
@@ -113,5 +115,60 @@ func (s *Storage) readServers(provider string, hardcodedVersion uint16,
|
||||
provider, err)
|
||||
}
|
||||
|
||||
return servers, versionsMatch, nil
|
||||
const sourcePath = ""
|
||||
if !checkVersions(hardcodedVersion, servers.Version, provider, sourcePath,
|
||||
servers.Preferred, s.logger) {
|
||||
return models.Servers{}, false, nil
|
||||
}
|
||||
|
||||
return servers, true, nil
|
||||
}
|
||||
|
||||
func (s *Storage) readServersFromFilepath(provider, filepath string, hardcodedVersion uint16) (
|
||||
referencedServers models.Servers, versionsMatch bool, err error,
|
||||
) {
|
||||
providerFile, err := os.Open(filepath)
|
||||
if os.IsNotExist(err) {
|
||||
return models.Servers{}, false, nil
|
||||
} else if err != nil {
|
||||
return models.Servers{}, false, fmt.Errorf("opening servers file %s for provider %s: %w",
|
||||
filepath, provider, err)
|
||||
}
|
||||
defer providerFile.Close()
|
||||
|
||||
err = json.NewDecoder(providerFile).Decode(&referencedServers)
|
||||
if err != nil {
|
||||
return models.Servers{}, false, fmt.Errorf("decoding servers file %s for provider %s: %w",
|
||||
filepath, provider, err)
|
||||
}
|
||||
|
||||
if !checkVersions(hardcodedVersion, referencedServers.Version, provider, filepath,
|
||||
referencedServers.Preferred, s.logger) {
|
||||
return models.Servers{}, false, nil
|
||||
}
|
||||
|
||||
referencedServers.Filepath = filepath
|
||||
return referencedServers, true, nil
|
||||
}
|
||||
|
||||
func checkVersions(builtinVersion, version uint16, provider, sourcePath string,
|
||||
preferred bool, logger Logger,
|
||||
) (match bool) {
|
||||
if version == builtinVersion {
|
||||
return true
|
||||
}
|
||||
name := provider
|
||||
log := logger.Info
|
||||
if preferred {
|
||||
name += " preferred"
|
||||
log = logger.Warn
|
||||
}
|
||||
name += " servers"
|
||||
if sourcePath != "" {
|
||||
name += " from file " + sourcePath
|
||||
}
|
||||
log(fmt.Sprintf(
|
||||
"%s discarded because they have version %d and hardcoded servers have version %d",
|
||||
name, version, builtinVersion))
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user