mirror of
https://github.com/go-gost/x.git
synced 2026-10-19 16:16:32 +00:00
fix(api): save config back to the loaded file path (gost/x#123)
POST /config without an explicit path= always wrote gost.yaml/gost.json to the process CWD, silently leaving the config loaded via -C untouched. Track the last file read by ReadFile and default the save target to it, deriving the output format from the file extension so a JSON config is saved back as JSON. Falls back to the CWD default when no config file was loaded.
This commit is contained in:
+29
-11
@@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-gost/core/observer/stats"
|
||||
@@ -127,10 +129,11 @@ func getConfig(ctx *gin.Context) {
|
||||
|
||||
// swagger:parameters saveConfigRequest
|
||||
type saveConfigRequest struct {
|
||||
// output format, one of yaml|json, default is yaml.
|
||||
// output format, one of yaml|json, default is derived from the file extension.
|
||||
// in: query
|
||||
Format string `form:"format" json:"format"`
|
||||
// file path, default is gost.yaml|gost.json in current working directory.
|
||||
// file path, default is the loaded config file, or gost.yaml|gost.json in
|
||||
// the current working directory when no config file was loaded.
|
||||
// in: query
|
||||
Path string `form:"path" json:"path"`
|
||||
}
|
||||
@@ -155,16 +158,31 @@ func saveConfig(ctx *gin.Context) {
|
||||
var req saveConfigRequest
|
||||
ctx.ShouldBindQuery(&req)
|
||||
|
||||
file := "gost.yaml"
|
||||
switch req.Format {
|
||||
case "json":
|
||||
file = "gost.json"
|
||||
default:
|
||||
req.Format = "yaml"
|
||||
file := req.Path
|
||||
if file == "" {
|
||||
// Default to the config file that was loaded (via -C), falling back to
|
||||
// the current working directory when the config came from elsewhere.
|
||||
file = config.ConfigFile()
|
||||
}
|
||||
|
||||
if req.Path != "" {
|
||||
file = req.Path
|
||||
if file == "" {
|
||||
file = "gost.yaml"
|
||||
if req.Format == "json" {
|
||||
file = "gost.json"
|
||||
}
|
||||
}
|
||||
switch strings.ToLower(req.Format) {
|
||||
case "json":
|
||||
req.Format = "json"
|
||||
case "yaml":
|
||||
req.Format = "yaml"
|
||||
default:
|
||||
// Derive the format from the file extension so a loaded JSON config
|
||||
// is saved back as JSON (ReadFile forces format from extension).
|
||||
if strings.ToLower(filepath.Ext(file)) == ".json" {
|
||||
req.Format = "json"
|
||||
} else {
|
||||
req.Format = "yaml"
|
||||
}
|
||||
}
|
||||
|
||||
f, err := os.Create(file)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
@@ -28,8 +29,21 @@ func init() {
|
||||
var (
|
||||
global = &Config{}
|
||||
globalMux sync.RWMutex
|
||||
|
||||
// configFile remembers the last file loaded via ReadFile so the API can
|
||||
// save back to the same location (issue go-gost/x#123).
|
||||
configFile atomic.Value // string
|
||||
)
|
||||
|
||||
// ConfigFile returns the path of the last config file loaded via ReadFile,
|
||||
// or an empty string when the config came from stdin, a URL, or inline JSON.
|
||||
func ConfigFile() string {
|
||||
if s, ok := configFile.Load().(string); ok {
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func Global() *Config {
|
||||
globalMux.RLock()
|
||||
defer globalMux.RUnlock()
|
||||
@@ -780,6 +794,7 @@ func (c *Config) ReadFile(file string) error {
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
configFile.Store(file)
|
||||
return v.Unmarshal(c, viper.DecodeHook(gostDecodeHook()))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user