Files
elmprodvpn/selective-vpn-api/app/transport_singbox_dns_migration_apply.go

68 lines
1.7 KiB
Go

package app
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
)
func transportMaybeMigrateSingBoxDNSConfig(client TransportClient) (string, error) {
if client.Kind != TransportClientSingBox {
return "", nil
}
if !transportSingBoxDNSMigrationEnabled(client) {
return "", nil
}
path := transportSingBoxConfigPath(client)
if path == "" {
return "", nil
}
data, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("read singbox config failed: %w", err)
}
var root map[string]any
if err := json.Unmarshal(data, &root); err != nil {
return "", fmt.Errorf("parse singbox config failed: %w", err)
}
changed, warnings := transportMigrateSingBoxDNSConfigMap(root)
if !changed {
if len(warnings) == 0 {
return "", nil
}
return "", errors.New(strings.Join(warnings, "; "))
}
backup := path + ".legacy-dns.bak"
if _, err := os.Stat(backup); os.IsNotExist(err) {
if writeErr := os.WriteFile(backup, data, 0o644); writeErr != nil {
return "", fmt.Errorf("write backup failed: %w", writeErr)
}
}
out, err := json.MarshalIndent(root, "", " ")
if err != nil {
return "", fmt.Errorf("marshal migrated config failed: %w", err)
}
tmp := path + ".tmp"
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return "", fmt.Errorf("ensure config dir failed: %w", err)
}
if err := os.WriteFile(tmp, append(out, '\n'), 0o644); err != nil {
return "", fmt.Errorf("write migrated config failed: %w", err)
}
if err := os.Rename(tmp, path); err != nil {
return "", fmt.Errorf("replace migrated config failed: %w", err)
}
msg := "singbox dns migrated to new server format"
if len(warnings) > 0 {
return msg, errors.New(strings.Join(warnings, "; "))
}
return msg, nil
}