mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-30 22:02:02 +02:00
added new file button in config editor, dockerfile fix
This commit is contained in:
38
src/go-proxy/args.go
Normal file
38
src/go-proxy/args.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Args struct {
|
||||
Command string
|
||||
}
|
||||
|
||||
const (
|
||||
CommandStart = ""
|
||||
CommandVerify = "verify"
|
||||
CommandReload = "reload"
|
||||
)
|
||||
|
||||
var ValidCommands = []string{CommandStart, CommandVerify, CommandReload}
|
||||
|
||||
func getArgs() Args {
|
||||
var args Args
|
||||
flag.Parse()
|
||||
args.Command = flag.Arg(0)
|
||||
if err := validateArgs(args.Command, ValidCommands); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func validateArgs[T comparable](arg T, validArgs []T) error {
|
||||
for _, v := range validArgs {
|
||||
if arg == v {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return NewNestedError("invalid argument").Subjectf("%v", arg)
|
||||
}
|
||||
@@ -21,9 +21,9 @@ import (
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
)
|
||||
|
||||
type ProviderOptions = map[string]string
|
||||
type ProviderGenerator = func(ProviderOptions) (challenge.Provider, error)
|
||||
type CertExpiries = map[string]time.Time
|
||||
type ProviderOptions map[string]string
|
||||
type ProviderGenerator func(ProviderOptions) (challenge.Provider, error)
|
||||
type CertExpiries map[string]time.Time
|
||||
|
||||
type AutoCertConfig struct {
|
||||
Email string `json:"email"`
|
||||
|
||||
@@ -3,12 +3,14 @@ package main
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// commented out if unused
|
||||
type Config interface {
|
||||
Value() configModel
|
||||
// Load() error
|
||||
MustLoad()
|
||||
GetAutoCertProvider() (AutoCertProvider, error)
|
||||
@@ -21,7 +23,13 @@ type Config interface {
|
||||
}
|
||||
|
||||
func NewConfig(path string) Config {
|
||||
cfg := &config{reader: &FileReader{Path: path}}
|
||||
cfg := &config{
|
||||
m: &configModel{
|
||||
TimeoutShutdown: 3 * time.Second,
|
||||
RedirectToHTTPS: false,
|
||||
},
|
||||
reader: &FileReader{Path: path},
|
||||
}
|
||||
cfg.watcher = NewFileWatcher(
|
||||
path,
|
||||
cfg.MustReload, // OnChange
|
||||
@@ -35,6 +43,10 @@ func ValidateConfig(data []byte) error {
|
||||
return cfg.Load()
|
||||
}
|
||||
|
||||
func (cfg *config) Value() configModel {
|
||||
return *cfg.m
|
||||
}
|
||||
|
||||
func (cfg *config) Load(reader ...Reader) error {
|
||||
cfg.mutex.Lock()
|
||||
defer cfg.mutex.Unlock()
|
||||
@@ -170,12 +182,14 @@ func (cfg *config) StopWatching() {
|
||||
}
|
||||
|
||||
type configModel struct {
|
||||
Providers map[string]*Provider `yaml:",flow" json:"providers"`
|
||||
AutoCert AutoCertConfig `yaml:",flow" json:"autocert"`
|
||||
Providers map[string]*Provider `yaml:",flow" json:"providers"`
|
||||
AutoCert AutoCertConfig `yaml:",flow" json:"autocert"`
|
||||
TimeoutShutdown time.Duration `yaml:"timeout_shutdown" json:"timeout_shutdown"`
|
||||
RedirectToHTTPS bool `yaml:"redirect_to_https" json:"redirect_to_https"`
|
||||
}
|
||||
|
||||
type config struct {
|
||||
m *configModel
|
||||
m *configModel
|
||||
|
||||
reader Reader
|
||||
watcher Watcher
|
||||
|
||||
@@ -147,6 +147,4 @@ var logLevel = func() logrus.Level {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
return logrus.GetLevel()
|
||||
}()
|
||||
|
||||
var redirectToHTTPS = os.Getenv("GOPROXY_REDIRECT_HTTP") != "0" && os.Getenv("GOPROXY_REDIRECT_HTTP") != "false"
|
||||
}()
|
||||
@@ -44,8 +44,8 @@ func NewHTTPRoute(config *ProxyConfig) (*HTTPRoute, error) {
|
||||
PathMode: config.PathMode,
|
||||
l: hrlog.WithFields(logrus.Fields{
|
||||
"alias": config.Alias,
|
||||
"path": config.Path,
|
||||
"path_mode": config.PathMode,
|
||||
// "path": config.Path,
|
||||
// "path_mode": config.PathMode,
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -157,6 +157,6 @@ func (config *ProxyConfig) pathSubModResp(r *http.Response) error {
|
||||
}
|
||||
|
||||
// alias -> (path -> routes)
|
||||
type HTTPRoutes = SafeMap[string, pathPoolMap]
|
||||
type HTTPRoutes SafeMap[string, pathPoolMap]
|
||||
|
||||
var httpRoutes HTTPRoutes = NewSafeMapOf[HTTPRoutes](newPathPoolMap)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -16,21 +17,27 @@ var cfg Config
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
|
||||
var verifyOnly bool
|
||||
flag.BoolVar(&verifyOnly, "verify", false, "verify config without starting server")
|
||||
flag.Parse()
|
||||
args := getArgs()
|
||||
|
||||
logrus.SetFormatter(&logrus.TextFormatter{
|
||||
ForceColors: true,
|
||||
DisableColors: false,
|
||||
FullTimestamp: true,
|
||||
ForceColors: true,
|
||||
DisableColors: false,
|
||||
FullTimestamp: true,
|
||||
TimestampFormat: "01-02 15:04:05",
|
||||
})
|
||||
|
||||
if args.Command == CommandReload {
|
||||
err := utils.reloadServer()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
cfg = NewConfig(configPath)
|
||||
cfg.MustLoad()
|
||||
|
||||
if verifyOnly {
|
||||
if args.Command == CommandVerify {
|
||||
logrus.Printf("config OK")
|
||||
return
|
||||
}
|
||||
@@ -63,7 +70,7 @@ func main() {
|
||||
HTTPAddr: ":80",
|
||||
HTTPSAddr: ":443",
|
||||
Handler: http.HandlerFunc(proxyHandler),
|
||||
RedirectToHTTPS: redirectToHTTPS,
|
||||
RedirectToHTTPS: cfg.Value().RedirectToHTTPS,
|
||||
})
|
||||
panelServer = NewServer(ServerOptions{
|
||||
Name: "panel",
|
||||
@@ -71,7 +78,7 @@ func main() {
|
||||
HTTPAddr: ":8080",
|
||||
HTTPSAddr: ":8443",
|
||||
Handler: panelHandler,
|
||||
RedirectToHTTPS: redirectToHTTPS,
|
||||
RedirectToHTTPS: cfg.Value().RedirectToHTTPS,
|
||||
})
|
||||
|
||||
proxyServer.Start()
|
||||
@@ -88,10 +95,32 @@ func main() {
|
||||
signal.Notify(sig, syscall.SIGHUP)
|
||||
|
||||
<-sig
|
||||
// cfg.StopWatching()
|
||||
StopFSWatcher()
|
||||
StopDockerWatcher()
|
||||
cfg.StopProviders()
|
||||
panelServer.Stop()
|
||||
proxyServer.Stop()
|
||||
logrus.Info("shutting down")
|
||||
done := make(chan struct{}, 1)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(3)
|
||||
|
||||
go func() {
|
||||
StopFSWatcher()
|
||||
StopDockerWatcher()
|
||||
cfg.StopProviders()
|
||||
wg.Done()
|
||||
}()
|
||||
go func() {
|
||||
panelServer.Stop()
|
||||
proxyServer.Stop()
|
||||
wg.Done()
|
||||
}()
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
logrus.Info("shutdown complete")
|
||||
case <-time.After(cfg.Value().TimeoutShutdown * time.Second):
|
||||
logrus.Info("timeout waiting for shutdown")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -68,7 +69,7 @@ func panelCheckTargetHealth(w http.ResponseWriter, r *http.Request) {
|
||||
func panelConfigEditor(w http.ResponseWriter, r *http.Request) {
|
||||
cfgFiles := make([]string, 0)
|
||||
cfgFiles = append(cfgFiles, path.Base(configPath))
|
||||
for _, p := range cfg.(*config).m.Providers {
|
||||
for _, p := range cfg.Value().Providers {
|
||||
if p.Kind != ProviderKind_File {
|
||||
continue
|
||||
}
|
||||
@@ -99,12 +100,20 @@ func panelConfigUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
panelHandleErr(w, r, err)
|
||||
return
|
||||
}
|
||||
err = os.WriteFile(path.Join(configBasePath, p), content, 0644)
|
||||
p = path.Join(configBasePath, p)
|
||||
_, err = os.Stat(p)
|
||||
exists := !errors.Is(err, os.ErrNotExist)
|
||||
err = os.WriteFile(p, content, 0644)
|
||||
if err != nil {
|
||||
panelHandleErr(w, r, NewNestedError("unable to write config file").With(err))
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if !exists {
|
||||
w.Write([]byte(fmt.Sprintf("Config file %s created, remember to add it to config.yml!", p)))
|
||||
return
|
||||
}
|
||||
w.Write([]byte(fmt.Sprintf("Config file %s updated", p)))
|
||||
}
|
||||
|
||||
func panelServeFile(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -141,4 +150,4 @@ func panelHandleErr(w http.ResponseWriter, r *http.Request, err error, code ...i
|
||||
return
|
||||
}
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ type ProxyConfig struct {
|
||||
provider *Provider
|
||||
}
|
||||
|
||||
type ProxyConfigMap = map[string]ProxyConfig
|
||||
type ProxyConfigSlice = []ProxyConfig
|
||||
type ProxyConfigMap map[string]ProxyConfig
|
||||
type ProxyConfigSlice []ProxyConfig
|
||||
|
||||
func NewProxyConfig(provider *Provider) ProxyConfig {
|
||||
return ProxyConfig{
|
||||
|
||||
@@ -47,6 +47,6 @@ func isStreamScheme(s string) bool {
|
||||
}
|
||||
|
||||
// id -> target
|
||||
type StreamRoutes = SafeMap[string, StreamRoute]
|
||||
type StreamRoutes SafeMap[string, StreamRoute]
|
||||
|
||||
var streamRoutes StreamRoutes = NewSafeMapOf[StreamRoutes]()
|
||||
|
||||
@@ -31,11 +31,11 @@ type ServerOptions struct {
|
||||
}
|
||||
|
||||
type LogrusWrapper struct {
|
||||
l *logrus.Entry
|
||||
*logrus.Entry
|
||||
}
|
||||
|
||||
func (l LogrusWrapper) Write(b []byte) (int, error) {
|
||||
return l.l.Logger.WriterLevel(logrus.ErrorLevel).Write(b)
|
||||
return l.Logger.WriterLevel(logrus.ErrorLevel).Write(b)
|
||||
}
|
||||
|
||||
func NewServer(opt ServerOptions) *Server {
|
||||
|
||||
@@ -45,10 +45,8 @@ type StreamRouteBase struct {
|
||||
|
||||
func newStreamRouteBase(config *ProxyConfig) (*StreamRouteBase, error) {
|
||||
var streamType string = StreamType_TCP
|
||||
var srcPort string
|
||||
var dstPort string
|
||||
var srcScheme string
|
||||
var dstScheme string
|
||||
var srcPort, dstPort string
|
||||
var srcScheme, dstScheme string
|
||||
|
||||
portSplit := strings.Split(config.Port, ":")
|
||||
if len(portSplit) != 2 {
|
||||
@@ -101,8 +99,8 @@ func newStreamRouteBase(config *ProxyConfig) (*StreamRouteBase, error) {
|
||||
started: false,
|
||||
l: srlog.WithFields(logrus.Fields{
|
||||
"alias": config.Alias,
|
||||
"src": fmt.Sprintf("%s://:%d", srcScheme, srcPortInt),
|
||||
"dst": fmt.Sprintf("%s://%s:%d", dstScheme, config.Host, dstPortInt),
|
||||
// "src": fmt.Sprintf("%s://:%d", srcScheme, srcPortInt),
|
||||
// "dst": fmt.Sprintf("%s://%s:%d", dstScheme, config.Host, dstPortInt),
|
||||
}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -94,6 +94,18 @@ func (*Utils) healthCheckStream(scheme, host string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*Utils) reloadServer() error {
|
||||
resp, err := healthCheckHttpClient.Post("http://localhost:8080/reload", "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return NewNestedError("server reload failed").Subjectf("%d", resp.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*Utils) snakeToPascal(s string) string {
|
||||
toHyphenCamel := http.CanonicalHeaderKey(strings.ReplaceAll(s, "_", "-"))
|
||||
return strings.ReplaceAll(toHyphenCamel, "-", "")
|
||||
|
||||
@@ -89,7 +89,7 @@ func (w *fileWatcher) Stop() {
|
||||
fileWatchMap.Delete(w.path)
|
||||
err := fsWatcher.Remove(w.path)
|
||||
if err != nil {
|
||||
w.l.WithField("action", "stop").Error(err)
|
||||
w.l.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user