SDK下载乱码问题修复
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package apps
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -49,6 +50,6 @@ func (this *SdkDocAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
this.AddHeader("Content-Type", "text/markdown; charset=utf-8")
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\""+downloadName+"\";")
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"sdk-doc.md\"; filename*=UTF-8''"+url.PathEscape(downloadName))
|
||||
_, _ = this.ResponseWriter.Write(data)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package apps
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -58,7 +59,7 @@ func (this *SdkDownloadAction) RunGet(params struct {
|
||||
this.AddHeader("X-SDK-Filename", downloadName)
|
||||
} else {
|
||||
this.AddHeader("Content-Type", "application/zip")
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\""+downloadName+"\";")
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"sdk-download\"; filename*=UTF-8''"+url.PathEscape(downloadName))
|
||||
}
|
||||
this.AddHeader("X-Accel-Buffering", "no")
|
||||
_, _ = io.Copy(this.ResponseWriter, fp)
|
||||
|
||||
1
EdgeHttpDNS/.gitignore
vendored
1
EdgeHttpDNS/.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
*.zip
|
||||
edge-dns
|
||||
configs/
|
||||
logs/
|
||||
data/
|
||||
|
||||
171
EdgeHttpDNS/internal/configs/api_config.go
Normal file
171
EdgeHttpDNS/internal/configs/api_config.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const ConfigFileName = "api_httpdns.yaml"
|
||||
const oldConfigFileName = "api.yaml"
|
||||
|
||||
var sharedAPIConfig *APIConfig
|
||||
|
||||
type APIConfig struct {
|
||||
OldRPC struct {
|
||||
Endpoints []string `yaml:"endpoints"`
|
||||
DisableUpdate bool `yaml:"disableUpdate"`
|
||||
} `yaml:"rpc,omitempty"`
|
||||
|
||||
RPCEndpoints []string `yaml:"rpc.endpoints,flow" json:"rpc.endpoints"`
|
||||
RPCDisableUpdate bool `yaml:"rpc.disableUpdate" json:"rpc.disableUpdate"`
|
||||
|
||||
NodeId string `yaml:"nodeId"`
|
||||
Secret string `yaml:"secret"`
|
||||
|
||||
ListenAddr string `yaml:"listenAddr"`
|
||||
|
||||
HTTPSListenAddr string `yaml:"https.listenAddr" json:"https.listenAddr"`
|
||||
HTTPSCert string `yaml:"https.cert" json:"https.cert"`
|
||||
HTTPSKey string `yaml:"https.key" json:"https.key"`
|
||||
|
||||
LogDir string `yaml:"logDir" json:"logDir"`
|
||||
}
|
||||
|
||||
func SharedAPIConfig() (*APIConfig, error) {
|
||||
if sharedAPIConfig != nil {
|
||||
return sharedAPIConfig, nil
|
||||
}
|
||||
|
||||
config, err := LoadAPIConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sharedAPIConfig = config
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func LoadAPIConfig() (*APIConfig, error) {
|
||||
for _, filename := range []string{ConfigFileName, oldConfigFileName} {
|
||||
var loadedData []byte
|
||||
var loadedPath string
|
||||
for _, candidate := range findConfigCandidates(filename) {
|
||||
data, err := os.ReadFile(candidate)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
loadedData = data
|
||||
loadedPath = candidate
|
||||
break
|
||||
}
|
||||
|
||||
if len(loadedData) == 0 {
|
||||
if filename == oldConfigFileName {
|
||||
continue
|
||||
}
|
||||
return nil, errors.New("no config file '" + ConfigFileName + "' found")
|
||||
}
|
||||
|
||||
config := &APIConfig{}
|
||||
err := yaml.Unmarshal(loadedData, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = config.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if filename == oldConfigFileName {
|
||||
config.OldRPC.Endpoints = nil
|
||||
// 优先写回当前旧配置所在目录,避免依赖启动时工作目录
|
||||
_ = config.WriteFile(filepath.Join(filepath.Dir(loadedPath), ConfigFileName))
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
return nil, errors.New("no config file '" + ConfigFileName + "' found")
|
||||
}
|
||||
|
||||
func (c *APIConfig) Init() error {
|
||||
if len(c.RPCEndpoints) == 0 && len(c.OldRPC.Endpoints) > 0 {
|
||||
c.RPCEndpoints = c.OldRPC.Endpoints
|
||||
c.RPCDisableUpdate = c.OldRPC.DisableUpdate
|
||||
}
|
||||
|
||||
if len(c.RPCEndpoints) == 0 {
|
||||
return errors.New("no valid 'rpc.endpoints'")
|
||||
}
|
||||
|
||||
if len(c.NodeId) == 0 {
|
||||
return errors.New("'nodeId' required")
|
||||
}
|
||||
if len(c.Secret) == 0 {
|
||||
return errors.New("'secret' required")
|
||||
}
|
||||
|
||||
// 兼容旧配置中的 listenAddr
|
||||
if len(c.HTTPSListenAddr) == 0 {
|
||||
if len(c.ListenAddr) > 0 {
|
||||
c.HTTPSListenAddr = c.ListenAddr
|
||||
} else {
|
||||
c.HTTPSListenAddr = ":8443"
|
||||
}
|
||||
}
|
||||
|
||||
if len(c.HTTPSCert) == 0 {
|
||||
// return errors.New("'https.cert' required")
|
||||
}
|
||||
if len(c.HTTPSKey) == 0 {
|
||||
// return errors.New("'https.key' required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *APIConfig) WriteFile(path string) error {
|
||||
data, err := yaml.Marshal(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, data, 0666)
|
||||
}
|
||||
|
||||
func findConfigCandidates(filename string) []string {
|
||||
candidates := []string{
|
||||
Tea.ConfigFile(filename),
|
||||
Tea.ConfigFile(filepath.Join("configs", filename)),
|
||||
filename,
|
||||
filepath.Join("configs", filename),
|
||||
}
|
||||
|
||||
if exePath, err := os.Executable(); err == nil {
|
||||
exeDir := filepath.Dir(exePath)
|
||||
candidates = append(candidates,
|
||||
filepath.Join(exeDir, filename),
|
||||
filepath.Join(exeDir, "configs", filename),
|
||||
filepath.Join(exeDir, "..", "configs", filename),
|
||||
)
|
||||
}
|
||||
|
||||
uniq := map[string]struct{}{}
|
||||
result := make([]string, 0, len(candidates))
|
||||
for _, candidate := range candidates {
|
||||
candidate = filepath.Clean(candidate)
|
||||
if len(candidate) == 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := uniq[candidate]; ok {
|
||||
continue
|
||||
}
|
||||
uniq[candidate] = struct{}{}
|
||||
result = append(result, candidate)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package apps
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -49,6 +50,6 @@ func (this *SdkDocAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
this.AddHeader("Content-Type", "text/markdown; charset=utf-8")
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\""+downloadName+"\";")
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"sdk-doc.md\"; filename*=UTF-8''"+url.PathEscape(downloadName))
|
||||
_, _ = this.ResponseWriter.Write(data)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package apps
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -58,7 +59,7 @@ func (this *SdkDownloadAction) RunGet(params struct {
|
||||
this.AddHeader("X-SDK-Filename", downloadName)
|
||||
} else {
|
||||
this.AddHeader("Content-Type", "application/zip")
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\""+downloadName+"\";")
|
||||
this.AddHeader("Content-Disposition", "attachment; filename=\"sdk-download\"; filename*=UTF-8''"+url.PathEscape(downloadName))
|
||||
}
|
||||
this.AddHeader("X-Accel-Buffering", "no")
|
||||
_, _ = io.Copy(this.ResponseWriter, fp)
|
||||
|
||||
Reference in New Issue
Block a user