mirror of
https://github.com/qdm12/gluetun.git
synced 2026-05-07 04:20:12 +02:00
25f67cd170
- new directory structure containing manifest.json and one json file per provider, by default. - the manifest.json file can specify a filepath for each vpn provider - each vpn provider json data file can contain the `"preferred": true` field to enforce it is used even if outdated, unless there is a version mismatch - `STORAGE_SERVERS_DIRECTORY_PATH` replaces `STORAGE_FILEPATH` (which is now a migration source only). It sets the directory where server manifest and per-provider JSON files are stored (default: `/gluetun/servers/`). - First-run migration: On startup, gluetun checks for the old /gluetun/servers.json file; if found and no new manifest exists, it automatically migrates all data to /gluetun/servers/ directory structure - Silent fallback: If legacy file isn't found, uses the new directory path normally - Legacy cleanup: After successful migration, attempts to remove the old fat JSON file (logs warning only if removal fails, e.g., read-only bind mounts) Co-authored-by: Copilot <copilot@github.com>
83 lines
2.4 KiB
Go
83 lines
2.4 KiB
Go
package storage
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
|
|
"github.com/qdm12/gluetun/internal/models"
|
|
)
|
|
|
|
func countServers(allServers models.AllServers) (count int) {
|
|
for _, servers := range allServers.ProviderToServers {
|
|
count += len(servers.Servers)
|
|
}
|
|
return count
|
|
}
|
|
|
|
// syncServers merges the hardcoded servers with the ones from on disk files.
|
|
// It assumes s.directoryPath is set.
|
|
func (s *Storage) syncServers() (err error) {
|
|
hardcodedVersions := make(map[string]uint16, len(s.hardcodedServers.ProviderToServers))
|
|
for provider, servers := range s.hardcodedServers.ProviderToServers {
|
|
hardcodedVersions[provider] = servers.Version
|
|
}
|
|
|
|
sourceManifestPath := filepath.Join(s.directoryPath, manifestFilename)
|
|
destinationManifestPath := sourceManifestPath
|
|
serversOnFile, found, err := s.readFromFile(sourceManifestPath, hardcodedVersions)
|
|
if err != nil {
|
|
return fmt.Errorf("reading servers from file: %w", err)
|
|
}
|
|
|
|
hasLegacy := s.hasLegacy()
|
|
if !found && hasLegacy {
|
|
sourceManifestPath = s.legacyFilepath
|
|
s.logger.Infof("reading legacy servers file %s and migrating it to directory %s", sourceManifestPath, s.directoryPath)
|
|
serversOnFile, _, err = s.readFromFile(sourceManifestPath, hardcodedVersions)
|
|
if err != nil {
|
|
return fmt.Errorf("reading servers from file: %w", err)
|
|
}
|
|
}
|
|
|
|
hardcodedCount := countServers(s.hardcodedServers)
|
|
countOnFile := countServers(serversOnFile)
|
|
|
|
s.mergedMutex.Lock()
|
|
defer s.mergedMutex.Unlock()
|
|
|
|
if countOnFile == 0 {
|
|
s.logger.Info(fmt.Sprintf(
|
|
"writing servers data files to %s with %d hardcoded servers",
|
|
s.directoryPath, hardcodedCount))
|
|
s.mergedServers = s.hardcodedServers
|
|
} else {
|
|
s.logger.Info(fmt.Sprintf(
|
|
"merging by most recent %d hardcoded servers and %d servers read from manifest file %s",
|
|
hardcodedCount, countOnFile, sourceManifestPath))
|
|
|
|
s.mergedServers = s.mergeServers(s.hardcodedServers, serversOnFile)
|
|
}
|
|
|
|
// Eventually write file
|
|
if reflect.DeepEqual(serversOnFile, s.mergedServers) {
|
|
return nil
|
|
}
|
|
|
|
err = s.flushToFile(destinationManifestPath)
|
|
if err != nil {
|
|
s.logger.Warn("failed writing servers to destination manifest: " + err.Error())
|
|
return nil
|
|
}
|
|
|
|
migratedFromLegacy := hasLegacy && sourceManifestPath == s.legacyFilepath
|
|
if migratedFromLegacy {
|
|
err = os.Remove(sourceManifestPath)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
s.logger.Warn("failed removing legacy servers file " + sourceManifestPath + ": " + err.Error())
|
|
}
|
|
}
|
|
return nil
|
|
}
|