feat(config): support loading configuration from URL

https://github.com/fatedier/frp/issues/4853
This commit introduces the capability to load configuration files directly from an HTTP or HTTPS URL, in addition to local file paths.

A new helper function, `readBytesFromPath`, is implemented to handle both remote and local file retrieval. This function replaces direct calls to `os.ReadFile` in the configuration loading logic, providing greater flexibility for deploying and managing frp configurations.
pull/4855/head
heskdx 2025-06-27 14:48:59 +08:00
parent c777891f75
commit 058fe0b6e5
2 changed files with 38 additions and 3 deletions

View File

@ -16,6 +16,9 @@ package legacy
import ( import (
"bytes" "bytes"
"fmt"
"io"
"net/http"
"os" "os"
"strings" "strings"
"text/template" "text/template"
@ -45,6 +48,21 @@ func GetValues() *Values {
} }
} }
func readBytesFromPath(path string) ([]byte, error) {
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
resp, err := http.Get(path)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch config from url %s, status code: %d", path, resp.StatusCode)
}
return io.ReadAll(resp.Body)
}
return os.ReadFile(path)
}
func RenderContent(in []byte) (out []byte, err error) { func RenderContent(in []byte) (out []byte, err error) {
tmpl, errRet := template.New("frp").Parse(string(in)) tmpl, errRet := template.New("frp").Parse(string(in))
if errRet != nil { if errRet != nil {
@ -64,7 +82,7 @@ func RenderContent(in []byte) (out []byte, err error) {
func GetRenderedConfFromFile(path string) (out []byte, err error) { func GetRenderedConfFromFile(path string) (out []byte, err error) {
var b []byte var b []byte
b, err = os.ReadFile(path) b, err = readBytesFromPath(path)
if err != nil { if err != nil {
return return
} }

View File

@ -18,6 +18,8 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -36,6 +38,21 @@ import (
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
) )
func readBytesFromPath(path string) ([]byte, error) {
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
resp, err := http.Get(path)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to fetch config from url %s, status code: %d", path, resp.StatusCode)
}
return io.ReadAll(resp.Body)
}
return os.ReadFile(path)
}
var glbEnvs map[string]string var glbEnvs map[string]string
func init() { func init() {
@ -72,7 +89,7 @@ func DetectLegacyINIFormat(content []byte) bool {
} }
func DetectLegacyINIFormatFromFile(path string) bool { func DetectLegacyINIFormatFromFile(path string) bool {
b, err := os.ReadFile(path) b, err := readBytesFromPath(path)
if err != nil { if err != nil {
return false return false
} }
@ -96,7 +113,7 @@ func RenderWithTemplate(in []byte, values *Values) ([]byte, error) {
} }
func LoadFileContentWithTemplate(path string, values *Values) ([]byte, error) { func LoadFileContentWithTemplate(path string, values *Values) ([]byte, error) {
b, err := os.ReadFile(path) b, err := readBytesFromPath(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }