diff --git a/agent/cmd/main.go b/agent/cmd/main.go index a4c7a28..2369706 100644 --- a/agent/cmd/main.go +++ b/agent/cmd/main.go @@ -6,7 +6,7 @@ import ( "github.com/yusing/go-proxy/agent/pkg/agent" "github.com/yusing/go-proxy/agent/pkg/env" "github.com/yusing/go-proxy/agent/pkg/server" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/pkg" @@ -16,7 +16,7 @@ func main() { args := os.Args if len(args) > 1 && args[1] == "migrate" { if err := agent.MigrateFromOld(); err != nil { - E.LogFatal("failed to migrate from old docker compose", err) + gperr.LogFatal("failed to migrate from old docker compose", err) } return } @@ -24,21 +24,21 @@ func main() { ca := &agent.PEMPair{} err := ca.Load(env.AgentCACert) if err != nil { - E.LogFatal("init CA error", err) + gperr.LogFatal("init CA error", err) } caCert, err := ca.ToTLSCert() if err != nil { - E.LogFatal("init CA error", err) + gperr.LogFatal("init CA error", err) } srv := &agent.PEMPair{} srv.Load(env.AgentSSLCert) if err != nil { - E.LogFatal("init SSL error", err) + gperr.LogFatal("init SSL error", err) } srvCert, err := srv.ToTLSCert() if err != nil { - E.LogFatal("init SSL error", err) + gperr.LogFatal("init SSL error", err) } logging.Info().Msgf("GoDoxy Agent version %s", pkg.GetVersion()) diff --git a/agent/pkg/agent/config.go b/agent/pkg/agent/config.go index 7bcdc52..6849342 100644 --- a/agent/pkg/agent/config.go +++ b/agent/pkg/agent/config.go @@ -12,9 +12,9 @@ import ( "github.com/rs/zerolog" "github.com/yusing/go-proxy/agent/pkg/certs" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" - gphttp "github.com/yusing/go-proxy/internal/net/http" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" "github.com/yusing/go-proxy/internal/net/types" "github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/pkg" @@ -80,17 +80,17 @@ func checkVersion(a, b string) bool { return withoutBuildTime(a) == withoutBuildTime(b) } -func (cfg *AgentConfig) StartWithCerts(parent task.Parent, ca, crt, key []byte) E.Error { +func (cfg *AgentConfig) StartWithCerts(parent task.Parent, ca, crt, key []byte) error { clientCert, err := tls.X509KeyPair(crt, key) if err != nil { - return E.Wrap(err) + return err } // create tls config caCertPool := x509.NewCertPool() ok := caCertPool.AppendCertsFromPEM(ca) if !ok { - return E.New("invalid CA certificate") + return gperr.New("invalid CA certificate") } cfg.tlsConfig = &tls.Config{ @@ -108,17 +108,17 @@ func (cfg *AgentConfig) StartWithCerts(parent task.Parent, ca, crt, key []byte) // check agent version version, _, err := cfg.Fetch(ctx, EndpointVersion) if err != nil { - return E.Wrap(err) + return err } if !checkVersion(string(version), pkg.GetVersion()) { - return E.Errorf("agent version mismatch: server: %s, agent: %s", pkg.GetVersion(), string(version)) + return gperr.Errorf("agent version mismatch: server: %s, agent: %s", pkg.GetVersion(), string(version)) } // get agent name name, _, err := cfg.Fetch(ctx, EndpointName) if err != nil { - return E.Wrap(err) + return err } cfg.name = string(name) @@ -128,18 +128,18 @@ func (cfg *AgentConfig) StartWithCerts(parent task.Parent, ca, crt, key []byte) return nil } -func (cfg *AgentConfig) Start(parent task.Parent) E.Error { +func (cfg *AgentConfig) Start(parent task.Parent) error { certData, err := os.ReadFile(certs.AgentCertsFilename(cfg.Addr)) if err != nil { if os.IsNotExist(err) { - return E.Errorf("agents certs not found, did you run `godoxy new-agent %s ...`?", cfg.Addr) + return gperr.Errorf("agents certs not found, did you run `godoxy new-agent %s ...`?", cfg.Addr) } - return E.Wrap(err) + return gperr.Wrap(err) } ca, crt, key, err := certs.ExtractCert(certData) if err != nil { - return E.Wrap(err) + return gperr.Wrap(err) } return cfg.StartWithCerts(parent, ca, crt, key) diff --git a/agent/pkg/agent/docker_compose.go b/agent/pkg/agent/docker_compose.go index 503df65..02fe9a9 100644 --- a/agent/pkg/agent/docker_compose.go +++ b/agent/pkg/agent/docker_compose.go @@ -9,7 +9,7 @@ import ( _ "embed" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/utils" "gopkg.in/yaml.v3" @@ -110,11 +110,11 @@ func MigrateFromOld() error { composeConfig.SSLCert = agentCert.String() composeTemplate, err := composeConfig.Generate() if err != nil { - return E.Wrap(err, "failed to generate new docker compose") + return gperr.Wrap(err, "failed to generate new docker compose") } if err := os.WriteFile("/app/compose.yml", []byte(composeTemplate), 0600); err != nil { - return E.Wrap(err, "failed to write new docker compose") + return gperr.Wrap(err, "failed to write new docker compose") } logging.Info().Msg("Migrated from old docker compose:") diff --git a/agent/pkg/handler/check_health.go b/agent/pkg/handler/check_health.go index f697721..1dfadd7 100644 --- a/agent/pkg/handler/check_health.go +++ b/agent/pkg/handler/check_health.go @@ -7,7 +7,7 @@ import ( "os" "strings" - apiUtils "github.com/yusing/go-proxy/internal/api/v1/utils" + "github.com/yusing/go-proxy/internal/net/gphttp" "github.com/yusing/go-proxy/internal/net/types" "github.com/yusing/go-proxy/internal/watcher/health" "github.com/yusing/go-proxy/internal/watcher/health/monitor" @@ -72,5 +72,5 @@ func CheckHealth(w http.ResponseWriter, r *http.Request) { return } - apiUtils.RespondJSON(w, r, result) + gphttp.RespondJSON(w, r, result) } diff --git a/agent/pkg/handler/docker_socket.go b/agent/pkg/handler/docker_socket.go index e50ffaf..7e2d132 100644 --- a/agent/pkg/handler/docker_socket.go +++ b/agent/pkg/handler/docker_socket.go @@ -8,7 +8,7 @@ import ( "github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/docker" "github.com/yusing/go-proxy/internal/logging" - "github.com/yusing/go-proxy/internal/net/http/reverseproxy" + "github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy" "github.com/yusing/go-proxy/internal/net/types" ) diff --git a/agent/pkg/handler/proxy_http.go b/agent/pkg/handler/proxy_http.go index 8b864b1..712f261 100644 --- a/agent/pkg/handler/proxy_http.go +++ b/agent/pkg/handler/proxy_http.go @@ -8,10 +8,10 @@ import ( "time" "github.com/yusing/go-proxy/agent/pkg/agent" - agentproxy "github.com/yusing/go-proxy/agent/pkg/agentproxy" + "github.com/yusing/go-proxy/agent/pkg/agentproxy" "github.com/yusing/go-proxy/internal/logging" - gphttp "github.com/yusing/go-proxy/internal/net/http" - "github.com/yusing/go-proxy/internal/net/http/reverseproxy" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy" "github.com/yusing/go-proxy/internal/net/types" "github.com/yusing/go-proxy/internal/utils/strutils" ) diff --git a/agent/pkg/server/server.go b/agent/pkg/server/server.go index 20a2fc3..736fd81 100644 --- a/agent/pkg/server/server.go +++ b/agent/pkg/server/server.go @@ -14,7 +14,7 @@ import ( "github.com/yusing/go-proxy/agent/pkg/env" "github.com/yusing/go-proxy/agent/pkg/handler" "github.com/yusing/go-proxy/internal/logging" - "github.com/yusing/go-proxy/internal/net/http/server" + "github.com/yusing/go-proxy/internal/net/gphttp/server" "github.com/yusing/go-proxy/internal/task" ) diff --git a/cmd/main.go b/cmd/main.go index fbc704b..b50396f 100755 --- a/cmd/main.go +++ b/cmd/main.go @@ -11,10 +11,10 @@ import ( "github.com/yusing/go-proxy/internal/api/v1/query" "github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/config" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/homepage" "github.com/yusing/go-proxy/internal/logging" - "github.com/yusing/go-proxy/internal/net/http/middleware" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware" "github.com/yusing/go-proxy/internal/route/routes/routequery" "github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/pkg" @@ -32,7 +32,7 @@ func main() { return case common.CommandReload: if err := query.ReloadServer(); err != nil { - E.LogFatal("server reload error", err) + gperr.LogFatal("server reload error", err) } rawLogger.Println("ok") return @@ -88,9 +88,9 @@ func main() { middleware.LoadComposeFiles() var cfg *config.Config - var err E.Error + var err gperr.Error if cfg, err = config.Load(); err != nil { - E.LogWarn("errors in config", err) + gperr.LogWarn("errors in config", err) } switch args.Command { diff --git a/internal/api/handler.go b/internal/api/handler.go index 6ec1e47..9de8651 100644 --- a/internal/api/handler.go +++ b/internal/api/handler.go @@ -13,7 +13,7 @@ import ( "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/logging/memlogger" "github.com/yusing/go-proxy/internal/metrics/uptime" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" "github.com/yusing/go-proxy/internal/utils/strutils" ) diff --git a/internal/api/v1/agents.go b/internal/api/v1/agents.go index d722bee..d9d2a87 100644 --- a/internal/api/v1/agents.go +++ b/internal/api/v1/agents.go @@ -6,18 +6,19 @@ import ( "github.com/coder/websocket" "github.com/coder/websocket/wsjson" - U "github.com/yusing/go-proxy/internal/api/v1/utils" config "github.com/yusing/go-proxy/internal/config/types" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/gpwebsocket" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" ) func ListAgents(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) { if httpheaders.IsWebsocket(r.Header) { - U.PeriodicWS(w, r, 10*time.Second, func(conn *websocket.Conn) error { + gpwebsocket.Periodic(w, r, 10*time.Second, func(conn *websocket.Conn) error { wsjson.Write(r.Context(), conn, cfg.ListAgents()) return nil }) } else { - U.RespondJSON(w, r, cfg.ListAgents()) + gphttp.RespondJSON(w, r, cfg.ListAgents()) } } diff --git a/internal/api/v1/auth/auth.go b/internal/api/v1/auth/auth.go index ed0060e..705c74b 100644 --- a/internal/api/v1/auth/auth.go +++ b/internal/api/v1/auth/auth.go @@ -3,9 +3,9 @@ package auth import ( "net/http" - U "github.com/yusing/go-proxy/internal/api/v1/utils" "github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/logging" + "github.com/yusing/go-proxy/internal/net/gphttp" ) var defaultAuth Provider @@ -44,7 +44,7 @@ func RequireAuth(next http.HandlerFunc) http.HandlerFunc { if IsEnabled() { return func(w http.ResponseWriter, r *http.Request) { if err := defaultAuth.CheckToken(r); err != nil { - U.RespondError(w, err, http.StatusUnauthorized) + gphttp.ClientError(w, err, http.StatusUnauthorized) } else { next(w, r) } diff --git a/internal/api/v1/auth/oidc.go b/internal/api/v1/auth/oidc.go index d08d674..e22904c 100644 --- a/internal/api/v1/auth/oidc.go +++ b/internal/api/v1/auth/oidc.go @@ -12,9 +12,8 @@ import ( "time" "github.com/coreos/go-oidc/v3/oidc" - U "github.com/yusing/go-proxy/internal/api/v1/utils" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/net/gphttp" CE "github.com/yusing/go-proxy/internal/utils" "github.com/yusing/go-proxy/internal/utils/strutils" "golang.org/x/oauth2" @@ -154,7 +153,7 @@ func generateState() (string, error) { func (auth *OIDCProvider) RedirectLoginPage(w http.ResponseWriter, r *http.Request) { state, err := generateState() if err != nil { - U.HandleErr(w, r, err, http.StatusInternalServerError) + gphttp.ServerError(w, r, err) return } http.SetCookie(w, &http.Cookie{ @@ -171,7 +170,7 @@ func (auth *OIDCProvider) RedirectLoginPage(w http.ResponseWriter, r *http.Reque if auth.isMiddleware { u, err := r.URL.Parse(redirURL) if err != nil { - U.HandleErr(w, r, err, http.StatusInternalServerError) + gphttp.ServerError(w, r, err) return } q := u.Query() @@ -201,31 +200,31 @@ func (auth *OIDCProvider) LoginCallbackHandler(w http.ResponseWriter, r *http.Re state, err := r.Cookie(CookieOauthState) if err != nil { - U.HandleErr(w, r, E.New("missing state cookie"), http.StatusBadRequest) + gphttp.BadRequest(w, "missing state cookie") return } query := r.URL.Query() if query.Get("state") != state.Value { - U.HandleErr(w, r, E.New("invalid oauth state"), http.StatusBadRequest) + gphttp.BadRequest(w, "invalid oauth state") return } oauth2Token, err := auth.exchange(r) if err != nil { - U.HandleErr(w, r, fmt.Errorf("failed to exchange token: %w", err), http.StatusInternalServerError) + gphttp.ServerError(w, r, fmt.Errorf("failed to exchange token: %w", err)) return } rawIDToken, ok := oauth2Token.Extra("id_token").(string) if !ok { - U.HandleErr(w, r, E.New("missing id_token"), http.StatusInternalServerError) + gphttp.BadRequest(w, "missing id_token") return } idToken, err := auth.oidcVerifier.Verify(r.Context(), rawIDToken) if err != nil { - U.HandleErr(w, r, fmt.Errorf("failed to verify ID token: %w", err), http.StatusInternalServerError) + gphttp.ServerError(w, r, fmt.Errorf("failed to verify ID token: %w", err)) return } @@ -243,7 +242,7 @@ func (auth *OIDCProvider) LogoutCallbackHandler(w http.ResponseWriter, r *http.R token, err := r.Cookie(auth.TokenCookieName()) if err != nil { - U.HandleErr(w, r, E.New("missing token cookie"), http.StatusBadRequest) + gphttp.BadRequest(w, "missing token cookie") return } clearTokenCookie(w, r, auth.TokenCookieName()) @@ -258,12 +257,12 @@ func (auth *OIDCProvider) LogoutCallbackHandler(w http.ResponseWriter, r *http.R func (auth *OIDCProvider) handleTestCallback(w http.ResponseWriter, r *http.Request) { state, err := r.Cookie(CookieOauthState) if err != nil { - U.HandleErr(w, r, E.New("missing state cookie"), http.StatusBadRequest) + gphttp.BadRequest(w, "missing state cookie") return } if r.URL.Query().Get("state") != state.Value { - U.HandleErr(w, r, E.New("invalid oauth state"), http.StatusBadRequest) + gphttp.BadRequest(w, "invalid oauth state") return } diff --git a/internal/api/v1/auth/userpass.go b/internal/api/v1/auth/userpass.go index 7c6512c..239a4cc 100644 --- a/internal/api/v1/auth/userpass.go +++ b/internal/api/v1/auth/userpass.go @@ -7,16 +7,16 @@ import ( "time" "github.com/golang-jwt/jwt/v5" - U "github.com/yusing/go-proxy/internal/api/v1/utils" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/net/gphttp" "github.com/yusing/go-proxy/internal/utils/strutils" "golang.org/x/crypto/bcrypt" ) var ( - ErrInvalidUsername = E.New("invalid username") - ErrInvalidPassword = E.New("invalid password") + ErrInvalidUsername = gperr.New("invalid username") + ErrInvalidPassword = gperr.New("invalid password") ) type ( @@ -94,7 +94,7 @@ func (auth *UserPassAuth) CheckToken(r *http.Request) error { case claims.Username != auth.username: return ErrUserNotAllowed.Subject(claims.Username) case claims.ExpiresAt.Before(time.Now()): - return E.Errorf("token expired on %s", strutils.FormatTime(claims.ExpiresAt.Time)) + return gperr.Errorf("token expired on %s", strutils.FormatTime(claims.ExpiresAt.Time)) } return nil @@ -111,17 +111,16 @@ func (auth *UserPassAuth) LoginCallbackHandler(w http.ResponseWriter, r *http.Re } err := json.NewDecoder(r.Body).Decode(&creds) if err != nil { - U.HandleErr(w, r, err, http.StatusBadRequest) + gphttp.Unauthorized(w, "invalid credentials") return } if err := auth.validatePassword(creds.User, creds.Pass); err != nil { - U.LogError(r).Err(err).Msg("auth: invalid credentials") - U.RespondError(w, E.New("invalid credentials"), http.StatusUnauthorized) + gphttp.Unauthorized(w, "invalid credentials") return } token, err := auth.NewToken() if err != nil { - U.HandleErr(w, r, err, http.StatusInternalServerError) + gphttp.ServerError(w, r, err) return } setTokenCookie(w, r, auth.TokenCookieName(), token, auth.tokenTTL) diff --git a/internal/api/v1/auth/utils.go b/internal/api/v1/auth/utils.go index 05a1558..91eec3e 100644 --- a/internal/api/v1/auth/utils.go +++ b/internal/api/v1/auth/utils.go @@ -5,14 +5,14 @@ import ( "net/http" "time" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/utils/strutils" ) var ( - ErrMissingToken = E.New("missing token") - ErrInvalidToken = E.New("invalid token") - ErrUserNotAllowed = E.New("user not allowed") + ErrMissingToken = gperr.New("missing token") + ErrInvalidToken = gperr.New("invalid token") + ErrUserNotAllowed = gperr.New("user not allowed") ) // cookieFQDN returns the fully qualified domain name of the request host diff --git a/internal/api/v1/favicon/favicon.go b/internal/api/v1/favicon/favicon.go index 5376644..055c74f 100644 --- a/internal/api/v1/favicon/favicon.go +++ b/internal/api/v1/favicon/favicon.go @@ -13,10 +13,10 @@ import ( "github.com/PuerkitoBio/goquery" "github.com/vincent-petithory/dataurl" - U "github.com/yusing/go-proxy/internal/api/v1/utils" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/homepage" "github.com/yusing/go-proxy/internal/logging" - gphttp "github.com/yusing/go-proxy/internal/net/http" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" "github.com/yusing/go-proxy/internal/route/routes" route "github.com/yusing/go-proxy/internal/route/types" ) @@ -53,11 +53,11 @@ func (res *fetchResult) ContentType() string { func GetFavIcon(w http.ResponseWriter, req *http.Request) { url, alias := req.FormValue("url"), req.FormValue("alias") if url == "" && alias == "" { - U.RespondError(w, U.ErrMissingKey("url or alias"), http.StatusBadRequest) + gphttp.ClientError(w, gphttp.ErrMissingKey("url or alias"), http.StatusBadRequest) return } if url != "" && alias != "" { - U.RespondError(w, U.ErrInvalidKey("url and alias are mutually exclusive"), http.StatusBadRequest) + gphttp.ClientError(w, gperr.New("url and alias are mutually exclusive"), http.StatusBadRequest) return } @@ -65,7 +65,7 @@ func GetFavIcon(w http.ResponseWriter, req *http.Request) { if url != "" { var iconURL homepage.IconURL if err := iconURL.Parse(url); err != nil { - U.RespondError(w, err, http.StatusBadRequest) + gphttp.ClientError(w, err, http.StatusBadRequest) return } fetchResult := getFavIconFromURL(&iconURL) @@ -74,14 +74,14 @@ func GetFavIcon(w http.ResponseWriter, req *http.Request) { return } w.Header().Set("Content-Type", fetchResult.ContentType()) - U.WriteBody(w, fetchResult.icon) + gphttp.WriteBody(w, fetchResult.icon) return } // try with route.Homepage.Icon r, ok := routes.GetHTTPRoute(alias) if !ok { - U.RespondError(w, errors.New("no such route"), http.StatusNotFound) + gphttp.ClientError(w, errors.New("no such route"), http.StatusNotFound) return } @@ -105,7 +105,7 @@ func GetFavIcon(w http.ResponseWriter, req *http.Request) { return } w.Header().Set("Content-Type", result.ContentType()) - U.WriteBody(w, result.icon) + gphttp.WriteBody(w, result.icon) } func getFavIconFromURL(iconURL *homepage.IconURL) *fetchResult { @@ -125,7 +125,7 @@ func fetchIconAbsolute(url string) *fetchResult { return result } - resp, err := U.Get(url) + resp, err := gphttp.Get(url) if err != nil || resp.StatusCode != http.StatusOK { if err == nil { err = errors.New(resp.Status) diff --git a/internal/api/v1/file.go b/internal/api/v1/file.go index 0a84977..d05c1db 100644 --- a/internal/api/v1/file.go +++ b/internal/api/v1/file.go @@ -7,11 +7,11 @@ import ( "path" "strings" - U "github.com/yusing/go-proxy/internal/api/v1/utils" "github.com/yusing/go-proxy/internal/common" config "github.com/yusing/go-proxy/internal/config/types" - E "github.com/yusing/go-proxy/internal/error" - "github.com/yusing/go-proxy/internal/net/http/middleware" + "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware" "github.com/yusing/go-proxy/internal/route/provider" ) @@ -51,12 +51,12 @@ func (t FileType) GetPath(filename string) string { func getArgs(r *http.Request) (fileType FileType, filename string, err error) { fileType = FileType(r.PathValue("type")) if !fileType.IsValid() { - err = U.ErrInvalidKey("type") + err = gphttp.ErrInvalidKey("type") return } filename = r.PathValue("filename") if filename == "" { - err = U.ErrMissingKey("filename") + err = gphttp.ErrMissingKey("filename") } return } @@ -64,23 +64,23 @@ func getArgs(r *http.Request) (fileType FileType, filename string, err error) { func GetFileContent(w http.ResponseWriter, r *http.Request) { fileType, filename, err := getArgs(r) if err != nil { - U.RespondError(w, err, http.StatusBadRequest) + gphttp.BadRequest(w, err.Error()) return } content, err := os.ReadFile(fileType.GetPath(filename)) if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } - U.WriteBody(w, content) + gphttp.WriteBody(w, content) } -func validateFile(fileType FileType, content []byte) error { +func validateFile(fileType FileType, content []byte) gperr.Error { switch fileType { case FileTypeConfig: return config.Validate(content) case FileTypeMiddleware: - errs := E.NewBuilder("middleware errors") + errs := gperr.NewBuilder("middleware errors") middleware.BuildMiddlewaresFromYAML("", content, errs) return errs.Error() } @@ -90,18 +90,17 @@ func validateFile(fileType FileType, content []byte) error { func ValidateFile(w http.ResponseWriter, r *http.Request) { fileType := FileType(r.PathValue("type")) if !fileType.IsValid() { - U.RespondError(w, U.ErrInvalidKey("type"), http.StatusBadRequest) + gphttp.BadRequest(w, "invalid file type") return } content, err := io.ReadAll(r.Body) if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } r.Body.Close() - err = validateFile(fileType, content) - if err != nil { - U.RespondError(w, err, http.StatusBadRequest) + if valErr := validateFile(fileType, content); valErr != nil { + gphttp.JSONError(w, valErr, http.StatusBadRequest) return } w.WriteHeader(http.StatusOK) @@ -110,23 +109,23 @@ func ValidateFile(w http.ResponseWriter, r *http.Request) { func SetFileContent(w http.ResponseWriter, r *http.Request) { fileType, filename, err := getArgs(r) if err != nil { - U.RespondError(w, err, http.StatusBadRequest) + gphttp.BadRequest(w, err.Error()) return } content, err := io.ReadAll(r.Body) if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } if valErr := validateFile(fileType, content); valErr != nil { - U.RespondError(w, valErr, http.StatusBadRequest) + gphttp.JSONError(w, valErr, http.StatusBadRequest) return } err = os.WriteFile(fileType.GetPath(filename), content, 0o644) if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } w.WriteHeader(http.StatusOK) diff --git a/internal/api/v1/health.go b/internal/api/v1/health.go index 2856aaf..3379022 100644 --- a/internal/api/v1/health.go +++ b/internal/api/v1/health.go @@ -6,17 +6,18 @@ import ( "github.com/coder/websocket" "github.com/coder/websocket/wsjson" - U "github.com/yusing/go-proxy/internal/api/v1/utils" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/gpwebsocket" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" "github.com/yusing/go-proxy/internal/route/routes/routequery" ) func Health(w http.ResponseWriter, r *http.Request) { if httpheaders.IsWebsocket(r.Header) { - U.PeriodicWS(w, r, 1*time.Second, func(conn *websocket.Conn) error { + gpwebsocket.Periodic(w, r, 1*time.Second, func(conn *websocket.Conn) error { return wsjson.Write(r.Context(), conn, routequery.HealthMap()) }) } else { - U.RespondJSON(w, r, routequery.HealthMap()) + gphttp.RespondJSON(w, r, routequery.HealthMap()) } } diff --git a/internal/api/v1/homepage_overrides.go b/internal/api/v1/homepage_overrides.go index 0d570fb..f9d6448 100644 --- a/internal/api/v1/homepage_overrides.go +++ b/internal/api/v1/homepage_overrides.go @@ -5,8 +5,8 @@ import ( "io" "net/http" - "github.com/yusing/go-proxy/internal/api/v1/utils" "github.com/yusing/go-proxy/internal/homepage" + "github.com/yusing/go-proxy/internal/net/gphttp" ) const ( @@ -37,13 +37,13 @@ type ( func SetHomePageOverrides(w http.ResponseWriter, r *http.Request) { what := r.FormValue("what") if what == "" { - http.Error(w, "missing what or which", http.StatusBadRequest) + gphttp.BadRequest(w, "missing what or which") return } data, err := io.ReadAll(r.Body) if err != nil { - utils.RespondError(w, err, http.StatusBadRequest) + gphttp.ClientError(w, err, http.StatusBadRequest) return } r.Body.Close() @@ -53,21 +53,21 @@ func SetHomePageOverrides(w http.ResponseWriter, r *http.Request) { case HomepageOverrideItem: var params HomepageOverrideItemParams if err := json.Unmarshal(data, ¶ms); err != nil { - utils.RespondError(w, err, http.StatusBadRequest) + gphttp.ClientError(w, err, http.StatusBadRequest) return } overrides.OverrideItem(params.Which, ¶ms.Value) case HomepageOverrideItemsBatch: var params HomepageOverrideItemsBatchParams if err := json.Unmarshal(data, ¶ms); err != nil { - utils.RespondError(w, err, http.StatusBadRequest) + gphttp.ClientError(w, err, http.StatusBadRequest) return } overrides.OverrideItems(params.Value) case HomepageOverrideItemVisible: // POST /v1/item_visible [a,b,c], false => hide a, b, c var params HomepageOverrideItemVisibleParams if err := json.Unmarshal(data, ¶ms); err != nil { - utils.RespondError(w, err, http.StatusBadRequest) + gphttp.ClientError(w, err, http.StatusBadRequest) return } if params.Value { @@ -78,7 +78,7 @@ func SetHomePageOverrides(w http.ResponseWriter, r *http.Request) { case HomepageOverrideCategoryOrder: var params HomepageOverrideCategoryOrderParams if err := json.Unmarshal(data, ¶ms); err != nil { - utils.RespondError(w, err, http.StatusBadRequest) + gphttp.ClientError(w, err, http.StatusBadRequest) return } overrides.SetCategoryOrder(params.Which, params.Value) diff --git a/internal/api/v1/index.go b/internal/api/v1/index.go index 71bbf2e..dcaa976 100644 --- a/internal/api/v1/index.go +++ b/internal/api/v1/index.go @@ -3,9 +3,9 @@ package v1 import ( "net/http" - . "github.com/yusing/go-proxy/internal/api/v1/utils" + "github.com/yusing/go-proxy/internal/net/gphttp" ) func Index(w http.ResponseWriter, r *http.Request) { - WriteBody(w, []byte("API ready")) + gphttp.WriteBody(w, []byte("API ready")) } diff --git a/internal/api/v1/list.go b/internal/api/v1/list.go index 2e861c1..cdb520b 100644 --- a/internal/api/v1/list.go +++ b/internal/api/v1/list.go @@ -1,15 +1,16 @@ package v1 import ( + "fmt" "net/http" "strconv" "strings" "github.com/yusing/go-proxy/internal" - U "github.com/yusing/go-proxy/internal/api/v1/utils" "github.com/yusing/go-proxy/internal/common" config "github.com/yusing/go-proxy/internal/config/types" - "github.com/yusing/go-proxy/internal/net/http/middleware" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware" "github.com/yusing/go-proxy/internal/route/routes/routequery" route "github.com/yusing/go-proxy/internal/route/types" "github.com/yusing/go-proxy/internal/task" @@ -41,26 +42,25 @@ func List(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) { case ListRoute: if route := listRoute(which); route == nil { http.NotFound(w, r) - return } else { - U.RespondJSON(w, r, route) + gphttp.RespondJSON(w, r, route) } case ListRoutes: - U.RespondJSON(w, r, routequery.RoutesByAlias(route.RouteType(r.FormValue("type")))) + gphttp.RespondJSON(w, r, routequery.RoutesByAlias(route.RouteType(r.FormValue("type")))) case ListFiles: listFiles(w, r) case ListMiddlewares: - U.RespondJSON(w, r, middleware.All()) + gphttp.RespondJSON(w, r, middleware.All()) case ListMiddlewareTraces: - U.RespondJSON(w, r, middleware.GetAllTrace()) + gphttp.RespondJSON(w, r, middleware.GetAllTrace()) case ListMatchDomains: - U.RespondJSON(w, r, cfg.Value().MatchDomains) + gphttp.RespondJSON(w, r, cfg.Value().MatchDomains) case ListHomepageConfig: - U.RespondJSON(w, r, routequery.HomepageConfig(cfg.Value().Homepage.UseDefaultCategories, r.FormValue("category"), r.FormValue("provider"))) + gphttp.RespondJSON(w, r, routequery.HomepageConfig(cfg.Value().Homepage.UseDefaultCategories, r.FormValue("category"), r.FormValue("provider"))) case ListRouteProviders: - U.RespondJSON(w, r, cfg.RouteProviderList()) + gphttp.RespondJSON(w, r, cfg.RouteProviderList()) case ListHomepageCategories: - U.RespondJSON(w, r, routequery.HomepageCategories()) + gphttp.RespondJSON(w, r, routequery.HomepageCategories()) case ListIcons: limit, err := strconv.Atoi(r.FormValue("limit")) if err != nil { @@ -68,17 +68,17 @@ func List(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) { } icons, err := internal.SearchIcons(r.FormValue("keyword"), limit) if err != nil { - U.RespondError(w, err) + gphttp.ClientError(w, err) return } if icons == nil { icons = []string{} } - U.RespondJSON(w, r, icons) + gphttp.RespondJSON(w, r, icons) case ListTasks: - U.RespondJSON(w, r, task.DebugTaskList()) + gphttp.RespondJSON(w, r, task.DebugTaskList()) default: - U.HandleErr(w, r, U.ErrInvalidKey("what"), http.StatusBadRequest) + gphttp.BadRequest(w, fmt.Sprintf("invalid what: %s", what)) } } @@ -99,7 +99,7 @@ func listRoute(which string) any { func listFiles(w http.ResponseWriter, r *http.Request) { files, err := utils.ListFiles(common.ConfigBasePath, 0, true) if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } resp := map[FileType][]string{ @@ -116,12 +116,12 @@ func listFiles(w http.ResponseWriter, r *http.Request) { mids, err := utils.ListFiles(common.MiddlewareComposeBasePath, 0, true) if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } for _, mid := range mids { mid = strings.TrimPrefix(mid, common.MiddlewareComposeBasePath+"/") resp[FileTypeMiddleware] = append(resp[FileTypeMiddleware], mid) } - U.RespondJSON(w, r, resp) + gphttp.RespondJSON(w, r, resp) } diff --git a/internal/api/v1/new_agent.go b/internal/api/v1/new_agent.go index c328bdd..ecb6daa 100644 --- a/internal/api/v1/new_agent.go +++ b/internal/api/v1/new_agent.go @@ -12,8 +12,9 @@ import ( "github.com/yusing/go-proxy/agent/pkg/agent" "github.com/yusing/go-proxy/agent/pkg/certs" - U "github.com/yusing/go-proxy/internal/api/v1/utils" config "github.com/yusing/go-proxy/internal/config/types" + "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/net/gphttp" "github.com/yusing/go-proxy/internal/utils/strutils" ) @@ -21,27 +22,27 @@ func NewAgent(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() name := q.Get("name") if name == "" { - U.RespondError(w, U.ErrMissingKey("name")) + gphttp.ClientError(w, gphttp.ErrMissingKey("name")) return } host := q.Get("host") if host == "" { - U.RespondError(w, U.ErrMissingKey("host")) + gphttp.ClientError(w, gphttp.ErrMissingKey("host")) return } portStr := q.Get("port") if portStr == "" { - U.RespondError(w, U.ErrMissingKey("port")) + gphttp.ClientError(w, gphttp.ErrMissingKey("port")) return } port, err := strconv.Atoi(portStr) if err != nil || port < 1 || port > 65535 { - U.RespondError(w, U.ErrInvalidKey("port")) + gphttp.ClientError(w, gphttp.ErrInvalidKey("port")) return } hostport := fmt.Sprintf("%s:%d", host, port) if _, ok := config.GetInstance().GetAgent(hostport); ok { - U.RespondError(w, U.ErrAlreadyExists("agent", hostport), http.StatusConflict) + gphttp.ClientError(w, gphttp.ErrAlreadyExists("agent", hostport), http.StatusConflict) return } t := q.Get("type") @@ -49,13 +50,13 @@ func NewAgent(w http.ResponseWriter, r *http.Request) { case "docker": break case "system": - U.RespondError(w, U.Errorf("system agent is not supported yet"), http.StatusNotImplemented) + gphttp.ClientError(w, gperr.Errorf("system agent is not supported yet"), http.StatusNotImplemented) return case "": - U.RespondError(w, U.ErrMissingKey("type")) + gphttp.ClientError(w, gphttp.ErrMissingKey("type")) return default: - U.RespondError(w, U.ErrInvalidKey("type")) + gphttp.ClientError(w, gphttp.ErrInvalidKey("type")) return } @@ -69,7 +70,7 @@ func NewAgent(w http.ResponseWriter, r *http.Request) { ca, srv, client, err := agent.NewAgent() if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } @@ -83,11 +84,11 @@ func NewAgent(w http.ResponseWriter, r *http.Request) { template, err := cfg.Generate() if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } - U.RespondJSON(w, r, map[string]any{ + gphttp.RespondJSON(w, r, map[string]any{ "compose": template, "ca": ca, "client": client, @@ -98,7 +99,7 @@ func AddAgent(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() clientPEMData, err := io.ReadAll(r.Body) if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } @@ -109,24 +110,24 @@ func AddAgent(w http.ResponseWriter, r *http.Request) { } if err := json.Unmarshal(clientPEMData, &data); err != nil { - U.RespondError(w, err, http.StatusBadRequest) + gphttp.ClientError(w, err, http.StatusBadRequest) return } nRoutesAdded, err := config.GetInstance().AddAgent(data.Host, data.CA, data.Client) if err != nil { - U.RespondError(w, err) + gphttp.ClientError(w, err) return } zip, err := certs.ZipCert(data.CA.Cert, data.Client.Cert, data.Client.Key) if err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } if err := os.WriteFile(certs.AgentCertsFilename(data.Host), zip, 0600); err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } diff --git a/internal/api/v1/query/query.go b/internal/api/v1/query/query.go index 7b59772..0a1d576 100644 --- a/internal/api/v1/query/query.go +++ b/internal/api/v1/query/query.go @@ -7,20 +7,20 @@ import ( "net/http" v1 "github.com/yusing/go-proxy/internal/api/v1" - U "github.com/yusing/go-proxy/internal/api/v1/utils" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" - "github.com/yusing/go-proxy/internal/net/http/middleware" + "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware" ) -func ReloadServer() E.Error { - resp, err := U.Post(common.APIHTTPURL+"/v1/reload", "", nil) +func ReloadServer() gperr.Error { + resp, err := gphttp.Post(common.APIHTTPURL+"/v1/reload", "", nil) if err != nil { - return E.From(err) + return gperr.Wrap(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - failure := E.Errorf("server reload status %v", resp.StatusCode) + failure := gperr.Errorf("server reload status %v", resp.StatusCode) body, err := io.ReadAll(resp.Body) if err != nil { return failure.With(err) @@ -31,34 +31,34 @@ func ReloadServer() E.Error { return nil } -func List[T any](what string) (_ T, outErr E.Error) { - resp, err := U.Get(fmt.Sprintf("%s/v1/list/%s", common.APIHTTPURL, what)) +func List[T any](what string) (_ T, outErr gperr.Error) { + resp, err := gphttp.Get(fmt.Sprintf("%s/v1/list/%s", common.APIHTTPURL, what)) if err != nil { - outErr = E.From(err) + outErr = gperr.Wrap(err) return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - outErr = E.Errorf("list %s: failed, status %v", what, resp.StatusCode) + outErr = gperr.Errorf("list %s: failed, status %v", what, resp.StatusCode) return } var res T err = json.NewDecoder(resp.Body).Decode(&res) if err != nil { - outErr = E.From(err) + outErr = gperr.Wrap(err) return } return res, nil } -func ListRoutes() (map[string]map[string]any, E.Error) { +func ListRoutes() (map[string]map[string]any, gperr.Error) { return List[map[string]map[string]any](v1.ListRoutes) } -func ListMiddlewareTraces() (middleware.Traces, E.Error) { +func ListMiddlewareTraces() (middleware.Traces, gperr.Error) { return List[middleware.Traces](v1.ListMiddlewareTraces) } -func DebugListTasks() (map[string]any, E.Error) { +func DebugListTasks() (map[string]any, gperr.Error) { return List[map[string]any](v1.ListTasks) } diff --git a/internal/api/v1/reload.go b/internal/api/v1/reload.go index defa4e4..1460d47 100644 --- a/internal/api/v1/reload.go +++ b/internal/api/v1/reload.go @@ -3,14 +3,14 @@ package v1 import ( "net/http" - U "github.com/yusing/go-proxy/internal/api/v1/utils" config "github.com/yusing/go-proxy/internal/config/types" + "github.com/yusing/go-proxy/internal/net/gphttp" ) func Reload(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) { if err := cfg.Reload(); err != nil { - U.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } - U.WriteBody(w, []byte("OK")) + gphttp.WriteBody(w, []byte("OK")) } diff --git a/internal/api/v1/stats.go b/internal/api/v1/stats.go index ffdece9..1fbac51 100644 --- a/internal/api/v1/stats.go +++ b/internal/api/v1/stats.go @@ -6,19 +6,20 @@ import ( "github.com/coder/websocket" "github.com/coder/websocket/wsjson" - U "github.com/yusing/go-proxy/internal/api/v1/utils" config "github.com/yusing/go-proxy/internal/config/types" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/gpwebsocket" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" "github.com/yusing/go-proxy/internal/utils/strutils" ) func Stats(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) { if httpheaders.IsWebsocket(r.Header) { - U.PeriodicWS(w, r, 1*time.Second, func(conn *websocket.Conn) error { + gpwebsocket.Periodic(w, r, 1*time.Second, func(conn *websocket.Conn) error { return wsjson.Write(r.Context(), conn, getStats(cfg)) }) } else { - U.RespondJSON(w, r, getStats(cfg)) + gphttp.RespondJSON(w, r, getStats(cfg)) } } diff --git a/internal/api/v1/system_info.go b/internal/api/v1/system_info.go index 1c06dad..31f6829 100644 --- a/internal/api/v1/system_info.go +++ b/internal/api/v1/system_info.go @@ -4,12 +4,12 @@ import ( "net/http" agentPkg "github.com/yusing/go-proxy/agent/pkg/agent" - U "github.com/yusing/go-proxy/internal/api/v1/utils" config "github.com/yusing/go-proxy/internal/config/types" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/metrics/systeminfo" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" - "github.com/yusing/go-proxy/internal/net/http/reverseproxy" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy" ) func SystemInfo(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Request) { @@ -23,7 +23,7 @@ func SystemInfo(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Reques agent, ok := cfg.GetAgent(agentAddr) if !ok { - U.HandleErr(w, r, U.ErrInvalidKey("agent_addr"), http.StatusNotFound) + gphttp.NotFound(w, "agent_addr") return } @@ -31,20 +31,20 @@ func SystemInfo(cfg config.ConfigInstance, w http.ResponseWriter, r *http.Reques if !isWS { respData, status, err := agent.Forward(r, agentPkg.EndpointSystemInfo) if err != nil { - U.HandleErr(w, r, E.Wrap(err, "failed to forward request to agent")) + gphttp.ServerError(w, r, gperr.Wrap(err, "failed to forward request to agent")) return } if status != http.StatusOK { http.Error(w, string(respData), status) return } - U.WriteBody(w, respData) + gphttp.WriteBody(w, respData) } else { rp := reverseproxy.NewReverseProxy("agent", agentPkg.AgentURL, agent.Transport()) header := r.Header.Clone() r, err := http.NewRequestWithContext(r.Context(), r.Method, agentPkg.EndpointSystemInfo+"?"+query.Encode(), nil) if err != nil { - U.HandleErr(w, r, E.Wrap(err, "failed to create request")) + gphttp.ServerError(w, r, gperr.Wrap(err, "failed to create request")) return } r.Header = header diff --git a/internal/api/v1/utils/error.go b/internal/api/v1/utils/error.go deleted file mode 100644 index 422f1c9..0000000 --- a/internal/api/v1/utils/error.go +++ /dev/null @@ -1,66 +0,0 @@ -package utils - -import ( - "context" - "errors" - "net/http" - "syscall" - - E "github.com/yusing/go-proxy/internal/error" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" - "github.com/yusing/go-proxy/internal/utils/strutils/ansi" -) - -// HandleErr logs the error and returns an error code to the client. -// If code is specified, it will be used as the HTTP status code; otherwise, -// http.StatusInternalServerError is used. -// -// The error is only logged but not returned to the client. -func HandleErr(w http.ResponseWriter, r *http.Request, err error, code ...int) { - switch { - case err == nil, - errors.Is(err, context.Canceled), - errors.Is(err, syscall.EPIPE), - errors.Is(err, syscall.ECONNRESET): - return - } - LogError(r).Msg(err.Error()) - if httpheaders.IsWebsocket(r.Header) { - return - } - if len(code) == 0 { - code = []int{http.StatusInternalServerError} - } - http.Error(w, http.StatusText(code[0]), code[0]) -} - -// RespondError returns error details to the client. -// If code is specified, it will be used as the HTTP status code; otherwise, -// http.StatusBadRequest is used. -func RespondError(w http.ResponseWriter, err error, code ...int) { - if len(code) == 0 { - code = []int{http.StatusBadRequest} - } - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - http.Error(w, ansi.StripANSI(err.Error()), code[0]) -} - -func Errorf(format string, args ...any) error { - return E.Errorf(format, args...) -} - -func ErrMissingKey(k string) error { - return E.New(k + " is required") -} - -func ErrInvalidKey(k string) error { - return E.New(k + " is invalid") -} - -func ErrAlreadyExists(k, v string) error { - return E.Errorf("%s %q already exists", k, v) -} - -func ErrNotFound(k, v string) error { - return E.Errorf("%s %q not found", k, v) -} diff --git a/internal/api/v1/version.go b/internal/api/v1/version.go index f0db6bf..f43a9d6 100644 --- a/internal/api/v1/version.go +++ b/internal/api/v1/version.go @@ -3,10 +3,10 @@ package v1 import ( "net/http" - . "github.com/yusing/go-proxy/internal/api/v1/utils" + "github.com/yusing/go-proxy/internal/net/gphttp" "github.com/yusing/go-proxy/pkg" ) func GetVersion(w http.ResponseWriter, r *http.Request) { - WriteBody(w, []byte(pkg.GetVersion())) + gphttp.WriteBody(w, []byte(pkg.GetVersion())) } diff --git a/internal/autocert/config.go b/internal/autocert/config.go index 3a32f73..19de2ba 100644 --- a/internal/autocert/config.go +++ b/internal/autocert/config.go @@ -10,7 +10,7 @@ import ( "github.com/go-acme/lego/v4/certcrypto" "github.com/go-acme/lego/v4/lego" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/utils" "github.com/yusing/go-proxy/internal/utils/strutils" @@ -30,17 +30,17 @@ type ( ) var ( - ErrMissingDomain = E.New("missing field 'domains'") - ErrMissingEmail = E.New("missing field 'email'") - ErrMissingProvider = E.New("missing field 'provider'") - ErrInvalidDomain = E.New("invalid domain") - ErrUnknownProvider = E.New("unknown provider") + ErrMissingDomain = gperr.New("missing field 'domains'") + ErrMissingEmail = gperr.New("missing field 'email'") + ErrMissingProvider = gperr.New("missing field 'provider'") + ErrInvalidDomain = gperr.New("invalid domain") + ErrUnknownProvider = gperr.New("unknown provider") ) var domainOrWildcardRE = regexp.MustCompile(`^\*?([^.]+\.)+[^.]+$`) // Validate implements the utils.CustomValidator interface. -func (cfg *AutocertConfig) Validate() E.Error { +func (cfg *AutocertConfig) Validate() gperr.Error { if cfg == nil { return nil } @@ -50,7 +50,7 @@ func (cfg *AutocertConfig) Validate() E.Error { return nil } - b := E.NewBuilder("autocert errors") + b := gperr.NewBuilder("autocert errors") if cfg.Provider != ProviderLocal { if len(cfg.Domains) == 0 { b.Add(ErrMissingDomain) @@ -79,7 +79,7 @@ func (cfg *AutocertConfig) Validate() E.Error { return b.Error() } -func (cfg *AutocertConfig) GetProvider() (*Provider, E.Error) { +func (cfg *AutocertConfig) GetProvider() (*Provider, gperr.Error) { if cfg == nil { cfg = new(AutocertConfig) } @@ -107,10 +107,10 @@ func (cfg *AutocertConfig) GetProvider() (*Provider, E.Error) { logging.Info().Msg("generate new ACME private key") privKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { - return nil, E.New("generate ACME private key").With(err) + return nil, gperr.New("generate ACME private key").With(err) } if err = cfg.saveACMEKey(privKey); err != nil { - return nil, E.New("save ACME private key").With(err) + return nil, gperr.New("save ACME private key").With(err) } } } diff --git a/internal/autocert/provider.go b/internal/autocert/provider.go index eaad175..9948d32 100644 --- a/internal/autocert/provider.go +++ b/internal/autocert/provider.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "crypto/x509" "errors" + "fmt" "os" "path" "reflect" @@ -14,7 +15,7 @@ import ( "github.com/go-acme/lego/v4/challenge" "github.com/go-acme/lego/v4/lego" "github.com/go-acme/lego/v4/registration" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/task" U "github.com/yusing/go-proxy/internal/utils" @@ -32,7 +33,7 @@ type ( tlsCert *tls.Certificate certExpiries CertExpiries } - ProviderGenerator func(ProviderOpt) (challenge.Provider, E.Error) + ProviderGenerator func(ProviderOpt) (challenge.Provider, gperr.Error) CertExpiries map[string]time.Time ) @@ -62,7 +63,7 @@ func (p *Provider) GetExpiries() CertExpiries { return p.certExpiries } -func (p *Provider) ObtainCert() E.Error { +func (p *Provider) ObtainCert() error { if p.cfg.Provider == ProviderLocal { return nil } @@ -75,7 +76,7 @@ func (p *Provider) ObtainCert() E.Error { if p.user.Registration == nil { if err := p.registerACME(); err != nil { - return E.From(err) + return err } } @@ -100,22 +101,22 @@ func (p *Provider) ObtainCert() E.Error { Bundle: true, }) if err != nil { - return E.From(err) + return err } } if err = p.saveCert(cert); err != nil { - return E.From(err) + return err } tlsCert, err := tls.X509KeyPair(cert.Certificate, cert.PrivateKey) if err != nil { - return E.From(err) + return err } expiries, err := getCertExpiries(&tlsCert) if err != nil { - return E.From(err) + return err } p.tlsCert = &tlsCert p.certExpiries = expiries @@ -123,14 +124,14 @@ func (p *Provider) ObtainCert() E.Error { return nil } -func (p *Provider) LoadCert() E.Error { +func (p *Provider) LoadCert() error { cert, err := tls.LoadX509KeyPair(p.cfg.CertPath, p.cfg.KeyPath) if err != nil { - return E.Errorf("load SSL certificate: %w", err) + return fmt.Errorf("load SSL certificate: %w", err) } expiries, err := getCertExpiries(&cert) if err != nil { - return E.Errorf("parse SSL certificate: %w", err) + return fmt.Errorf("parse SSL certificate: %w", err) } p.tlsCert = &cert p.certExpiries = expiries @@ -171,7 +172,7 @@ func (p *Provider) ScheduleRenewal(parent task.Parent) { continue } if err := p.renewIfNeeded(); err != nil { - E.LogWarn("cert renew failed", err) + gperr.LogWarn("cert renew failed", err) lastErrOn = time.Now() continue } @@ -184,10 +185,10 @@ func (p *Provider) ScheduleRenewal(parent task.Parent) { }() } -func (p *Provider) initClient() E.Error { +func (p *Provider) initClient() error { legoClient, err := lego.NewClient(p.legoCfg) if err != nil { - return E.From(err) + return err } generator := providersGenMap[p.cfg.Provider] @@ -198,7 +199,7 @@ func (p *Provider) initClient() E.Error { err = legoClient.Challenge.SetDNS01Provider(legoProvider) if err != nil { - return E.From(err) + return err } p.client = legoClient @@ -273,7 +274,7 @@ func (p *Provider) certState() CertState { return CertStateValid } -func (p *Provider) renewIfNeeded() E.Error { +func (p *Provider) renewIfNeeded() error { if p.cfg.Provider == ProviderLocal { return nil } @@ -312,13 +313,13 @@ func providerGenerator[CT any, PT challenge.Provider]( defaultCfg func() *CT, newProvider func(*CT) (PT, error), ) ProviderGenerator { - return func(opt ProviderOpt) (challenge.Provider, E.Error) { + return func(opt ProviderOpt) (challenge.Provider, gperr.Error) { cfg := defaultCfg() err := U.Deserialize(opt, &cfg) if err != nil { return nil, err } p, pErr := newProvider(cfg) - return p, E.From(pErr) + return p, gperr.Wrap(pErr) } } diff --git a/internal/autocert/setup.go b/internal/autocert/setup.go index 82e58ad..b436bed 100644 --- a/internal/autocert/setup.go +++ b/internal/autocert/setup.go @@ -1,16 +1,16 @@ package autocert import ( + "errors" "os" - E "github.com/yusing/go-proxy/internal/error" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/utils/strutils" ) -func (p *Provider) Setup() (err E.Error) { +func (p *Provider) Setup() (err error) { if err = p.LoadCert(); err != nil { - if !err.Is(os.ErrNotExist) { // ignore if cert doesn't exist + if !errors.Is(err, os.ErrNotExist) { // ignore if cert doesn't exist return err } logging.Debug().Msg("obtaining cert due to error loading cert") diff --git a/internal/common/constants.go b/internal/common/constants.go index 230a389..17e6190 100644 --- a/internal/common/constants.go +++ b/internal/common/constants.go @@ -4,12 +4,6 @@ import ( "time" ) -const ( - ConnectionTimeout = 5 * time.Second - DialTimeout = 3 * time.Second - KeepAlive = 60 * time.Second -) - // file, folder structure const ( @@ -50,5 +44,3 @@ const ( StopTimeoutDefault = "30s" StopMethodDefault = "stop" ) - -const HeaderCheckRedirect = "X-Goproxy-Check-Redirect" diff --git a/internal/config/agent_pool.go b/internal/config/agent_pool.go index 5088b37..9fe203d 100644 --- a/internal/config/agent_pool.go +++ b/internal/config/agent_pool.go @@ -2,7 +2,7 @@ package config import ( "github.com/yusing/go-proxy/agent/pkg/agent" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/route/provider" "github.com/yusing/go-proxy/internal/utils/functional" ) @@ -29,12 +29,12 @@ func (cfg *Config) GetAgent(agentAddrOrDockerHost string) (*agent.AgentConfig, b return GetAgent(agent.GetAgentAddrFromDockerHost(agentAddrOrDockerHost)) } -func (cfg *Config) AddAgent(host string, ca agent.PEMPair, client agent.PEMPair) (int, E.Error) { +func (cfg *Config) AddAgent(host string, ca agent.PEMPair, client agent.PEMPair) (int, gperr.Error) { var agentCfg agent.AgentConfig agentCfg.Addr = host err := agentCfg.StartWithCerts(cfg.Task(), ca.Cert, client.Cert, client.Key) if err != nil { - return 0, err + return 0, gperr.Wrap(err, "failed to start agent") } provider := provider.NewAgentProvider(&agentCfg) diff --git a/internal/config/config.go b/internal/config/config.go index a0b6987..28fd5e6 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -14,9 +14,9 @@ import ( "github.com/yusing/go-proxy/internal/common" config "github.com/yusing/go-proxy/internal/config/types" "github.com/yusing/go-proxy/internal/entrypoint" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" - "github.com/yusing/go-proxy/internal/net/http/server" + "github.com/yusing/go-proxy/internal/net/gphttp/server" "github.com/yusing/go-proxy/internal/notif" proxy "github.com/yusing/go-proxy/internal/route/provider" "github.com/yusing/go-proxy/internal/task" @@ -64,7 +64,7 @@ func newConfig() *Config { } } -func Load() (*Config, E.Error) { +func Load() (*Config, gperr.Error) { if config.HasInstance() { panic(errors.New("config already loaded")) } @@ -84,8 +84,8 @@ func WatchChanges() { t, configEventFlushInterval, OnConfigChange, - func(err E.Error) { - E.LogError("config reload error", err) + func(err gperr.Error) { + gperr.LogError("config reload error", err) }, ) eventQueue.Start(cfgWatcher.Events(t.Context())) @@ -109,7 +109,7 @@ func OnConfigChange(ev []events.Event) { } } -func Reload() E.Error { +func Reload() gperr.Error { // avoid race between config change and API reload request reloadMu.Lock() defer reloadMu.Unlock() @@ -118,7 +118,7 @@ func Reload() E.Error { err := newCfg.load() if err != nil { newCfg.task.Finish(err) - return E.New("using last config").With(err) + return gperr.New("using last config").With(err) } // cancel all current subtasks -> wait @@ -133,10 +133,13 @@ func (cfg *Config) Value() *config.Config { return cfg.value } -func (cfg *Config) Reload() E.Error { +func (cfg *Config) Reload() gperr.Error { return Reload() } +// AutoCertProvider returns the autocert provider. +// +// If the autocert provider is not configured, it returns nil. func (cfg *Config) AutoCertProvider() *autocert.Provider { return cfg.autocertProvider } @@ -163,7 +166,7 @@ func (cfg *Config) StartAutoCert() { } if err := autocert.Setup(); err != nil { - E.LogFatal("autocert setup error", err) + gperr.LogFatal("autocert setup error", err) } else { autocert.ScheduleRenewal(cfg.task) } @@ -175,8 +178,8 @@ func (cfg *Config) StartProxyProviders() { return p.Start(cfg.task) }) - if err := E.Join(errs...); err != nil { - E.LogError("route provider errors", err) + if err := gperr.Join(errs...); err != nil { + gperr.LogError("route provider errors", err) } } @@ -210,21 +213,21 @@ func (cfg *Config) StartServers(opts ...*StartServersOptions) { } } -func (cfg *Config) load() E.Error { +func (cfg *Config) load() gperr.Error { const errMsg = "config load error" data, err := os.ReadFile(common.ConfigPath) if err != nil { - E.LogFatal(errMsg, err) + gperr.LogFatal(errMsg, err) } model := config.DefaultConfig() if err := utils.DeserializeYAML(data, model); err != nil { - E.LogFatal(errMsg, err) + gperr.LogFatal(errMsg, err) } // errors are non fatal below - errs := E.NewBuilder(errMsg) + errs := gperr.NewBuilder(errMsg) errs.Add(cfg.entrypoint.SetMiddlewares(model.Entrypoint.Middlewares)) errs.Add(cfg.entrypoint.SetAccessLogger(cfg.task, model.Entrypoint.AccessLog)) cfg.initNotification(model.Providers.Notification) @@ -252,7 +255,7 @@ func (cfg *Config) initNotification(notifCfg []notif.NotificationConfig) { } } -func (cfg *Config) initAutoCert(autocertCfg *autocert.AutocertConfig) (err E.Error) { +func (cfg *Config) initAutoCert(autocertCfg *autocert.AutocertConfig) (err gperr.Error) { if cfg.autocertProvider != nil { return } @@ -261,9 +264,9 @@ func (cfg *Config) initAutoCert(autocertCfg *autocert.AutocertConfig) (err E.Err return } -func (cfg *Config) errIfExists(p *proxy.Provider) E.Error { +func (cfg *Config) errIfExists(p *proxy.Provider) gperr.Error { if _, ok := cfg.providers.Load(p.String()); ok { - return E.Errorf("provider %s already exists", p.String()) + return gperr.Errorf("provider %s already exists", p.String()) } return nil } @@ -272,9 +275,9 @@ func (cfg *Config) storeProvider(p *proxy.Provider) { cfg.providers.Store(p.String(), p) } -func (cfg *Config) loadRouteProviders(providers *config.Providers) E.Error { - errs := E.NewBuilder("route provider errors") - results := E.NewBuilder("loaded route providers") +func (cfg *Config) loadRouteProviders(providers *config.Providers) gperr.Error { + errs := gperr.NewBuilder("route provider errors") + results := gperr.NewBuilder("loaded route providers") removeAllAgents() @@ -297,7 +300,7 @@ func (cfg *Config) loadRouteProviders(providers *config.Providers) E.Error { err = cfg.errIfExists(p) } if err != nil { - errs.Add(E.PrependSubject(filename, err)) + errs.Add(gperr.PrependSubject(filename, err)) continue } cfg.storeProvider(p) diff --git a/internal/config/types/config.go b/internal/config/types/config.go index 7788d78..60c766c 100644 --- a/internal/config/types/config.go +++ b/internal/config/types/config.go @@ -8,11 +8,10 @@ import ( "github.com/go-playground/validator/v10" "github.com/yusing/go-proxy/agent/pkg/agent" "github.com/yusing/go-proxy/internal/autocert" - "github.com/yusing/go-proxy/internal/net/http/accesslog" + "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" "github.com/yusing/go-proxy/internal/notif" "github.com/yusing/go-proxy/internal/utils" - - E "github.com/yusing/go-proxy/internal/error" ) type ( @@ -37,12 +36,12 @@ type ( ConfigInstance interface { Value() *Config - Reload() E.Error + Reload() gperr.Error Statistics() map[string]any RouteProviderList() []string Context() context.Context GetAgent(agentAddrOrDockerHost string) (*agent.AgentConfig, bool) - AddAgent(host string, ca agent.PEMPair, client agent.PEMPair) (int, E.Error) + AddAgent(host string, ca agent.PEMPair, client agent.PEMPair) (int, gperr.Error) ListAgents() []*agent.AgentConfig } ) @@ -79,7 +78,7 @@ func HasInstance() bool { return instance != nil } -func Validate(data []byte) E.Error { +func Validate(data []byte) gperr.Error { var model Config return utils.DeserializeYAML(data, &model) } diff --git a/internal/docker/idlewatcher/loading_page.go b/internal/docker/idlewatcher/loading_page.go index 80913c7..b6e9860 100644 --- a/internal/docker/idlewatcher/loading_page.go +++ b/internal/docker/idlewatcher/loading_page.go @@ -6,7 +6,7 @@ import ( "strings" "text/template" - "github.com/yusing/go-proxy/internal/common" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" ) type templateData struct { @@ -23,11 +23,11 @@ func (w *Watcher) makeLoadingPageBody() []byte { msg := w.ContainerName + " is starting..." data := new(templateData) - data.CheckRedirectHeader = common.HeaderCheckRedirect + data.CheckRedirectHeader = httpheaders.HeaderGoDoxyCheckRedirect data.Title = w.ContainerName data.Message = strings.ReplaceAll(msg, " ", " ") - buf := bytes.NewBuffer(make([]byte, len(loadingPage)+len(data.Title)+len(data.Message)+len(common.HeaderCheckRedirect))) + buf := bytes.NewBuffer(make([]byte, len(loadingPage)+len(data.Title)+len(data.Message)+len(httpheaders.HeaderGoDoxyCheckRedirect))) err := loadingPageTmpl.Execute(buf, data) if err != nil { // should never happen in production panic(err) diff --git a/internal/docker/idlewatcher/types/config.go b/internal/docker/idlewatcher/types/config.go index a813cec..c607bb6 100644 --- a/internal/docker/idlewatcher/types/config.go +++ b/internal/docker/idlewatcher/types/config.go @@ -7,7 +7,7 @@ import ( "time" "github.com/yusing/go-proxy/internal/docker" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) type ( @@ -40,7 +40,7 @@ var validSignals = map[string]struct{}{ "INT": {}, "TERM": {}, "HUP": {}, "QUIT": {}, } -func ValidateConfig(cont *docker.Container) (*Config, E.Error) { +func ValidateConfig(cont *docker.Container) (*Config, gperr.Error) { if cont == nil { return nil, nil } @@ -54,14 +54,14 @@ func ValidateConfig(cont *docker.Container) (*Config, E.Error) { }, nil } - errs := E.NewBuilder("invalid idlewatcher config") + errs := gperr.NewBuilder("invalid idlewatcher config") - idleTimeout := E.Collect(errs, validateDurationPostitive, cont.IdleTimeout) - wakeTimeout := E.Collect(errs, validateDurationPostitive, cont.WakeTimeout) - stopTimeout := E.Collect(errs, validateDurationPostitive, cont.StopTimeout) - stopMethod := E.Collect(errs, validateStopMethod, cont.StopMethod) - signal := E.Collect(errs, validateSignal, cont.StopSignal) - startEndpoint := E.Collect(errs, validateStartEndpoint, cont.StartEndpoint) + idleTimeout := gperr.Collect(errs, validateDurationPostitive, cont.IdleTimeout) + wakeTimeout := gperr.Collect(errs, validateDurationPostitive, cont.WakeTimeout) + stopTimeout := gperr.Collect(errs, validateDurationPostitive, cont.StopTimeout) + stopMethod := gperr.Collect(errs, validateStopMethod, cont.StopMethod) + signal := gperr.Collect(errs, validateSignal, cont.StopSignal) + startEndpoint := gperr.Collect(errs, validateStartEndpoint, cont.StartEndpoint) if errs.HasError() { return nil, errs.Error() diff --git a/internal/docker/idlewatcher/waker.go b/internal/docker/idlewatcher/waker.go index 6af2381..0b6fce9 100644 --- a/internal/docker/idlewatcher/waker.go +++ b/internal/docker/idlewatcher/waker.go @@ -5,9 +5,9 @@ import ( "time" "github.com/yusing/go-proxy/internal/docker/idlewatcher/types" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/metrics" - "github.com/yusing/go-proxy/internal/net/http/reverseproxy" + "github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy" net "github.com/yusing/go-proxy/internal/net/types" route "github.com/yusing/go-proxy/internal/route/types" "github.com/yusing/go-proxy/internal/task" @@ -37,7 +37,7 @@ const ( // TODO: support stream -func newWaker(parent task.Parent, route route.Route, rp *reverseproxy.ReverseProxy, stream net.Stream) (Waker, E.Error) { +func newWaker(parent task.Parent, route route.Route, rp *reverseproxy.ReverseProxy, stream net.Stream) (Waker, gperr.Error) { hcCfg := route.HealthCheckConfig() hcCfg.Timeout = idleWakerCheckTimeout @@ -48,7 +48,7 @@ func newWaker(parent task.Parent, route route.Route, rp *reverseproxy.ReversePro task := parent.Subtask("idlewatcher." + route.TargetName()) watcher, err := registerWatcher(task, route, waker) if err != nil { - return nil, E.Errorf("register watcher: %w", err) + return nil, gperr.Errorf("register watcher: %w", err) } switch { @@ -66,16 +66,16 @@ func newWaker(parent task.Parent, route route.Route, rp *reverseproxy.ReversePro } // lifetime should follow route provider. -func NewHTTPWaker(parent task.Parent, route route.Route, rp *reverseproxy.ReverseProxy) (Waker, E.Error) { +func NewHTTPWaker(parent task.Parent, route route.Route, rp *reverseproxy.ReverseProxy) (Waker, gperr.Error) { return newWaker(parent, route, rp, nil) } -func NewStreamWaker(parent task.Parent, route route.Route, stream net.Stream) (Waker, E.Error) { +func NewStreamWaker(parent task.Parent, route route.Route, stream net.Stream) (Waker, gperr.Error) { return newWaker(parent, route, nil, stream) } // Start implements health.HealthMonitor. -func (w *Watcher) Start(parent task.Parent) E.Error { +func (w *Watcher) Start(parent task.Parent) gperr.Error { w.task.OnCancel("route_cleanup", func() { parent.Finish(w.task.FinishCause()) if w.metric != nil { diff --git a/internal/docker/idlewatcher/waker_http.go b/internal/docker/idlewatcher/waker_http.go index b3b7c9b..f3b1975 100644 --- a/internal/docker/idlewatcher/waker_http.go +++ b/internal/docker/idlewatcher/waker_http.go @@ -7,8 +7,8 @@ import ( "strconv" "time" - "github.com/yusing/go-proxy/internal/common" - gphttp "github.com/yusing/go-proxy/internal/net/http" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" "github.com/yusing/go-proxy/internal/watcher/health" ) @@ -63,7 +63,7 @@ func (w *Watcher) wakeFromHTTP(rw http.ResponseWriter, r *http.Request) (shouldN accept := gphttp.GetAccept(r.Header) acceptHTML := (r.Method == http.MethodGet && accept.AcceptHTML() || r.RequestURI == "/" && accept.IsEmpty()) - isCheckRedirect := r.Header.Get(common.HeaderCheckRedirect) != "" + isCheckRedirect := r.Header.Get(httpheaders.HeaderGoDoxyCheckRedirect) != "" if !isCheckRedirect && acceptHTML { // Send a loading response to the client body := w.makeLoadingPageBody() diff --git a/internal/docker/idlewatcher/watcher.go b/internal/docker/idlewatcher/watcher.go index bf35371..599579e 100644 --- a/internal/docker/idlewatcher/watcher.go +++ b/internal/docker/idlewatcher/watcher.go @@ -10,7 +10,7 @@ import ( "github.com/rs/zerolog" D "github.com/yusing/go-proxy/internal/docker" idlewatcher "github.com/yusing/go-proxy/internal/docker/idlewatcher/types" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" route "github.com/yusing/go-proxy/internal/route/types" "github.com/yusing/go-proxy/internal/task" @@ -180,7 +180,7 @@ func (w *Watcher) wakeIfStopped() error { case "running": return nil default: - return E.Errorf("unexpected container status: %s", status) + return gperr.Errorf("unexpected container status: %s", status) } } @@ -213,7 +213,7 @@ func (w *Watcher) expires() time.Time { return w.lastReset.Add(w.IdleTimeout) } -func (w *Watcher) getEventCh(dockerWatcher watcher.DockerWatcher) (eventCh <-chan events.Event, errCh <-chan E.Error) { +func (w *Watcher) getEventCh(dockerWatcher watcher.DockerWatcher) (eventCh <-chan events.Event, errCh <-chan gperr.Error) { eventCh, errCh = dockerWatcher.EventsWithOptions(w.Task().Context(), watcher.DockerListOptions{ Filters: watcher.NewDockerFilter( watcher.DockerFilterContainer, @@ -251,7 +251,7 @@ func (w *Watcher) watchUntilDestroy() (returnCause error) { return w.task.FinishCause() case err := <-dockerEventErrCh: if !err.Is(context.Canceled) { - E.LogError("idlewatcher error", err, &w.Logger) + gperr.LogError("idlewatcher error", err, &w.Logger) } return err case e := <-dockerEventCh: diff --git a/internal/docker/label.go b/internal/docker/label.go index 2dead0a..73de823 100644 --- a/internal/docker/label.go +++ b/internal/docker/label.go @@ -1,17 +1,17 @@ package docker import ( - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/utils/strutils" ) type LabelMap = map[string]any -var ErrInvalidLabel = E.New("invalid label") +var ErrInvalidLabel = gperr.New("invalid label") -func ParseLabels(labels map[string]string) (LabelMap, E.Error) { +func ParseLabels(labels map[string]string) (LabelMap, gperr.Error) { nestedMap := make(LabelMap) - errs := E.NewBuilder("labels error") + errs := gperr.NewBuilder("labels error") for lbl, value := range labels { parts := strutils.SplitRune(lbl, '.') @@ -37,7 +37,7 @@ func ParseLabels(labels map[string]string) (LabelMap, E.Error) { // Move deeper into the nested map m, ok := currentMap[k].(LabelMap) if !ok && currentMap[k] != "" { - errs.Add(E.Errorf("expect mapping, got %T", currentMap[k]).Subject(lbl)) + errs.Add(gperr.Errorf("expect mapping, got %T", currentMap[k]).Subject(lbl)) continue } else if !ok { m = make(LabelMap) diff --git a/internal/entrypoint/entrypoint.go b/internal/entrypoint/entrypoint.go index 3ab6dac..1a3a166 100644 --- a/internal/entrypoint/entrypoint.go +++ b/internal/entrypoint/entrypoint.go @@ -7,10 +7,10 @@ import ( "strings" "github.com/yusing/go-proxy/internal/logging" - gphttp "github.com/yusing/go-proxy/internal/net/http" - "github.com/yusing/go-proxy/internal/net/http/accesslog" - "github.com/yusing/go-proxy/internal/net/http/middleware" - "github.com/yusing/go-proxy/internal/net/http/middleware/errorpage" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware/errorpage" "github.com/yusing/go-proxy/internal/route/routes" route "github.com/yusing/go-proxy/internal/route/types" "github.com/yusing/go-proxy/internal/task" diff --git a/internal/gperr/README.md b/internal/gperr/README.md new file mode 100644 index 0000000..1ee390e --- /dev/null +++ b/internal/gperr/README.md @@ -0,0 +1,106 @@ +# gperr + +gperr is an error interface that supports nested structure and subject highlighting. + +## Usage + +### gperr.Error + +The error interface. + +### gperr.New + +Like `errors.New`, but returns a `gperr.Error`. + +### gperr.Wrap + +Like `fmt.Errorf("%s: %w", message, err)`, but returns a `gperr.Error`. + +### gperr.Error.Subject + +Returns a new error with the subject prepended to the error message. The main subject is highlighted. + +```go +err := gperr.New("error message") +err = err.Subject("bar") +err = err.Subject("foo") +``` + +Output: + +foo > bar: error message + +### gperr.Error.Subjectf + +Like `gperr.Error.Subject`, but formats the subject with `fmt.Sprintf`. + +### gperr.PrependSubject + +Prepends the subject to the error message like `gperr.Error.Subject`. + +```go +err := gperr.New("error message") +err = gperr.PrependSubject(err, "foo") +err = gperr.PrependSubject(err, "bar") +``` + +Output: + +bar > foo: error message + +### gperr.Error.With + +Adds a new error to the error chain. + +```go +err := gperr.New("error message") +err = err.With(gperr.New("inner error")) +err = err.With(gperr.New("inner error 2").With(gperr.New("inner inner error"))) +``` + +Output: + +``` +error message: + • inner error + • inner error 2 + • inner inner error +``` + +### gperr.Error.Withf + +Like `gperr.Error.With`, but formats the error with `fmt.Errorf`. + +### gperr.Error.Is + +Returns true if the error is equal to the given error. + +### gperr.Builder + +A builder for `gperr.Error`. + +```go +builder := gperr.NewBuilder("foo") +builder.Add(gperr.New("error message")) +builder.Addf("error message: %s", "foo") +builder.AddRange(gperr.New("error message 1"), gperr.New("error message 2")) +``` + +Output: + +``` +foo: + • error message + • error message: foo + • error message 1 + • error message 2 +``` + +### gperr.Builder.Build + +Builds a `gperr.Error` from the builder. + +## When to return gperr.Error + +- When you want to return multiple errors +- When the error has a subject diff --git a/internal/error/base.go b/internal/gperr/base.go similarity index 98% rename from internal/error/base.go rename to internal/gperr/base.go index 4668a11..96a36b3 100644 --- a/internal/error/base.go +++ b/internal/gperr/base.go @@ -1,4 +1,4 @@ -package err +package gperr import ( "encoding/json" diff --git a/internal/error/builder.go b/internal/gperr/builder.go similarity index 96% rename from internal/error/builder.go rename to internal/gperr/builder.go index 6a23f25..4eeee60 100644 --- a/internal/error/builder.go +++ b/internal/gperr/builder.go @@ -1,4 +1,4 @@ -package err +package gperr import ( "fmt" @@ -36,7 +36,7 @@ func (b *Builder) error() Error { func (b *Builder) Error() Error { if len(b.errs) == 1 { - return From(b.errs[0]) + return wrap(b.errs[0]) } return b.error() } @@ -60,7 +60,7 @@ func (b *Builder) Add(err error) *Builder { b.Lock() defer b.Unlock() - switch err := From(err).(type) { + switch err := wrap(err).(type) { case *baseError: b.errs = append(b.errs, err.Err) case *nestedError: diff --git a/internal/error/builder_test.go b/internal/gperr/builder_test.go similarity index 94% rename from internal/error/builder_test.go rename to internal/gperr/builder_test.go index 2975e4a..04aa326 100644 --- a/internal/error/builder_test.go +++ b/internal/gperr/builder_test.go @@ -1,4 +1,4 @@ -package err_test +package gperr_test import ( "context" @@ -6,7 +6,7 @@ import ( "io" "testing" - . "github.com/yusing/go-proxy/internal/error" + . "github.com/yusing/go-proxy/internal/gperr" . "github.com/yusing/go-proxy/internal/utils/testing" ) diff --git a/internal/error/error.go b/internal/gperr/error.go similarity index 98% rename from internal/error/error.go rename to internal/gperr/error.go index 03e0079..6d3e70c 100644 --- a/internal/error/error.go +++ b/internal/gperr/error.go @@ -1,4 +1,4 @@ -package err +package gperr type Error interface { error diff --git a/internal/error/error_test.go b/internal/gperr/error_test.go similarity index 96% rename from internal/error/error_test.go rename to internal/gperr/error_test.go index ad3aca7..81d0139 100644 --- a/internal/error/error_test.go +++ b/internal/gperr/error_test.go @@ -1,4 +1,4 @@ -package err +package gperr import ( "errors" @@ -44,7 +44,7 @@ func TestBaseWithExtra(t *testing.T) { func TestBaseUnwrap(t *testing.T) { err := errors.New("err") - wrapped := From(err) + wrapped := Wrap(err) ExpectError(t, err, errors.Unwrap(wrapped)) } @@ -52,7 +52,7 @@ func TestBaseUnwrap(t *testing.T) { func TestNestedUnwrap(t *testing.T) { err := errors.New("err") err2 := New("err2") - wrapped := From(err).Subject("foo").With(err2.Subject("bar")) + wrapped := Wrap(err).Subject("foo").With(err2.Subject("bar")) unwrapper, ok := wrapped.(interface{ Unwrap() []error }) ExpectTrue(t, ok) @@ -64,7 +64,7 @@ func TestNestedUnwrap(t *testing.T) { func TestErrorIs(t *testing.T) { from := errors.New("error") - err := From(from) + err := Wrap(from) ExpectError(t, from, err) ExpectTrue(t, err.Is(from)) diff --git a/internal/error/log.go b/internal/gperr/log.go similarity index 50% rename from internal/error/log.go rename to internal/gperr/log.go index 0729023..94c2d15 100644 --- a/internal/error/log.go +++ b/internal/gperr/log.go @@ -1,4 +1,4 @@ -package err +package gperr import ( "github.com/rs/zerolog" @@ -6,42 +6,35 @@ import ( "github.com/yusing/go-proxy/internal/logging" ) -func getLogger(logger ...*zerolog.Logger) *zerolog.Logger { +func log(msg string, err error, level zerolog.Level, logger ...*zerolog.Logger) { + var l *zerolog.Logger if len(logger) > 0 { - return logger[0] + l = logger[0] + } else { + l = logging.GetLogger() } - return logging.GetLogger() + l.WithLevel(level).Msg(msg + ": " + err.Error()) } -//go:inline func LogFatal(msg string, err error, logger ...*zerolog.Logger) { if common.IsDebug { LogPanic(msg, err, logger...) } - getLogger(logger...).Fatal().Msg(err.Error()) + log(msg, err, zerolog.FatalLevel, logger...) } -//go:inline func LogError(msg string, err error, logger ...*zerolog.Logger) { - getLogger(logger...).Error().Msg(err.Error()) + log(msg, err, zerolog.ErrorLevel, logger...) } -//go:inline func LogWarn(msg string, err error, logger ...*zerolog.Logger) { - getLogger(logger...).Warn().Msg(err.Error()) + log(msg, err, zerolog.WarnLevel, logger...) } -//go:inline func LogPanic(msg string, err error, logger ...*zerolog.Logger) { - getLogger(logger...).Panic().Msg(err.Error()) + log(msg, err, zerolog.PanicLevel, logger...) } -//go:inline -func LogInfo(msg string, err error, logger ...*zerolog.Logger) { - getLogger(logger...).Info().Msg(err.Error()) -} - -//go:inline func LogDebug(msg string, err error, logger ...*zerolog.Logger) { - getLogger(logger...).Debug().Msg(err.Error()) + log(msg, err, zerolog.DebugLevel, logger...) } diff --git a/internal/error/nested_error.go b/internal/gperr/nested_error.go similarity index 97% rename from internal/error/nested_error.go rename to internal/gperr/nested_error.go index e666a4f..dc97d87 100644 --- a/internal/error/nested_error.go +++ b/internal/gperr/nested_error.go @@ -1,4 +1,4 @@ -package err +package gperr import ( "errors" @@ -99,7 +99,7 @@ func makeLines(errs []error, level int) []string { } lines := make([]string, 0, len(errs)) for _, err := range errs { - switch err := From(err).(type) { + switch err := wrap(err).(type) { case *nestedError: if err.Err != nil { lines = append(lines, makeLine(err.Err.Error(), level)) diff --git a/internal/error/subject.go b/internal/gperr/subject.go similarity index 99% rename from internal/error/subject.go rename to internal/gperr/subject.go index eac7499..293b648 100644 --- a/internal/error/subject.go +++ b/internal/gperr/subject.go @@ -1,4 +1,4 @@ -package err +package gperr import ( "encoding/json" diff --git a/internal/error/utils.go b/internal/gperr/utils.go similarity index 60% rename from internal/error/utils.go rename to internal/gperr/utils.go index 8e36f83..4ac1d64 100644 --- a/internal/error/utils.go +++ b/internal/gperr/utils.go @@ -1,6 +1,8 @@ -package err +package gperr import ( + "encoding/json" + "errors" "fmt" ) @@ -19,27 +21,50 @@ func Errorf(format string, args ...any) Error { return &baseError{fmt.Errorf(format, args...)} } +// Wrap wraps message in front of the error message. func Wrap(err error, message ...string) Error { - if len(message) == 0 || message[0] == "" { - return From(err) + if err == nil { + return nil } - return Errorf("%s: %w", message[0], err) + if len(message) == 0 || message[0] == "" { + return wrap(err) + } + //nolint:errorlint + switch err := err.(type) { + case *baseError: + err.Err = fmt.Errorf("%s: %w", message[0], err.Err) + return err + case *nestedError: + err.Err = fmt.Errorf("%s: %w", message[0], err.Err) + return err + } + return &baseError{fmt.Errorf("%s: %w", message[0], err)} } -func From(err error) Error { +func wrap(err error) Error { if err == nil { return nil } //nolint:errorlint switch err := err.(type) { - case *baseError: - return err - case *nestedError: + case Error: return err } return &baseError{err} } +func IsJSONMarshallable(err error) bool { + switch err := err.(type) { + case *nestedError, *withSubject: + return true + case *baseError: + return IsJSONMarshallable(err.Err) + default: + var v json.Marshaler + return errors.As(err, &v) + } +} + func Join(errors ...error) Error { n := 0 for _, err := range errors { diff --git a/internal/gperr/utils_test.go b/internal/gperr/utils_test.go new file mode 100644 index 0000000..7298f80 --- /dev/null +++ b/internal/gperr/utils_test.go @@ -0,0 +1,58 @@ +package gperr + +import ( + "errors" + "testing" +) + +type testErr struct{} + +func (e *testErr) Error() string { + return "test error" +} + +func (e *testErr) MarshalJSON() ([]byte, error) { + return nil, nil +} + +func TestIsJSONMarshallable(t *testing.T) { + tests := []struct { + name string + err error + want bool + }{ + { + name: "testErr", + err: &testErr{}, + want: true, + }, + { + name: "baseError", + err: &baseError{}, + want: true, + }, + { + name: "nestedError", + err: &nestedError{}, + want: true, + }, + { + name: "withSubject", + err: &withSubject{}, + want: true, + }, + { + name: "standard error", + err: errors.New("test error"), + want: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if got := IsJSONMarshallable(test.err); got != test.want { + t.Errorf("IsJSONMarshallable(%v) = %v, want %v", test.err, got, test.want) + } + }) + } +} diff --git a/internal/homepage/icon_url.go b/internal/homepage/icon_url.go index f5265a4..f53060d 100644 --- a/internal/homepage/icon_url.go +++ b/internal/homepage/icon_url.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/yusing/go-proxy/internal" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) type ( @@ -31,7 +31,7 @@ const ( IconSourceSelfhSt ) -var ErrInvalidIconURL = E.New("invalid icon url") +var ErrInvalidIconURL = gperr.New("invalid icon url") func NewSelfhStIconURL(reference, format string) *IconURL { return &IconURL{ diff --git a/internal/logging/memlogger/mem_logger.go b/internal/logging/memlogger/mem_logger.go index 5904b84..deff058 100644 --- a/internal/logging/memlogger/mem_logger.go +++ b/internal/logging/memlogger/mem_logger.go @@ -11,9 +11,10 @@ import ( "github.com/coder/websocket" "github.com/rs/zerolog" - "github.com/yusing/go-proxy/internal/api/v1/utils" "github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/logging" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/gpwebsocket" "github.com/yusing/go-proxy/internal/task" F "github.com/yusing/go-proxy/internal/utils/functional" ) @@ -27,8 +28,9 @@ type memLogger struct { sync.RWMutex notifyLock sync.RWMutex connChans F.Map[chan *logEntryRange, struct{}] + listeners F.Map[chan []byte, struct{}] - bufPool sync.Pool // used in hook mode + bufPool sync.Pool } type MemLogger io.Writer @@ -41,15 +43,16 @@ const ( maxMemLogSize = 16 * 1024 truncateSize = maxMemLogSize / 2 initialWriteChunkSize = 4 * 1024 - hookModeBufSize = 256 + bufPoolSize = 256 ) var memLoggerInstance = &memLogger{ connChans: F.NewMapOf[chan *logEntryRange, struct{}](), + listeners: F.NewMapOf[chan []byte, struct{}](), bufPool: sync.Pool{ New: func() any { return &buffer{ - data: make([]byte, 0, hookModeBufSize), + data: make([]byte, 0, bufPoolSize), } }, }, @@ -92,6 +95,10 @@ func HandlerFunc() http.HandlerFunc { return memLoggerInstance.ServeHTTP } +func Events() (<-chan []byte, func()) { + return memLoggerInstance.events() +} + func (m *memLogger) truncateIfNeeded(n int) { m.RLock() needTruncate := m.Len()+n > maxMemLogSize @@ -111,7 +118,7 @@ func (m *memLogger) truncateIfNeeded(n int) { func (m *memLogger) notifyWS(pos, n int) { if m.connChans.Size() > 0 { - timeout := time.NewTimer(1 * time.Second) + timeout := time.NewTimer(2 * time.Second) defer timeout.Stop() m.notifyLock.RLock() @@ -125,6 +132,19 @@ func (m *memLogger) notifyWS(pos, n int) { return false } }) + if m.listeners.Size() > 0 { + msg := make([]byte, n) + copy(msg, m.Buffer.Bytes()[pos:pos+n]) + m.listeners.Range(func(ch chan []byte, _ struct{}) bool { + select { + case <-timeout.C: + logging.Warn().Msg("mem logger: timeout logging to channel") + return false + case ch <- msg: + return true + } + }) + } return } } @@ -153,9 +173,9 @@ func (m *memLogger) Write(p []byte) (n int, err error) { } func (m *memLogger) ServeHTTP(w http.ResponseWriter, r *http.Request) { - conn, err := utils.InitiateWS(w, r) + conn, err := gpwebsocket.Initiate(w, r) if err != nil { - utils.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } @@ -172,13 +192,27 @@ func (m *memLogger) ServeHTTP(w http.ResponseWriter, r *http.Request) { }() if err := m.wsInitial(r.Context(), conn); err != nil { - utils.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } m.wsStreamLog(r.Context(), conn, logCh) } +func (m *memLogger) events() (<-chan []byte, func()) { + ch := make(chan []byte, 10) + m.notifyLock.Lock() + defer m.notifyLock.Unlock() + m.listeners.Store(ch, struct{}{}) + + return ch, func() { + m.notifyLock.Lock() + defer m.notifyLock.Unlock() + m.listeners.Delete(ch) + close(ch) + } +} + func (m *memLogger) writeBytes(ctx context.Context, conn *websocket.Conn, b []byte) error { return conn.Write(ctx, websocket.MessageText, b) } diff --git a/internal/metrics/period/handler.go b/internal/metrics/period/handler.go index af6ead0..40f7cfe 100644 --- a/internal/metrics/period/handler.go +++ b/internal/metrics/period/handler.go @@ -7,9 +7,10 @@ import ( "github.com/coder/websocket" "github.com/coder/websocket/wsjson" - "github.com/yusing/go-proxy/internal/api/v1/utils" metricsutils "github.com/yusing/go-proxy/internal/metrics/utils" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/gpwebsocket" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" ) // ServeHTTP serves the data for the given period. @@ -36,7 +37,7 @@ func (p *Poller[T, AggregateT]) ServeHTTP(w http.ResponseWriter, r *http.Request if interval < minInterval { interval = minInterval } - utils.PeriodicWS(w, r, interval, func(conn *websocket.Conn) error { + gpwebsocket.Periodic(w, r, interval, func(conn *websocket.Conn) error { data, err := p.getRespData(r) if err != nil { return err @@ -49,14 +50,14 @@ func (p *Poller[T, AggregateT]) ServeHTTP(w http.ResponseWriter, r *http.Request } else { data, err := p.getRespData(r) if err != nil { - utils.HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } if data == nil { http.Error(w, "no data", http.StatusNoContent) return } - utils.RespondJSON(w, r, data) + gphttp.RespondJSON(w, r, data) } } diff --git a/internal/metrics/period/poller.go b/internal/metrics/period/poller.go index 7a2ef3e..3ff9da9 100644 --- a/internal/metrics/period/poller.go +++ b/internal/metrics/period/poller.go @@ -6,7 +6,7 @@ import ( "net/url" "time" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/task" ) @@ -84,7 +84,7 @@ func (p *Poller[T, AggregateT]) gatherErrs() (string, bool) { if len(p.errs) == 0 { return "", false } - errs := E.NewBuilder(fmt.Sprintf("poller %s has encountered %d errors in the last %s:", p.name, len(p.errs), gatherErrsInterval)) + errs := gperr.NewBuilder(fmt.Sprintf("poller %s has encountered %d errors in the last %s:", p.name, len(p.errs), gatherErrsInterval)) for _, e := range p.errs { errs.Addf("%w: %d times", e.err, e.count) } diff --git a/internal/metrics/systeminfo/system_info.go b/internal/metrics/systeminfo/system_info.go index 4ef766b..27854d7 100644 --- a/internal/metrics/systeminfo/system_info.go +++ b/internal/metrics/systeminfo/system_info.go @@ -12,7 +12,7 @@ import ( "github.com/shirou/gopsutil/v4/net" "github.com/shirou/gopsutil/v4/sensors" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/metrics/period" "github.com/yusing/go-proxy/internal/utils/strutils" @@ -40,7 +40,7 @@ func _() { // check if this behavior is not changed } func getSystemInfo(ctx context.Context, lastResult *SystemInfo) (*SystemInfo, error) { - errs := E.NewBuilder("failed to get system info") + errs := gperr.NewBuilder("failed to get system info") var systemInfo SystemInfo if !common.MetricsDisableCPU { @@ -95,8 +95,8 @@ func getSystemInfo(ctx context.Context, lastResult *SystemInfo) (*SystemInfo, er } if errs.HasError() { - allWarnings := E.NewBuilder("") - allErrors := E.NewBuilder("failed to get system info") + allWarnings := gperr.NewBuilder("") + allErrors := gperr.NewBuilder("failed to get system info") errs.ForEach(func(err error) { // disk.Warnings has the same type // all Warnings are alias of common.Warnings from "github.com/shirou/gopsutil/v4/internal/common" diff --git a/internal/net/http/accesslog/access_logger.go b/internal/net/gphttp/accesslog/access_logger.go similarity index 97% rename from internal/net/http/accesslog/access_logger.go rename to internal/net/gphttp/accesslog/access_logger.go index 16c10d4..36e7486 100644 --- a/internal/net/http/accesslog/access_logger.go +++ b/internal/net/gphttp/accesslog/access_logger.go @@ -7,7 +7,7 @@ import ( "sync" "time" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/task" ) @@ -131,7 +131,7 @@ func (l *AccessLogger) Flush(force bool) { } func (l *AccessLogger) handleErr(err error) { - E.LogError("failed to write access log", err) + gperr.LogError("failed to write access log", err) } func (l *AccessLogger) start() { diff --git a/internal/net/http/accesslog/access_logger_test.go b/internal/net/gphttp/accesslog/access_logger_test.go similarity index 98% rename from internal/net/http/accesslog/access_logger_test.go rename to internal/net/gphttp/accesslog/access_logger_test.go index 2398ca7..012d8eb 100644 --- a/internal/net/http/accesslog/access_logger_test.go +++ b/internal/net/gphttp/accesslog/access_logger_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - . "github.com/yusing/go-proxy/internal/net/http/accesslog" + . "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" "github.com/yusing/go-proxy/internal/task" . "github.com/yusing/go-proxy/internal/utils/testing" ) diff --git a/internal/net/http/accesslog/config.go b/internal/net/gphttp/accesslog/config.go similarity index 100% rename from internal/net/http/accesslog/config.go rename to internal/net/gphttp/accesslog/config.go diff --git a/internal/net/http/accesslog/config_test.go b/internal/net/gphttp/accesslog/config_test.go similarity index 97% rename from internal/net/http/accesslog/config_test.go rename to internal/net/gphttp/accesslog/config_test.go index 125b501..e8de01d 100644 --- a/internal/net/http/accesslog/config_test.go +++ b/internal/net/gphttp/accesslog/config_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/yusing/go-proxy/internal/docker" - . "github.com/yusing/go-proxy/internal/net/http/accesslog" + . "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" "github.com/yusing/go-proxy/internal/utils" . "github.com/yusing/go-proxy/internal/utils/testing" ) diff --git a/internal/net/http/accesslog/fields.go b/internal/net/gphttp/accesslog/fields.go similarity index 100% rename from internal/net/http/accesslog/fields.go rename to internal/net/gphttp/accesslog/fields.go diff --git a/internal/net/http/accesslog/fields_test.go b/internal/net/gphttp/accesslog/fields_test.go similarity index 97% rename from internal/net/http/accesslog/fields_test.go rename to internal/net/gphttp/accesslog/fields_test.go index feac44d..1cfa370 100644 --- a/internal/net/http/accesslog/fields_test.go +++ b/internal/net/gphttp/accesslog/fields_test.go @@ -3,7 +3,7 @@ package accesslog_test import ( "testing" - . "github.com/yusing/go-proxy/internal/net/http/accesslog" + . "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" . "github.com/yusing/go-proxy/internal/utils/testing" ) diff --git a/internal/net/http/accesslog/file_logger.go b/internal/net/gphttp/accesslog/file_logger.go similarity index 100% rename from internal/net/http/accesslog/file_logger.go rename to internal/net/gphttp/accesslog/file_logger.go diff --git a/internal/net/http/accesslog/file_logger_test.go b/internal/net/gphttp/accesslog/file_logger_test.go similarity index 100% rename from internal/net/http/accesslog/file_logger_test.go rename to internal/net/gphttp/accesslog/file_logger_test.go diff --git a/internal/net/http/accesslog/filter.go b/internal/net/gphttp/accesslog/filter.go similarity index 94% rename from internal/net/http/accesslog/filter.go rename to internal/net/gphttp/accesslog/filter.go index 822101e..c0c3e29 100644 --- a/internal/net/http/accesslog/filter.go +++ b/internal/net/gphttp/accesslog/filter.go @@ -5,7 +5,7 @@ import ( "net/http" "strings" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/net/types" "github.com/yusing/go-proxy/internal/utils/strutils" ) @@ -27,7 +27,7 @@ type ( CIDR struct{ types.CIDR } ) -var ErrInvalidHTTPHeaderFilter = E.New("invalid http header filter") +var ErrInvalidHTTPHeaderFilter = gperr.New("invalid http header filter") func (f *LogFilter[T]) CheckKeep(req *http.Request, res *http.Response) bool { if len(f.Values) == 0 { diff --git a/internal/net/http/accesslog/filter_test.go b/internal/net/gphttp/accesslog/filter_test.go similarity index 98% rename from internal/net/http/accesslog/filter_test.go rename to internal/net/gphttp/accesslog/filter_test.go index 7160dce..a934a7b 100644 --- a/internal/net/http/accesslog/filter_test.go +++ b/internal/net/gphttp/accesslog/filter_test.go @@ -4,7 +4,7 @@ import ( "net/http" "testing" - . "github.com/yusing/go-proxy/internal/net/http/accesslog" + . "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" "github.com/yusing/go-proxy/internal/utils/strutils" . "github.com/yusing/go-proxy/internal/utils/testing" ) diff --git a/internal/net/http/accesslog/formatter.go b/internal/net/gphttp/accesslog/formatter.go similarity index 100% rename from internal/net/http/accesslog/formatter.go rename to internal/net/gphttp/accesslog/formatter.go diff --git a/internal/net/http/accesslog/mock_file.go b/internal/net/gphttp/accesslog/mock_file.go similarity index 100% rename from internal/net/http/accesslog/mock_file.go rename to internal/net/gphttp/accesslog/mock_file.go diff --git a/internal/net/http/accesslog/retention.go b/internal/net/gphttp/accesslog/retention.go similarity index 96% rename from internal/net/http/accesslog/retention.go rename to internal/net/gphttp/accesslog/retention.go index da31544..bf8b4c8 100644 --- a/internal/net/http/accesslog/retention.go +++ b/internal/net/gphttp/accesslog/retention.go @@ -7,7 +7,7 @@ import ( "strconv" "time" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/utils/strutils" ) @@ -19,8 +19,8 @@ type Retention struct { const chunkSizeMax int64 = 128 * 1024 // 128KB var ( - ErrInvalidSyntax = E.New("invalid syntax") - ErrZeroValue = E.New("zero value") + ErrInvalidSyntax = gperr.New("invalid syntax") + ErrZeroValue = gperr.New("zero value") ) // Syntax: diff --git a/internal/net/http/accesslog/retention_test.go b/internal/net/gphttp/accesslog/retention_test.go similarity index 96% rename from internal/net/http/accesslog/retention_test.go rename to internal/net/gphttp/accesslog/retention_test.go index ea51fe2..ccb3b5d 100644 --- a/internal/net/http/accesslog/retention_test.go +++ b/internal/net/gphttp/accesslog/retention_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - . "github.com/yusing/go-proxy/internal/net/http/accesslog" + . "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" "github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/utils/strutils" . "github.com/yusing/go-proxy/internal/utils/testing" diff --git a/internal/net/http/accesslog/status_code_range.go b/internal/net/gphttp/accesslog/status_code_range.go similarity index 81% rename from internal/net/http/accesslog/status_code_range.go rename to internal/net/gphttp/accesslog/status_code_range.go index 599f119..7ec94a2 100644 --- a/internal/net/http/accesslog/status_code_range.go +++ b/internal/net/gphttp/accesslog/status_code_range.go @@ -3,7 +3,7 @@ package accesslog import ( "strconv" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/utils/strutils" ) @@ -12,7 +12,7 @@ type StatusCodeRange struct { End int } -var ErrInvalidStatusCodeRange = E.New("invalid status code range") +var ErrInvalidStatusCodeRange = gperr.New("invalid status code range") func (r *StatusCodeRange) Includes(code int) bool { return r.Start <= code && code <= r.End @@ -25,7 +25,7 @@ func (r *StatusCodeRange) Parse(v string) error { case 1: start, err := strconv.Atoi(split[0]) if err != nil { - return E.From(err) + return gperr.Wrap(err) } r.Start = start r.End = start @@ -33,7 +33,7 @@ func (r *StatusCodeRange) Parse(v string) error { case 2: start, errStart := strconv.Atoi(split[0]) end, errEnd := strconv.Atoi(split[1]) - if err := E.Join(errStart, errEnd); err != nil { + if err := gperr.Join(errStart, errEnd); err != nil { return err } r.Start = start diff --git a/internal/api/v1/utils/utils.go b/internal/net/gphttp/body.go similarity index 65% rename from internal/api/v1/utils/utils.go rename to internal/net/gphttp/body.go index 48d4457..3a94023 100644 --- a/internal/api/v1/utils/utils.go +++ b/internal/net/gphttp/body.go @@ -1,7 +1,9 @@ -package utils +package gphttp import ( + "context" "encoding/json" + "errors" "fmt" "net/http" @@ -10,7 +12,13 @@ import ( func WriteBody(w http.ResponseWriter, body []byte) { if _, err := w.Write(body); err != nil { - logging.Err(err).Msg("failed to write body") + switch { + case errors.Is(err, http.ErrHandlerTimeout), + errors.Is(err, context.DeadlineExceeded): + logging.Err(err).Msg("timeout writing body") + default: + logging.Err(err).Msg("failed to write body") + } } } @@ -25,13 +33,13 @@ func RespondJSON(w http.ResponseWriter, r *http.Request, data any, code ...int) case string: _, err = w.Write([]byte(fmt.Sprintf("%q", data))) case []byte: - _, err = w.Write(data) + panic("use WriteBody instead") default: err = json.NewEncoder(w).Encode(data) } if err != nil { - HandleErr(w, r, err) + LogError(r).Err(err).Msg("failed to encode json") return false } return true diff --git a/internal/net/http/content_type.go b/internal/net/gphttp/content_type.go similarity index 98% rename from internal/net/http/content_type.go rename to internal/net/gphttp/content_type.go index 3b4be65..dee78ff 100644 --- a/internal/net/http/content_type.go +++ b/internal/net/gphttp/content_type.go @@ -1,4 +1,4 @@ -package http +package gphttp import ( "mime" diff --git a/internal/net/http/content_type_test.go b/internal/net/gphttp/content_type_test.go similarity index 99% rename from internal/net/http/content_type_test.go rename to internal/net/gphttp/content_type_test.go index ee4ea56..f5bba69 100644 --- a/internal/net/http/content_type_test.go +++ b/internal/net/gphttp/content_type_test.go @@ -1,4 +1,4 @@ -package http +package gphttp import ( "net/http" diff --git a/internal/api/v1/utils/http_client.go b/internal/net/gphttp/default_client.go similarity index 65% rename from internal/api/v1/utils/http_client.go rename to internal/net/gphttp/default_client.go index 48d743b..dee455a 100644 --- a/internal/api/v1/utils/http_client.go +++ b/internal/net/gphttp/default_client.go @@ -1,22 +1,21 @@ -package utils +package gphttp import ( "crypto/tls" "net" "net/http" - - "github.com/yusing/go-proxy/internal/common" + "time" ) var ( httpClient = &http.Client{ - Timeout: common.ConnectionTimeout, + Timeout: 5 * time.Second, Transport: &http.Transport{ DisableKeepAlives: true, ForceAttemptHTTP2: false, DialContext: (&net.Dialer{ - Timeout: common.DialTimeout, - KeepAlive: common.KeepAlive, // this is different from DisableKeepAlives + Timeout: 3 * time.Second, + KeepAlive: 60 * time.Second, // this is different from DisableKeepAlives }).DialContext, TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, diff --git a/internal/net/gphttp/error.go b/internal/net/gphttp/error.go new file mode 100644 index 0000000..060fac5 --- /dev/null +++ b/internal/net/gphttp/error.go @@ -0,0 +1,95 @@ +package gphttp + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "syscall" + + "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" +) + +// ServerError is for handling server errors. +// +// It logs the error and returns http.StatusInternalServerError to the client. +// Status code can be specified as an argument. +func ServerError(w http.ResponseWriter, r *http.Request, err error, code ...int) { + switch { + case err == nil, + errors.Is(err, context.Canceled), + errors.Is(err, syscall.EPIPE), + errors.Is(err, syscall.ECONNRESET): + return + } + LogError(r).Msg(err.Error()) + if httpheaders.IsWebsocket(r.Header) { + return + } + if len(code) == 0 { + code = []int{http.StatusInternalServerError} + } + http.Error(w, http.StatusText(code[0]), code[0]) +} + +// ClientError is for responding to client errors. +// +// It returns http.StatusBadRequest with reason to the client. +// Status code can be specified as an argument. +// +// For JSON marshallable errors (e.g. gperr.Error), it returns the error details as JSON. +// Otherwise, it returns the error details as plain text. +func ClientError(w http.ResponseWriter, err error, code ...int) { + if len(code) == 0 { + code = []int{http.StatusBadRequest} + } + if gperr.IsJSONMarshallable(err) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(err) + } else { + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + } + http.Error(w, err.Error(), code[0]) +} + +// JSONError returns a JSON response of gperr.Error with the given status code. +func JSONError(w http.ResponseWriter, err gperr.Error, code int) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(err) + http.Error(w, err.Error(), code) +} + +// BadRequest returns a Bad Request response with the given error message. +func BadRequest(w http.ResponseWriter, err string, code ...int) { + if len(code) == 0 { + code = []int{http.StatusBadRequest} + } + http.Error(w, err, code[0]) +} + +// Unauthorized returns an Unauthorized response with the given error message. +func Unauthorized(w http.ResponseWriter, err string) { + BadRequest(w, err, http.StatusUnauthorized) +} + +// NotFound returns a Not Found response with the given error message. +func NotFound(w http.ResponseWriter, err string) { + BadRequest(w, err, http.StatusNotFound) +} + +func ErrMissingKey(k string) error { + return gperr.New(k + " is required") +} + +func ErrInvalidKey(k string) error { + return gperr.New(k + " is invalid") +} + +func ErrAlreadyExists(k, v string) error { + return gperr.Errorf("%s %q already exists", k, v) +} + +func ErrNotFound(k, v string) error { + return gperr.Errorf("%s %q not found", k, v) +} diff --git a/internal/api/v1/utils/ws.go b/internal/net/gphttp/gpwebsocket/utils.go similarity index 57% rename from internal/api/v1/utils/ws.go rename to internal/net/gphttp/gpwebsocket/utils.go index aa2f985..cb67dd6 100644 --- a/internal/api/v1/utils/ws.go +++ b/internal/net/gphttp/gpwebsocket/utils.go @@ -1,4 +1,4 @@ -package utils +package gpwebsocket import ( "net/http" @@ -7,8 +7,10 @@ import ( "github.com/coder/websocket" "github.com/yusing/go-proxy/internal/common" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" ) func warnNoMatchDomains() { @@ -17,7 +19,7 @@ func warnNoMatchDomains() { var warnNoMatchDomainOnce sync.Once -func InitiateWS(w http.ResponseWriter, r *http.Request) (*websocket.Conn, error) { +func Initiate(w http.ResponseWriter, r *http.Request) (*websocket.Conn, error) { var originPats []string localAddresses := []string{"127.0.0.1", "10.0.*.*", "172.16.*.*", "192.168.*.*"} @@ -42,17 +44,17 @@ func InitiateWS(w http.ResponseWriter, r *http.Request) (*websocket.Conn, error) }) } -func PeriodicWS(w http.ResponseWriter, r *http.Request, interval time.Duration, do func(conn *websocket.Conn) error) { - conn, err := InitiateWS(w, r) +func Periodic(w http.ResponseWriter, r *http.Request, interval time.Duration, do func(conn *websocket.Conn) error) { + conn, err := Initiate(w, r) if err != nil { - HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } //nolint:errcheck defer conn.CloseNow() if err := do(conn); err != nil { - HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } @@ -65,9 +67,20 @@ func PeriodicWS(w http.ResponseWriter, r *http.Request, interval time.Duration, return case <-ticker.C: if err := do(conn); err != nil { - HandleErr(w, r, err) + gphttp.ServerError(w, r, err) return } } } } + +// WriteText writes a text message to the websocket connection. +// It returns true if the message was written successfully, false otherwise. +// It logs an error if the message is not written successfully. +func WriteText(r *http.Request, conn *websocket.Conn, msg string) bool { + if err := conn.Write(r.Context(), websocket.MessageText, []byte(msg)); err != nil { + gperr.LogError("failed to write text message", err) + return false + } + return true +} diff --git a/internal/net/http/httpheaders/sse.go b/internal/net/gphttp/httpheaders/sse.go similarity index 100% rename from internal/net/http/httpheaders/sse.go rename to internal/net/gphttp/httpheaders/sse.go diff --git a/internal/net/http/httpheaders/utils.go b/internal/net/gphttp/httpheaders/utils.go similarity index 91% rename from internal/net/http/httpheaders/utils.go rename to internal/net/gphttp/httpheaders/utils.go index 20e892b..00bed76 100644 --- a/internal/net/http/httpheaders/utils.go +++ b/internal/net/gphttp/httpheaders/utils.go @@ -17,13 +17,15 @@ const ( HeaderXForwardedURI = "X-Forwarded-Uri" HeaderXRealIP = "X-Real-IP" - HeaderUpstreamName = "X-GoDoxy-Upstream-Name" - HeaderUpstreamScheme = "X-GoDoxy-Upstream-Scheme" - HeaderUpstreamHost = "X-GoDoxy-Upstream-Host" - HeaderUpstreamPort = "X-GoDoxy-Upstream-Port" - HeaderContentType = "Content-Type" HeaderContentLength = "Content-Length" + + HeaderUpstreamName = "X-Godoxy-Upstream-Name" + HeaderUpstreamScheme = "X-Godoxy-Upstream-Scheme" + HeaderUpstreamHost = "X-Godoxy-Upstream-Host" + HeaderUpstreamPort = "X-Godoxy-Upstream-Port" + + HeaderGoDoxyCheckRedirect = "X-Godoxy-Check-Redirect" ) // Hop-by-hop headers. These are removed when sent to the backend. diff --git a/internal/net/http/httpheaders/websocket.go b/internal/net/gphttp/httpheaders/websocket.go similarity index 100% rename from internal/net/http/httpheaders/websocket.go rename to internal/net/gphttp/httpheaders/websocket.go diff --git a/internal/net/http/loadbalancer/ip_hash.go b/internal/net/gphttp/loadbalancer/ip_hash.go similarity index 89% rename from internal/net/http/loadbalancer/ip_hash.go rename to internal/net/gphttp/loadbalancer/ip_hash.go index 384f7cf..d8a54ed 100644 --- a/internal/net/http/loadbalancer/ip_hash.go +++ b/internal/net/gphttp/loadbalancer/ip_hash.go @@ -6,8 +6,8 @@ import ( "net/http" "sync" - E "github.com/yusing/go-proxy/internal/error" - "github.com/yusing/go-proxy/internal/net/http/middleware" + "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware" ) type ipHash struct { @@ -23,10 +23,10 @@ func (lb *LoadBalancer) newIPHash() impl { if len(lb.Options) == 0 { return impl } - var err E.Error + var err gperr.Error impl.realIP, err = middleware.RealIP.New(lb.Options) if err != nil { - E.LogError("invalid real_ip options, ignoring", err, &impl.l) + gperr.LogError("invalid real_ip options, ignoring", err, &impl.l) } return impl } diff --git a/internal/net/http/loadbalancer/least_conn.go b/internal/net/gphttp/loadbalancer/least_conn.go similarity index 100% rename from internal/net/http/loadbalancer/least_conn.go rename to internal/net/gphttp/loadbalancer/least_conn.go diff --git a/internal/net/http/loadbalancer/loadbalancer.go b/internal/net/gphttp/loadbalancer/loadbalancer.go similarity index 95% rename from internal/net/http/loadbalancer/loadbalancer.go rename to internal/net/gphttp/loadbalancer/loadbalancer.go index b453648..fa3e413 100644 --- a/internal/net/http/loadbalancer/loadbalancer.go +++ b/internal/net/gphttp/loadbalancer/loadbalancer.go @@ -6,10 +6,10 @@ import ( "time" "github.com/rs/zerolog" - "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" - "github.com/yusing/go-proxy/internal/net/http/loadbalancer/types" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types" "github.com/yusing/go-proxy/internal/route/routes" "github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/watcher/health" @@ -54,7 +54,7 @@ func New(cfg *Config) *LoadBalancer { } // Start implements task.TaskStarter. -func (lb *LoadBalancer) Start(parent task.Parent) E.Error { +func (lb *LoadBalancer) Start(parent task.Parent) gperr.Error { lb.startTime = time.Now() lb.task = parent.Subtask("loadbalancer."+lb.Link, false) parent.OnCancel("lb_remove_route", func() { @@ -227,7 +227,7 @@ func (lb *LoadBalancer) ServeHTTP(rw http.ResponseWriter, r *http.Request) { http.Error(rw, "Service unavailable", http.StatusServiceUnavailable) return } - if r.Header.Get(common.HeaderCheckRedirect) != "" { + if r.Header.Get(httpheaders.HeaderGoDoxyCheckRedirect) != "" { // wake all servers for _, srv := range srvs { if err := srv.TryWake(); err != nil { diff --git a/internal/net/http/loadbalancer/loadbalancer_test.go b/internal/net/gphttp/loadbalancer/loadbalancer_test.go similarity index 95% rename from internal/net/http/loadbalancer/loadbalancer_test.go rename to internal/net/gphttp/loadbalancer/loadbalancer_test.go index 25199b5..03f2bfc 100644 --- a/internal/net/http/loadbalancer/loadbalancer_test.go +++ b/internal/net/gphttp/loadbalancer/loadbalancer_test.go @@ -3,7 +3,7 @@ package loadbalancer import ( "testing" - "github.com/yusing/go-proxy/internal/net/http/loadbalancer/types" + "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types" . "github.com/yusing/go-proxy/internal/utils/testing" ) diff --git a/internal/net/http/loadbalancer/round_robin.go b/internal/net/gphttp/loadbalancer/round_robin.go similarity index 100% rename from internal/net/http/loadbalancer/round_robin.go rename to internal/net/gphttp/loadbalancer/round_robin.go diff --git a/internal/net/http/loadbalancer/types.go b/internal/net/gphttp/loadbalancer/types.go similarity index 72% rename from internal/net/http/loadbalancer/types.go rename to internal/net/gphttp/loadbalancer/types.go index 36b45ad..2a83a8f 100644 --- a/internal/net/http/loadbalancer/types.go +++ b/internal/net/gphttp/loadbalancer/types.go @@ -1,7 +1,7 @@ package loadbalancer import ( - "github.com/yusing/go-proxy/internal/net/http/loadbalancer/types" + "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types" ) type ( diff --git a/internal/net/http/loadbalancer/types/config.go b/internal/net/gphttp/loadbalancer/types/config.go similarity index 100% rename from internal/net/http/loadbalancer/types/config.go rename to internal/net/gphttp/loadbalancer/types/config.go diff --git a/internal/net/http/loadbalancer/types/mode.go b/internal/net/gphttp/loadbalancer/types/mode.go similarity index 100% rename from internal/net/http/loadbalancer/types/mode.go rename to internal/net/gphttp/loadbalancer/types/mode.go diff --git a/internal/net/http/loadbalancer/types/server.go b/internal/net/gphttp/loadbalancer/types/server.go similarity index 100% rename from internal/net/http/loadbalancer/types/server.go rename to internal/net/gphttp/loadbalancer/types/server.go diff --git a/internal/net/http/loadbalancer/types/weight.go b/internal/net/gphttp/loadbalancer/types/weight.go similarity index 100% rename from internal/net/http/loadbalancer/types/weight.go rename to internal/net/gphttp/loadbalancer/types/weight.go diff --git a/internal/api/v1/utils/logging.go b/internal/net/gphttp/logging.go similarity index 97% rename from internal/api/v1/utils/logging.go rename to internal/net/gphttp/logging.go index 6f06e31..cfb67f0 100644 --- a/internal/api/v1/utils/logging.go +++ b/internal/net/gphttp/logging.go @@ -1,4 +1,4 @@ -package utils +package gphttp import ( "net/http" diff --git a/internal/net/http/methods.go b/internal/net/gphttp/methods.go similarity index 95% rename from internal/net/http/methods.go rename to internal/net/gphttp/methods.go index caca564..6e49202 100644 --- a/internal/net/http/methods.go +++ b/internal/net/gphttp/methods.go @@ -1,4 +1,4 @@ -package http +package gphttp import "net/http" diff --git a/internal/net/http/middleware/cidr_whitelist.go b/internal/net/gphttp/middleware/cidr_whitelist.go similarity index 97% rename from internal/net/http/middleware/cidr_whitelist.go rename to internal/net/gphttp/middleware/cidr_whitelist.go index e123c86..6b9271f 100644 --- a/internal/net/http/middleware/cidr_whitelist.go +++ b/internal/net/gphttp/middleware/cidr_whitelist.go @@ -5,7 +5,7 @@ import ( "net/http" "github.com/go-playground/validator/v10" - gphttp "github.com/yusing/go-proxy/internal/net/http" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" "github.com/yusing/go-proxy/internal/net/types" "github.com/yusing/go-proxy/internal/utils" F "github.com/yusing/go-proxy/internal/utils/functional" diff --git a/internal/net/http/middleware/cidr_whitelist_test.go b/internal/net/gphttp/middleware/cidr_whitelist_test.go similarity index 96% rename from internal/net/http/middleware/cidr_whitelist_test.go rename to internal/net/gphttp/middleware/cidr_whitelist_test.go index 64fc9e8..a8c7cee 100644 --- a/internal/net/http/middleware/cidr_whitelist_test.go +++ b/internal/net/gphttp/middleware/cidr_whitelist_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/utils" . "github.com/yusing/go-proxy/internal/utils/testing" ) @@ -61,7 +61,7 @@ func TestCIDRWhitelistValidation(t *testing.T) { } func TestCIDRWhitelist(t *testing.T) { - errs := E.NewBuilder("") + errs := gperr.NewBuilder("") mids := BuildMiddlewaresFromYAML("", testCIDRWhitelistCompose, errs) ExpectNoError(t, errs.Error()) deny = mids["deny@file"] diff --git a/internal/net/http/middleware/cloudflare_real_ip.go b/internal/net/gphttp/middleware/cloudflare_real_ip.go similarity index 100% rename from internal/net/http/middleware/cloudflare_real_ip.go rename to internal/net/gphttp/middleware/cloudflare_real_ip.go diff --git a/internal/net/http/middleware/custom_error_page.go b/internal/net/gphttp/middleware/custom_error_page.go similarity index 92% rename from internal/net/http/middleware/custom_error_page.go rename to internal/net/gphttp/middleware/custom_error_page.go index 2c50f02..76110be 100644 --- a/internal/net/http/middleware/custom_error_page.go +++ b/internal/net/gphttp/middleware/custom_error_page.go @@ -9,9 +9,9 @@ import ( "strings" "github.com/yusing/go-proxy/internal/logging" - gphttp "github.com/yusing/go-proxy/internal/net/http" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" - "github.com/yusing/go-proxy/internal/net/http/middleware/errorpage" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware/errorpage" ) type customErrorPage struct{} diff --git a/internal/net/http/middleware/errorpage/error_page.go b/internal/net/gphttp/middleware/errorpage/error_page.go similarity index 95% rename from internal/net/http/middleware/errorpage/error_page.go rename to internal/net/gphttp/middleware/errorpage/error_page.go index 2fb09e1..a1acec6 100644 --- a/internal/net/http/middleware/errorpage/error_page.go +++ b/internal/net/gphttp/middleware/errorpage/error_page.go @@ -7,7 +7,7 @@ import ( "sync" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/task" U "github.com/yusing/go-proxy/internal/utils" @@ -90,7 +90,7 @@ func watchDir() { loadContent() } case err := <-errCh: - E.LogError("error watching error page directory", err) + gperr.LogError("error watching error page directory", err) } } } diff --git a/internal/net/http/middleware/metrics_logger/metrics_logger.go b/internal/net/gphttp/middleware/metrics_logger/metrics_logger.go similarity index 100% rename from internal/net/http/middleware/metrics_logger/metrics_logger.go rename to internal/net/gphttp/middleware/metrics_logger/metrics_logger.go diff --git a/internal/net/http/middleware/metrics_logger/metrics_response_writer.go b/internal/net/gphttp/middleware/metrics_logger/metrics_response_writer.go similarity index 100% rename from internal/net/http/middleware/metrics_logger/metrics_response_writer.go rename to internal/net/gphttp/middleware/metrics_logger/metrics_response_writer.go diff --git a/internal/net/http/middleware/middleware.go b/internal/net/gphttp/middleware/middleware.go similarity index 91% rename from internal/net/http/middleware/middleware.go rename to internal/net/gphttp/middleware/middleware.go index b206d26..9a36fe5 100644 --- a/internal/net/http/middleware/middleware.go +++ b/internal/net/gphttp/middleware/middleware.go @@ -7,15 +7,15 @@ import ( "sort" "strings" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" - gphttp "github.com/yusing/go-proxy/internal/net/http" - "github.com/yusing/go-proxy/internal/net/http/reverseproxy" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy" "github.com/yusing/go-proxy/internal/utils" ) type ( - Error = E.Error + Error = gperr.Error ReverseProxy = reverseproxy.ReverseProxy ProxyRequest = reverseproxy.ProxyRequest @@ -103,7 +103,7 @@ func (m *Middleware) setup() { } } -func (m *Middleware) apply(optsRaw OptionsRaw) E.Error { +func (m *Middleware) apply(optsRaw OptionsRaw) gperr.Error { if len(optsRaw) == 0 { return nil } @@ -132,10 +132,10 @@ func (m *Middleware) finalize() error { return nil } -func (m *Middleware) New(optsRaw OptionsRaw) (*Middleware, E.Error) { +func (m *Middleware) New(optsRaw OptionsRaw) (*Middleware, gperr.Error) { if m.construct == nil { // likely a middleware from compose if len(optsRaw) != 0 { - return nil, E.New("additional options not allowed for middleware ").Subject(m.name) + return nil, gperr.New("additional options not allowed for middleware ").Subject(m.name) } return m, nil } @@ -145,7 +145,7 @@ func (m *Middleware) New(optsRaw OptionsRaw) (*Middleware, E.Error) { return nil, err } if err := mid.finalize(); err != nil { - return nil, E.From(err) + return nil, gperr.Wrap(err) } return mid, nil } @@ -196,7 +196,7 @@ func (m *Middleware) ServeHTTP(next http.HandlerFunc, w http.ResponseWriter, r * next(w, r) } -func PatchReverseProxy(rp *ReverseProxy, middlewaresMap map[string]OptionsRaw) (err E.Error) { +func PatchReverseProxy(rp *ReverseProxy, middlewaresMap map[string]OptionsRaw) (err gperr.Error) { var middlewares []*Middleware middlewares, err = compileMiddlewares(middlewaresMap) if err != nil { diff --git a/internal/net/http/middleware/middleware_builder.go b/internal/net/gphttp/middleware/middleware_builder.go similarity index 79% rename from internal/net/http/middleware/middleware_builder.go rename to internal/net/gphttp/middleware/middleware_builder.go index 8ea5403..c7be596 100644 --- a/internal/net/http/middleware/middleware_builder.go +++ b/internal/net/gphttp/middleware/middleware_builder.go @@ -6,13 +6,13 @@ import ( "path" "sort" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "gopkg.in/yaml.v3" ) -var ErrMissingMiddlewareUse = E.New("missing middleware 'use' field") +var ErrMissingMiddlewareUse = gperr.New("missing middleware 'use' field") -func BuildMiddlewaresFromComposeFile(filePath string, eb *E.Builder) map[string]*Middleware { +func BuildMiddlewaresFromComposeFile(filePath string, eb *gperr.Builder) map[string]*Middleware { fileContent, err := os.ReadFile(filePath) if err != nil { eb.Add(err) @@ -21,7 +21,7 @@ func BuildMiddlewaresFromComposeFile(filePath string, eb *E.Builder) map[string] return BuildMiddlewaresFromYAML(path.Base(filePath), fileContent, eb) } -func BuildMiddlewaresFromYAML(source string, data []byte, eb *E.Builder) map[string]*Middleware { +func BuildMiddlewaresFromYAML(source string, data []byte, eb *gperr.Builder) map[string]*Middleware { var rawMap map[string][]map[string]any err := yaml.Unmarshal(data, &rawMap) if err != nil { @@ -40,11 +40,11 @@ func BuildMiddlewaresFromYAML(source string, data []byte, eb *E.Builder) map[str return middlewares } -func compileMiddlewares(middlewaresMap map[string]OptionsRaw) ([]*Middleware, E.Error) { +func compileMiddlewares(middlewaresMap map[string]OptionsRaw) ([]*Middleware, gperr.Error) { middlewares := make([]*Middleware, 0, len(middlewaresMap)) - errs := E.NewBuilder("middlewares compile error") - invalidOpts := E.NewBuilder("options compile error") + errs := gperr.NewBuilder("middlewares compile error") + invalidOpts := gperr.NewBuilder("options compile error") for name, opts := range middlewaresMap { m, err := Get(name) @@ -68,7 +68,7 @@ func compileMiddlewares(middlewaresMap map[string]OptionsRaw) ([]*Middleware, E. return middlewares, errs.Error() } -func BuildMiddlewareFromMap(name string, middlewaresMap map[string]OptionsRaw) (*Middleware, E.Error) { +func BuildMiddlewareFromMap(name string, middlewaresMap map[string]OptionsRaw) (*Middleware, gperr.Error) { compiled, err := compileMiddlewares(middlewaresMap) if err != nil { return nil, err @@ -77,8 +77,8 @@ func BuildMiddlewareFromMap(name string, middlewaresMap map[string]OptionsRaw) ( } // TODO: check conflict or duplicates. -func BuildMiddlewareFromChainRaw(name string, defs []map[string]any) (*Middleware, E.Error) { - chainErr := E.NewBuilder("") +func BuildMiddlewareFromChainRaw(name string, defs []map[string]any) (*Middleware, gperr.Error) { + chainErr := gperr.NewBuilder("") chain := make([]*Middleware, 0, len(defs)) for i, def := range defs { if def["use"] == nil || def["use"] == "" { diff --git a/internal/net/http/middleware/middleware_builder_test.go b/internal/net/gphttp/middleware/middleware_builder_test.go similarity index 85% rename from internal/net/http/middleware/middleware_builder_test.go rename to internal/net/gphttp/middleware/middleware_builder_test.go index 2c9828c..08e8402 100644 --- a/internal/net/http/middleware/middleware_builder_test.go +++ b/internal/net/gphttp/middleware/middleware_builder_test.go @@ -5,7 +5,7 @@ import ( "encoding/json" "testing" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" . "github.com/yusing/go-proxy/internal/utils/testing" ) @@ -13,7 +13,7 @@ import ( var testMiddlewareCompose []byte func TestBuild(t *testing.T) { - errs := E.NewBuilder("") + errs := gperr.NewBuilder("") middlewares := BuildMiddlewaresFromYAML("", testMiddlewareCompose, errs) ExpectNoError(t, errs.Error()) Must(json.MarshalIndent(middlewares, "", " ")) diff --git a/internal/net/http/middleware/middleware_chain.go b/internal/net/gphttp/middleware/middleware_chain.go similarity index 90% rename from internal/net/http/middleware/middleware_chain.go rename to internal/net/gphttp/middleware/middleware_chain.go index 932d278..cf1258b 100644 --- a/internal/net/http/middleware/middleware_chain.go +++ b/internal/net/gphttp/middleware/middleware_chain.go @@ -4,7 +4,7 @@ import ( "net/http" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) type middlewareChain struct { @@ -51,10 +51,10 @@ func (m *middlewareChain) modifyResponse(resp *http.Response) error { if len(m.modResps) == 0 { return nil } - errs := E.NewBuilder("modify response errors") + errs := gperr.NewBuilder("modify response errors") for i, mr := range m.modResps { if err := mr.modifyResponse(resp); err != nil { - errs.Add(E.From(err).Subjectf("%d", i)) + errs.Add(gperr.Wrap(err).Subjectf("%d", i)) } } return errs.Error() diff --git a/internal/net/http/middleware/middleware_test.go b/internal/net/gphttp/middleware/middleware_test.go similarity index 100% rename from internal/net/http/middleware/middleware_test.go rename to internal/net/gphttp/middleware/middleware_test.go diff --git a/internal/net/http/middleware/middlewares.go b/internal/net/gphttp/middleware/middlewares.go similarity index 86% rename from internal/net/http/middleware/middlewares.go rename to internal/net/gphttp/middleware/middlewares.go index a5050be..184de94 100644 --- a/internal/net/http/middleware/middlewares.go +++ b/internal/net/gphttp/middleware/middlewares.go @@ -4,7 +4,7 @@ import ( "path" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/utils" "github.com/yusing/go-proxy/internal/utils/strutils" @@ -35,8 +35,8 @@ var allMiddlewares = map[string]*Middleware{ } var ( - ErrUnknownMiddleware = E.New("unknown middleware") - ErrDuplicatedMiddleware = E.New("duplicated middleware") + ErrUnknownMiddleware = gperr.New("unknown middleware") + ErrDuplicatedMiddleware = gperr.New("duplicated middleware") ) func Get(name string) (*Middleware, Error) { @@ -54,14 +54,14 @@ func All() map[string]*Middleware { } func LoadComposeFiles() { - errs := E.NewBuilder("middleware compile errors") + errs := gperr.NewBuilder("middleware compile errors") middlewareDefs, err := utils.ListFiles(common.MiddlewareComposeBasePath, 0) if err != nil { logging.Err(err).Msg("failed to list middleware definitions") return } for _, defFile := range middlewareDefs { - voidErrs := E.NewBuilder("") // ignore these errors, will be added in next step + voidErrs := gperr.NewBuilder("") // ignore these errors, will be added in next step mws := BuildMiddlewaresFromComposeFile(defFile, voidErrs) if len(mws) == 0 { continue @@ -99,6 +99,6 @@ func LoadComposeFiles() { } } if errs.HasError() { - E.LogError(errs.About(), errs.Error()) + gperr.LogError(errs.About(), errs.Error()) } } diff --git a/internal/net/http/middleware/modify_request.go b/internal/net/gphttp/middleware/modify_request.go similarity index 100% rename from internal/net/http/middleware/modify_request.go rename to internal/net/gphttp/middleware/modify_request.go diff --git a/internal/net/http/middleware/modify_request_test.go b/internal/net/gphttp/middleware/modify_request_test.go similarity index 100% rename from internal/net/http/middleware/modify_request_test.go rename to internal/net/gphttp/middleware/modify_request_test.go diff --git a/internal/net/http/middleware/modify_response.go b/internal/net/gphttp/middleware/modify_response.go similarity index 100% rename from internal/net/http/middleware/modify_response.go rename to internal/net/gphttp/middleware/modify_response.go diff --git a/internal/net/http/middleware/modify_response_test.go b/internal/net/gphttp/middleware/modify_response_test.go similarity index 100% rename from internal/net/http/middleware/modify_response_test.go rename to internal/net/gphttp/middleware/modify_response_test.go diff --git a/internal/net/http/middleware/oidc.go b/internal/net/gphttp/middleware/oidc.go similarity index 94% rename from internal/net/http/middleware/oidc.go rename to internal/net/gphttp/middleware/oidc.go index 3af1ca3..128f4a0 100644 --- a/internal/net/http/middleware/oidc.go +++ b/internal/net/gphttp/middleware/oidc.go @@ -6,7 +6,7 @@ import ( "sync/atomic" "github.com/yusing/go-proxy/internal/api/v1/auth" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) type oidcMiddleware struct { @@ -24,7 +24,7 @@ var OIDC = NewMiddleware[oidcMiddleware]() func (amw *oidcMiddleware) finalize() error { if !auth.IsOIDCEnabled() { - return E.New("OIDC not enabled but OIDC middleware is used") + return gperr.New("OIDC not enabled but OIDC middleware is used") } return nil } diff --git a/internal/net/http/middleware/rate_limit.go b/internal/net/gphttp/middleware/rate_limit.go similarity index 100% rename from internal/net/http/middleware/rate_limit.go rename to internal/net/gphttp/middleware/rate_limit.go diff --git a/internal/net/http/middleware/rate_limit_test.go b/internal/net/gphttp/middleware/rate_limit_test.go similarity index 100% rename from internal/net/http/middleware/rate_limit_test.go rename to internal/net/gphttp/middleware/rate_limit_test.go diff --git a/internal/net/http/middleware/real_ip.go b/internal/net/gphttp/middleware/real_ip.go similarity index 97% rename from internal/net/http/middleware/real_ip.go rename to internal/net/gphttp/middleware/real_ip.go index f1925fb..ed11d12 100644 --- a/internal/net/http/middleware/real_ip.go +++ b/internal/net/gphttp/middleware/real_ip.go @@ -4,7 +4,7 @@ import ( "net" "net/http" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" "github.com/yusing/go-proxy/internal/net/types" ) diff --git a/internal/net/http/middleware/real_ip_test.go b/internal/net/gphttp/middleware/real_ip_test.go similarity index 96% rename from internal/net/http/middleware/real_ip_test.go rename to internal/net/gphttp/middleware/real_ip_test.go index 5b4d809..372862d 100644 --- a/internal/net/http/middleware/real_ip_test.go +++ b/internal/net/gphttp/middleware/real_ip_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" "github.com/yusing/go-proxy/internal/net/types" . "github.com/yusing/go-proxy/internal/utils/testing" ) diff --git a/internal/net/http/middleware/redirect_http.go b/internal/net/gphttp/middleware/redirect_http.go similarity index 100% rename from internal/net/http/middleware/redirect_http.go rename to internal/net/gphttp/middleware/redirect_http.go diff --git a/internal/net/http/middleware/redirect_http_test.go b/internal/net/gphttp/middleware/redirect_http_test.go similarity index 100% rename from internal/net/http/middleware/redirect_http_test.go rename to internal/net/gphttp/middleware/redirect_http_test.go diff --git a/internal/net/http/middleware/set_upstream_headers.go b/internal/net/gphttp/middleware/set_upstream_headers.go similarity index 86% rename from internal/net/http/middleware/set_upstream_headers.go rename to internal/net/gphttp/middleware/set_upstream_headers.go index 488b1c5..434c4cd 100644 --- a/internal/net/http/middleware/set_upstream_headers.go +++ b/internal/net/gphttp/middleware/set_upstream_headers.go @@ -3,8 +3,8 @@ package middleware import ( "net/http" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" - "github.com/yusing/go-proxy/internal/net/http/reverseproxy" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy" ) // internal use only. diff --git a/internal/net/http/middleware/test_data/cidr_whitelist_test.yml b/internal/net/gphttp/middleware/test_data/cidr_whitelist_test.yml similarity index 100% rename from internal/net/http/middleware/test_data/cidr_whitelist_test.yml rename to internal/net/gphttp/middleware/test_data/cidr_whitelist_test.yml diff --git a/internal/net/http/middleware/test_data/middleware_compose.yml b/internal/net/gphttp/middleware/test_data/middleware_compose.yml similarity index 100% rename from internal/net/http/middleware/test_data/middleware_compose.yml rename to internal/net/gphttp/middleware/test_data/middleware_compose.yml diff --git a/internal/net/http/middleware/test_data/sample_headers.json b/internal/net/gphttp/middleware/test_data/sample_headers.json similarity index 100% rename from internal/net/http/middleware/test_data/sample_headers.json rename to internal/net/gphttp/middleware/test_data/sample_headers.json diff --git a/internal/net/http/middleware/test_utils.go b/internal/net/gphttp/middleware/test_utils.go similarity index 94% rename from internal/net/http/middleware/test_utils.go rename to internal/net/gphttp/middleware/test_utils.go index 0adb1a5..2bd208b 100644 --- a/internal/net/http/middleware/test_utils.go +++ b/internal/net/gphttp/middleware/test_utils.go @@ -9,8 +9,8 @@ import ( "net/http/httptest" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" - "github.com/yusing/go-proxy/internal/net/http/reverseproxy" + "github.com/yusing/go-proxy/internal/gperr" + "github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy" "github.com/yusing/go-proxy/internal/net/types" . "github.com/yusing/go-proxy/internal/utils/testing" ) @@ -122,7 +122,7 @@ func (args *testArgs) bodyReader() io.Reader { return nil } -func newMiddlewareTest(middleware *Middleware, args *testArgs) (*TestResult, E.Error) { +func newMiddlewareTest(middleware *Middleware, args *testArgs) (*TestResult, gperr.Error) { if args == nil { args = new(testArgs) } @@ -136,7 +136,7 @@ func newMiddlewareTest(middleware *Middleware, args *testArgs) (*TestResult, E.E return newMiddlewaresTest([]*Middleware{mid}, args) } -func newMiddlewaresTest(middlewares []*Middleware, args *testArgs) (*TestResult, E.Error) { +func newMiddlewaresTest(middlewares []*Middleware, args *testArgs) (*TestResult, gperr.Error) { if args == nil { args = new(testArgs) } @@ -163,7 +163,7 @@ func newMiddlewaresTest(middlewares []*Middleware, args *testArgs) (*TestResult, data, err := io.ReadAll(resp.Body) if err != nil { - return nil, E.From(err) + return nil, gperr.Wrap(err) } return &TestResult{ diff --git a/internal/net/http/middleware/trace.go b/internal/net/gphttp/middleware/trace.go similarity index 96% rename from internal/net/http/middleware/trace.go rename to internal/net/gphttp/middleware/trace.go index a4ebcc7..4c9550a 100644 --- a/internal/net/http/middleware/trace.go +++ b/internal/net/gphttp/middleware/trace.go @@ -4,7 +4,7 @@ import ( "net/http" "sync" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" ) type ( diff --git a/internal/net/http/middleware/tracer.go b/internal/net/gphttp/middleware/tracer.go similarity index 100% rename from internal/net/http/middleware/tracer.go rename to internal/net/gphttp/middleware/tracer.go diff --git a/internal/net/http/middleware/vars.go b/internal/net/gphttp/middleware/vars.go similarity index 98% rename from internal/net/http/middleware/vars.go rename to internal/net/gphttp/middleware/vars.go index 20e716c..472ca72 100644 --- a/internal/net/http/middleware/vars.go +++ b/internal/net/gphttp/middleware/vars.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" ) type ( diff --git a/internal/net/http/middleware/x_forwarded.go b/internal/net/gphttp/middleware/x_forwarded.go similarity index 93% rename from internal/net/http/middleware/x_forwarded.go rename to internal/net/gphttp/middleware/x_forwarded.go index 7958a3d..a2de34b 100644 --- a/internal/net/http/middleware/x_forwarded.go +++ b/internal/net/gphttp/middleware/x_forwarded.go @@ -5,7 +5,7 @@ import ( "net/http" "strings" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" ) type ( diff --git a/internal/net/http/modify_response_writer.go b/internal/net/gphttp/modify_response_writer.go similarity index 99% rename from internal/net/http/modify_response_writer.go rename to internal/net/gphttp/modify_response_writer.go index a8c7b89..41f846d 100644 --- a/internal/net/http/modify_response_writer.go +++ b/internal/net/gphttp/modify_response_writer.go @@ -1,7 +1,7 @@ // Modified from Traefik Labs's MIT-licensed code (https://github.com/traefik/traefik/blob/master/pkg/middlewares/response_modifier.go) // Copyright (c) 2020-2024 Traefik Labs -package http +package gphttp import ( "bufio" diff --git a/internal/net/http/reverseproxy/reverse_proxy_mod.go b/internal/net/gphttp/reverseproxy/reverse_proxy_mod.go similarity index 99% rename from internal/net/http/reverseproxy/reverse_proxy_mod.go rename to internal/net/gphttp/reverseproxy/reverse_proxy_mod.go index f3f0b7b..221aa74 100644 --- a/internal/net/http/reverseproxy/reverse_proxy_mod.go +++ b/internal/net/gphttp/reverseproxy/reverse_proxy_mod.go @@ -26,8 +26,8 @@ import ( "github.com/rs/zerolog" "github.com/yusing/go-proxy/internal/logging" - "github.com/yusing/go-proxy/internal/net/http/accesslog" - "github.com/yusing/go-proxy/internal/net/http/httpheaders" + "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" + "github.com/yusing/go-proxy/internal/net/gphttp/httpheaders" "github.com/yusing/go-proxy/internal/net/types" U "github.com/yusing/go-proxy/internal/utils" "golang.org/x/net/http/httpguts" diff --git a/internal/net/http/serve_mux.go b/internal/net/gphttp/serve_mux.go similarity index 97% rename from internal/net/http/serve_mux.go rename to internal/net/gphttp/serve_mux.go index 0e487b6..902c0e2 100644 --- a/internal/net/http/serve_mux.go +++ b/internal/net/gphttp/serve_mux.go @@ -1,4 +1,4 @@ -package http +package gphttp import "net/http" diff --git a/internal/net/http/server/error.go b/internal/net/gphttp/server/error.go similarity index 100% rename from internal/net/http/server/error.go rename to internal/net/gphttp/server/error.go diff --git a/internal/net/http/server/server.go b/internal/net/gphttp/server/server.go similarity index 100% rename from internal/net/http/server/server.go rename to internal/net/gphttp/server/server.go diff --git a/internal/net/http/status_code.go b/internal/net/gphttp/status_code.go similarity index 93% rename from internal/net/http/status_code.go rename to internal/net/gphttp/status_code.go index 8235805..25977df 100644 --- a/internal/net/http/status_code.go +++ b/internal/net/gphttp/status_code.go @@ -1,4 +1,4 @@ -package http +package gphttp import "net/http" diff --git a/internal/net/http/transport.go b/internal/net/gphttp/transport.go similarity index 98% rename from internal/net/http/transport.go rename to internal/net/gphttp/transport.go index 84e294f..d633ee6 100644 --- a/internal/net/http/transport.go +++ b/internal/net/gphttp/transport.go @@ -1,4 +1,4 @@ -package http +package gphttp import ( "crypto/tls" diff --git a/internal/notif/base.go b/internal/notif/base.go index 5af0df1..a1db3af 100644 --- a/internal/notif/base.go +++ b/internal/notif/base.go @@ -6,7 +6,7 @@ import ( "net/url" "strings" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) type ProviderBase struct { @@ -16,12 +16,12 @@ type ProviderBase struct { } var ( - ErrMissingToken = E.New("token is required") - ErrURLMissingScheme = E.New("url missing scheme, expect 'http://' or 'https://'") + ErrMissingToken = gperr.New("token is required") + ErrURLMissingScheme = gperr.New("url missing scheme, expect 'http://' or 'https://'") ) // Validate implements the utils.CustomValidator interface. -func (base *ProviderBase) Validate() E.Error { +func (base *ProviderBase) Validate() gperr.Error { if base.Token == "" { return ErrMissingToken } @@ -30,7 +30,7 @@ func (base *ProviderBase) Validate() E.Error { } u, err := url.Parse(base.URL) if err != nil { - return E.Wrap(err) + return gperr.Wrap(err) } base.URL = u.String() return nil @@ -63,7 +63,7 @@ func (base *ProviderBase) SetHeaders(logMsg *LogMessage, headers http.Header) { func (base *ProviderBase) makeRespError(resp *http.Response) error { body, err := io.ReadAll(resp.Body) if err == nil { - return E.Errorf("%s status %d: %s", base.Name, resp.StatusCode, body) + return gperr.Errorf("%s status %d: %s", base.Name, resp.StatusCode, body) } - return E.Errorf("%s status %d", base.Name, resp.StatusCode) + return gperr.Errorf("%s status %d", base.Name, resp.StatusCode) } diff --git a/internal/notif/config.go b/internal/notif/config.go index c9c29cd..1f35cdb 100644 --- a/internal/notif/config.go +++ b/internal/notif/config.go @@ -1,7 +1,7 @@ package notif import ( - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/utils" ) @@ -11,13 +11,13 @@ type NotificationConfig struct { } var ( - ErrMissingNotifProvider = E.New("missing notification provider") - ErrInvalidNotifProviderType = E.New("invalid notification provider type") - ErrUnknownNotifProvider = E.New("unknown notification provider") + ErrMissingNotifProvider = gperr.New("missing notification provider") + ErrInvalidNotifProviderType = gperr.New("invalid notification provider type") + ErrUnknownNotifProvider = gperr.New("unknown notification provider") ) // UnmarshalMap implements MapUnmarshaler. -func (cfg *NotificationConfig) UnmarshalMap(m map[string]any) (err E.Error) { +func (cfg *NotificationConfig) UnmarshalMap(m map[string]any) (err gperr.Error) { // extract provider name providerName := m["provider"] switch providerName := providerName.(type) { diff --git a/internal/notif/dispatcher.go b/internal/notif/dispatcher.go index c8431b2..7b9788e 100644 --- a/internal/notif/dispatcher.go +++ b/internal/notif/dispatcher.go @@ -2,7 +2,7 @@ package notif import ( "github.com/rs/zerolog" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/task" F "github.com/yusing/go-proxy/internal/utils/functional" @@ -89,14 +89,14 @@ func (disp *Dispatcher) dispatch(msg *LogMessage) { task := disp.task.Subtask("dispatcher") defer task.Finish("notif dispatched") - errs := E.NewBuilder(dispatchErr) + errs := gperr.NewBuilder(dispatchErr) disp.providers.RangeAllParallel(func(p Provider) { if err := notifyProvider(task.Context(), p, msg); err != nil { - errs.Add(E.PrependSubject(p.GetName(), err)) + errs.Add(gperr.PrependSubject(p.GetName(), err)) } }) if errs.HasError() { - E.LogError(errs.About(), errs.Error()) + gperr.LogError(errs.About(), errs.Error()) } else { logging.Debug().Str("title", msg.Title).Msgf("dispatched notif") } diff --git a/internal/notif/ntfy.go b/internal/notif/ntfy.go index 42b97f7..6e10725 100644 --- a/internal/notif/ntfy.go +++ b/internal/notif/ntfy.go @@ -7,7 +7,7 @@ import ( "strings" "github.com/rs/zerolog" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) // See https://docs.ntfy.sh/publish @@ -24,22 +24,22 @@ const ( NtfyStylePlain NtfyStyle = "plain" ) -func (n *Ntfy) Validate() E.Error { +func (n *Ntfy) Validate() gperr.Error { if n.URL == "" { - return E.New("url is required") + return gperr.New("url is required") } if n.Topic == "" { - return E.New("topic is required") + return gperr.New("topic is required") } if n.Topic[0] == '/' { - return E.New("topic should not start with a slash") + return gperr.New("topic should not start with a slash") } switch n.Style { case "": n.Style = NtfyStyleMarkdown case NtfyStyleMarkdown, NtfyStylePlain: default: - return E.Errorf("invalid style, expecting %q or %q, got %q", NtfyStyleMarkdown, NtfyStylePlain, n.Style) + return gperr.Errorf("invalid style, expecting %q or %q, got %q", NtfyStyleMarkdown, NtfyStylePlain, n.Style) } return nil } diff --git a/internal/notif/providers.go b/internal/notif/providers.go index 0de2a2c..953fb3b 100644 --- a/internal/notif/providers.go +++ b/internal/notif/providers.go @@ -6,8 +6,8 @@ import ( "net/http" "time" - E "github.com/yusing/go-proxy/internal/error" - gphttp "github.com/yusing/go-proxy/internal/net/http" + "github.com/yusing/go-proxy/internal/gperr" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" "github.com/yusing/go-proxy/internal/utils" ) @@ -26,7 +26,7 @@ type ( makeRespError(resp *http.Response) error } - ProviderCreateFunc func(map[string]any) (Provider, E.Error) + ProviderCreateFunc func(map[string]any) (Provider, gperr.Error) ProviderConfig map[string]any ) @@ -39,7 +39,7 @@ const ( func notifyProvider(ctx context.Context, provider Provider, msg *LogMessage) error { body, err := provider.MakeBody(msg) if err != nil { - return E.PrependSubject(provider.GetName(), err) + return gperr.PrependSubject(provider.GetName(), err) } ctx, cancel := context.WithTimeout(ctx, 2*time.Second) @@ -52,7 +52,7 @@ func notifyProvider(ctx context.Context, provider Provider, msg *LogMessage) err body, ) if err != nil { - return E.PrependSubject(provider.GetName(), err) + return gperr.PrependSubject(provider.GetName(), err) } req.Header.Set("Content-Type", provider.GetMIMEType()) @@ -63,7 +63,7 @@ func notifyProvider(ctx context.Context, provider Provider, msg *LogMessage) err resp, err := http.DefaultClient.Do(req) if err != nil { - return E.PrependSubject(provider.GetName(), err) + return gperr.PrependSubject(provider.GetName(), err) } defer resp.Body.Close() diff --git a/internal/notif/webhook.go b/internal/notif/webhook.go index 806b5f9..13fd23c 100644 --- a/internal/notif/webhook.go +++ b/internal/notif/webhook.go @@ -8,7 +8,7 @@ import ( "net/http" "strings" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) type Webhook struct { @@ -27,7 +27,7 @@ var webhookTemplates = map[string]string{ "discord": discordPayload, } -func (webhook *Webhook) Validate() E.Error { +func (webhook *Webhook) Validate() gperr.Error { if err := webhook.ProviderBase.Validate(); err != nil && !err.Is(ErrMissingToken) { return err } @@ -37,16 +37,16 @@ func (webhook *Webhook) Validate() E.Error { webhook.MIMEType = "application/json" case "application/json", "application/x-www-form-urlencoded", "text/plain": default: - return E.New("invalid mime_type, expect empty, 'application/json', 'application/x-www-form-urlencoded' or 'text/plain'") + return gperr.New("invalid mime_type, expect empty, 'application/json', 'application/x-www-form-urlencoded' or 'text/plain'") } switch webhook.Template { case "": if webhook.MIMEType == "application/json" && !json.Valid([]byte(webhook.Payload)) { - return E.New("invalid payload, expect valid JSON") + return gperr.New("invalid payload, expect valid JSON") } if webhook.Payload == "" { - return E.New("invalid payload, expect non-empty") + return gperr.New("invalid payload, expect non-empty") } case "discord": webhook.ColorMode = "dec" @@ -56,7 +56,7 @@ func (webhook *Webhook) Validate() E.Error { webhook.Payload = discordPayload } default: - return E.New("invalid template, expect empty or 'discord'") + return gperr.New("invalid template, expect empty or 'discord'") } switch webhook.Method { @@ -64,7 +64,7 @@ func (webhook *Webhook) Validate() E.Error { webhook.Method = http.MethodPost case http.MethodGet, http.MethodPost, http.MethodPut: default: - return E.New("invalid method, expect empty, 'GET', 'POST' or 'PUT'") + return gperr.New("invalid method, expect empty, 'GET', 'POST' or 'PUT'") } switch webhook.ColorMode { @@ -72,7 +72,7 @@ func (webhook *Webhook) Validate() E.Error { webhook.ColorMode = "hex" case "hex", "dec": default: - return E.New("invalid color_mode, expect empty, 'hex' or 'dec'") + return gperr.New("invalid color_mode, expect empty, 'hex' or 'dec'") } return nil diff --git a/internal/route/fileserver.go b/internal/route/fileserver.go index e407d9b..ed75e9b 100644 --- a/internal/route/fileserver.go +++ b/internal/route/fileserver.go @@ -6,16 +6,15 @@ import ( "path/filepath" "github.com/yusing/go-proxy/internal/common" - gphttp "github.com/yusing/go-proxy/internal/net/http" - "github.com/yusing/go-proxy/internal/net/http/accesslog" - "github.com/yusing/go-proxy/internal/net/http/middleware" - metricslogger "github.com/yusing/go-proxy/internal/net/http/middleware/metrics_logger" + "github.com/yusing/go-proxy/internal/gperr" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware" + metricslogger "github.com/yusing/go-proxy/internal/net/gphttp/middleware/metrics_logger" "github.com/yusing/go-proxy/internal/route/routes" "github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/watcher/health" "github.com/yusing/go-proxy/internal/watcher/health/monitor" - - E "github.com/yusing/go-proxy/internal/error" ) type ( @@ -35,12 +34,12 @@ func handler(root string) http.Handler { return http.FileServer(http.Dir(root)) } -func NewFileServer(base *Route) (*FileServer, E.Error) { +func NewFileServer(base *Route) (*FileServer, gperr.Error) { s := &FileServer{Route: base} s.Root = filepath.Clean(s.Root) if !path.IsAbs(s.Root) { - return nil, E.New("`root` must be an absolute path") + return nil, gperr.New("`root` must be an absolute path") } s.handler = handler(s.Root) @@ -57,7 +56,7 @@ func NewFileServer(base *Route) (*FileServer, E.Error) { } // Start implements task.TaskStarter. -func (s *FileServer) Start(parent task.Parent) E.Error { +func (s *FileServer) Start(parent task.Parent) gperr.Error { s.task = parent.Subtask("fileserver."+s.TargetName(), false) pathPatterns := s.PathPatterns @@ -66,7 +65,7 @@ func (s *FileServer) Start(parent task.Parent) E.Error { case len(pathPatterns) == 1 && pathPatterns[0] == "/": default: mux := gphttp.NewServeMux() - patErrs := E.NewBuilder("invalid path pattern(s)") + patErrs := gperr.NewBuilder("invalid path pattern(s)") for _, p := range pathPatterns { patErrs.Add(mux.Handle(p, s.handler)) } @@ -88,7 +87,7 @@ func (s *FileServer) Start(parent task.Parent) E.Error { s.accessLogger, err = accesslog.NewFileAccessLogger(s.task, s.AccessLog) if err != nil { s.task.Finish(err) - return E.Wrap(err) + return gperr.Wrap(err) } } diff --git a/internal/route/provider/agent.go b/internal/route/provider/agent.go index 85acec9..c4dd88d 100644 --- a/internal/route/provider/agent.go +++ b/internal/route/provider/agent.go @@ -3,7 +3,7 @@ package provider import ( "github.com/rs/zerolog" "github.com/yusing/go-proxy/agent/pkg/agent" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/route" "github.com/yusing/go-proxy/internal/watcher" ) @@ -25,7 +25,7 @@ func (p *AgentProvider) IsExplicitOnly() bool { return p.docker.IsExplicitOnly() } -func (p *AgentProvider) loadRoutesImpl() (route.Routes, E.Error) { +func (p *AgentProvider) loadRoutesImpl() (route.Routes, gperr.Error) { return p.docker.loadRoutesImpl() } diff --git a/internal/route/provider/docker.go b/internal/route/provider/docker.go index 2bbc4b7..e08cfc8 100755 --- a/internal/route/provider/docker.go +++ b/internal/route/provider/docker.go @@ -8,7 +8,7 @@ import ( "github.com/rs/zerolog" "github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/docker" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/route" U "github.com/yusing/go-proxy/internal/utils" @@ -27,7 +27,7 @@ const ( aliasRefPrefixAlt = '$' ) -var ErrAliasRefIndexOutOfRange = E.New("index out of range") +var ErrAliasRefIndexOutOfRange = gperr.New("index out of range") func DockerProviderImpl(name, dockerHost string) ProviderImpl { if dockerHost == common.DockerHostFromEnv { @@ -60,13 +60,13 @@ func (p *DockerProvider) NewWatcher() watcher.Watcher { return watcher.NewDockerWatcher(p.dockerHost) } -func (p *DockerProvider) loadRoutesImpl() (route.Routes, E.Error) { +func (p *DockerProvider) loadRoutesImpl() (route.Routes, gperr.Error) { containers, err := docker.ListContainers(p.dockerHost) if err != nil { - return nil, E.From(err) + return nil, gperr.Wrap(err) } - errs := E.NewBuilder("") + errs := gperr.NewBuilder("") routes := make(route.Routes) for _, c := range containers { @@ -93,7 +93,7 @@ func (p *DockerProvider) loadRoutesImpl() (route.Routes, E.Error) { // Returns a list of proxy entries for a container. // Always non-nil. -func (p *DockerProvider) routesFromContainerLabels(container *docker.Container) (route.Routes, E.Error) { +func (p *DockerProvider) routesFromContainerLabels(container *docker.Container) (route.Routes, gperr.Error) { if !container.IsExplicit && p.IsExplicitOnly() { return nil, nil } @@ -109,7 +109,7 @@ func (p *DockerProvider) routesFromContainerLabels(container *docker.Container) } } - errs := E.NewBuilder("label errors") + errs := gperr.NewBuilder("label errors") m, err := docker.ParseLabels(container.Labels) errs.Add(err) @@ -118,7 +118,7 @@ func (p *DockerProvider) routesFromContainerLabels(container *docker.Container) for alias, entryMapAny := range m { if len(alias) == 0 { - errs.Add(E.New("empty alias")) + errs.Add(gperr.New("empty alias")) continue } @@ -132,7 +132,7 @@ func (p *DockerProvider) routesFromContainerLabels(container *docker.Container) panic(fmt.Errorf("invalid entry map type %T", entryMapAny)) } if err := yaml.Unmarshal([]byte(yamlStr), &entryMap); err != nil { - errs.Add(E.From(err).Subject(alias)) + errs.Add(gperr.Wrap(err).Subject(alias)) continue } } diff --git a/internal/route/provider/event_handler.go b/internal/route/provider/event_handler.go index 3dccc0f..5035d58 100644 --- a/internal/route/provider/event_handler.go +++ b/internal/route/provider/event_handler.go @@ -1,7 +1,7 @@ package provider import ( - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/route" "github.com/yusing/go-proxy/internal/route/provider/types" "github.com/yusing/go-proxy/internal/task" @@ -11,19 +11,19 @@ import ( type EventHandler struct { provider *Provider - errs *E.Builder - added *E.Builder - removed *E.Builder - updated *E.Builder + errs *gperr.Builder + added *gperr.Builder + removed *gperr.Builder + updated *gperr.Builder } func (p *Provider) newEventHandler() *EventHandler { return &EventHandler{ provider: p, - errs: E.NewBuilder("event errors"), - added: E.NewBuilder("added"), - removed: E.NewBuilder("removed"), - updated: E.NewBuilder("updated"), + errs: gperr.NewBuilder("event errors"), + added: gperr.NewBuilder("added"), + removed: gperr.NewBuilder("removed"), + updated: gperr.NewBuilder("updated"), } } @@ -100,7 +100,7 @@ func (handler *EventHandler) Update(parent task.Parent, oldRoute *route.Route, n } func (handler *EventHandler) Log() { - results := E.NewBuilder("event occurred") + results := gperr.NewBuilder("event occurred") results.AddFrom(handler.added, false) results.AddFrom(handler.removed, false) results.AddFrom(handler.updated, false) diff --git a/internal/route/provider/file.go b/internal/route/provider/file.go index 8d2e208..79855b9 100644 --- a/internal/route/provider/file.go +++ b/internal/route/provider/file.go @@ -7,7 +7,7 @@ import ( "github.com/rs/zerolog" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/route" "github.com/yusing/go-proxy/internal/utils" @@ -33,12 +33,12 @@ func FileProviderImpl(filename string) (ProviderImpl, error) { return impl, nil } -func validate(data []byte) (routes route.Routes, err E.Error) { +func validate(data []byte) (routes route.Routes, err gperr.Error) { err = utils.DeserializeYAML(data, &routes) return } -func Validate(data []byte) (err E.Error) { +func Validate(data []byte) (err gperr.Error) { _, err = validate(data) return } @@ -59,16 +59,16 @@ func (p *FileProvider) Logger() *zerolog.Logger { return &p.l } -func (p *FileProvider) loadRoutesImpl() (route.Routes, E.Error) { +func (p *FileProvider) loadRoutesImpl() (route.Routes, gperr.Error) { data, err := os.ReadFile(p.path) if err != nil { - return nil, E.Wrap(err) + return nil, gperr.Wrap(err) } routes, err := validate(data) if err != nil && len(routes) == 0 { - return nil, E.Wrap(err) + return nil, gperr.Wrap(err) } - return routes, E.Wrap(err) + return routes, gperr.Wrap(err) } func (p *FileProvider) NewWatcher() W.Watcher { diff --git a/internal/route/provider/provider.go b/internal/route/provider/provider.go index 78cb4a4..6894879 100644 --- a/internal/route/provider/provider.go +++ b/internal/route/provider/provider.go @@ -8,7 +8,7 @@ import ( "github.com/rs/zerolog" "github.com/yusing/go-proxy/agent/pkg/agent" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/route" "github.com/yusing/go-proxy/internal/route/provider/types" "github.com/yusing/go-proxy/internal/task" @@ -29,7 +29,7 @@ type ( fmt.Stringer ShortName() string IsExplicitOnly() bool - loadRoutesImpl() (route.Routes, E.Error) + loadRoutesImpl() (route.Routes, gperr.Error) NewWatcher() W.Watcher Logger() *zerolog.Logger } @@ -86,7 +86,7 @@ func (p *Provider) MarshalText() ([]byte, error) { return []byte(p.String()), nil } -func (p *Provider) startRoute(parent task.Parent, r *route.Route) E.Error { +func (p *Provider) startRoute(parent task.Parent, r *route.Route) gperr.Error { err := r.Start(parent) if err != nil { delete(p.routes, r.Alias) @@ -97,10 +97,10 @@ func (p *Provider) startRoute(parent task.Parent, r *route.Route) E.Error { } // Start implements task.TaskStarter. -func (p *Provider) Start(parent task.Parent) E.Error { +func (p *Provider) Start(parent task.Parent) gperr.Error { t := parent.Subtask("provider."+p.String(), false) - errs := E.NewBuilder("routes error") + errs := gperr.NewBuilder("routes error") for _, r := range p.routes { errs.Add(p.startRoute(t, r)) } @@ -114,8 +114,8 @@ func (p *Provider) Start(parent task.Parent) E.Error { handler.Handle(t, events) handler.Log() }, - func(err E.Error) { - E.LogError("event error", err, p.Logger()) + func(err gperr.Error) { + gperr.LogError("event error", err, p.Logger()) }, ) eventQueue.Start(p.watcher.Events(t.Context())) @@ -137,12 +137,12 @@ func (p *Provider) GetRoute(alias string) (r *route.Route, ok bool) { return } -func (p *Provider) loadRoutes() (routes route.Routes, err E.Error) { +func (p *Provider) loadRoutes() (routes route.Routes, err gperr.Error) { routes, err = p.loadRoutesImpl() if err != nil && len(routes) == 0 { return route.Routes{}, err } - errs := E.NewBuilder("routes error") + errs := gperr.NewBuilder("routes error") errs.Add(err) // check for exclusion // set alias and provider, then validate @@ -161,7 +161,7 @@ func (p *Provider) loadRoutes() (routes route.Routes, err E.Error) { return routes, errs.Error() } -func (p *Provider) LoadRoutes() (err E.Error) { +func (p *Provider) LoadRoutes() (err gperr.Error) { p.routes, err = p.loadRoutes() return } diff --git a/internal/route/reverse_proxy.go b/internal/route/reverse_proxy.go index 5af3774..7500122 100755 --- a/internal/route/reverse_proxy.go +++ b/internal/route/reverse_proxy.go @@ -10,15 +10,15 @@ import ( "github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/docker" "github.com/yusing/go-proxy/internal/docker/idlewatcher" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" - gphttp "github.com/yusing/go-proxy/internal/net/http" - "github.com/yusing/go-proxy/internal/net/http/accesslog" - "github.com/yusing/go-proxy/internal/net/http/loadbalancer" - loadbalance "github.com/yusing/go-proxy/internal/net/http/loadbalancer/types" - "github.com/yusing/go-proxy/internal/net/http/middleware" - metricslogger "github.com/yusing/go-proxy/internal/net/http/middleware/metrics_logger" - "github.com/yusing/go-proxy/internal/net/http/reverseproxy" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" + "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer" + loadbalance "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types" + "github.com/yusing/go-proxy/internal/net/gphttp/middleware" + metricslogger "github.com/yusing/go-proxy/internal/net/gphttp/middleware/metrics_logger" + "github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy" "github.com/yusing/go-proxy/internal/route/routes" "github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/watcher/health" @@ -41,7 +41,7 @@ type ( // var globalMux = http.NewServeMux() // TODO: support regex subdomain matching. -func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, E.Error) { +func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, gperr.Error) { httpConfig := base.HTTPConfig proxyURL := base.ProxyURL @@ -96,9 +96,9 @@ func (r *ReveseProxyRoute) String() string { } // Start implements task.TaskStarter. -func (r *ReveseProxyRoute) Start(parent task.Parent) E.Error { +func (r *ReveseProxyRoute) Start(parent task.Parent) gperr.Error { if existing, ok := routes.GetHTTPRoute(r.TargetName()); ok { - return E.Errorf("route already exists: from provider %s and %s", existing.ProviderName(), r.ProviderName()) + return gperr.Errorf("route already exists: from provider %s and %s", existing.ProviderName(), r.ProviderName()) } r.task = parent.Subtask("http."+r.TargetName(), false) @@ -130,7 +130,7 @@ func (r *ReveseProxyRoute) Start(parent task.Parent) E.Error { r.rp.AccessLogger, err = accesslog.NewFileAccessLogger(r.task, r.AccessLog) if err != nil { r.task.Finish(err) - return E.From(err) + return gperr.Wrap(err) } } @@ -146,7 +146,7 @@ func (r *ReveseProxyRoute) Start(parent task.Parent) E.Error { Str("route", r.TargetName()). Msg("`path_patterns` for reverse proxy is deprecated. Use `rules` instead.") mux := gphttp.NewServeMux() - patErrs := E.NewBuilder("invalid path pattern(s)") + patErrs := gperr.NewBuilder("invalid path pattern(s)") for _, p := range pathPatterns { patErrs.Add(mux.HandleFunc(p, r.rp.HandlerFunc)) } diff --git a/internal/route/route.go b/internal/route/route.go index 871d333..2ae9edb 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -8,6 +8,7 @@ import ( "github.com/yusing/go-proxy/internal" "github.com/yusing/go-proxy/internal/docker" idlewatcher "github.com/yusing/go-proxy/internal/docker/idlewatcher/types" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/homepage" net "github.com/yusing/go-proxy/internal/net/types" "github.com/yusing/go-proxy/internal/task" @@ -16,9 +17,8 @@ import ( dockertypes "github.com/docker/docker/api/types" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" - "github.com/yusing/go-proxy/internal/net/http/accesslog" - loadbalance "github.com/yusing/go-proxy/internal/net/http/loadbalancer/types" + "github.com/yusing/go-proxy/internal/net/gphttp/accesslog" + loadbalance "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types" "github.com/yusing/go-proxy/internal/route/rules" "github.com/yusing/go-proxy/internal/route/types" "github.com/yusing/go-proxy/internal/utils" @@ -67,14 +67,14 @@ func (r Routes) Contains(alias string) bool { return ok } -func (r *Route) Validate() (err E.Error) { +func (r *Route) Validate() (err gperr.Error) { if r.isValidated { return nil } r.isValidated = true r.Finalize() - errs := E.NewBuilder("entry validation failed") + errs := gperr.NewBuilder("entry validation failed") switch r.Scheme { case types.SchemeFileServer: @@ -88,14 +88,14 @@ func (r *Route) Validate() (err E.Error) { } fallthrough case types.SchemeTCP, types.SchemeUDP: - r.LisURL = E.Collect(errs, net.ParseURL, fmt.Sprintf("%s://:%d", r.Scheme, r.Port.Listening)) + r.LisURL = gperr.Collect(errs, net.ParseURL, fmt.Sprintf("%s://:%d", r.Scheme, r.Port.Listening)) fallthrough default: if r.LoadBalance != nil && r.LoadBalance.Link == "" { r.LoadBalance = nil } - r.ProxyURL = E.Collect(errs, net.ParseURL, fmt.Sprintf("%s://%s:%d", r.Scheme, r.Host, r.Port.Proxy)) - r.Idlewatcher = E.Collect(errs, idlewatcher.ValidateConfig, r.Container) + r.ProxyURL = gperr.Collect(errs, net.ParseURL, fmt.Sprintf("%s://%s:%d", r.Scheme, r.Host, r.Port.Proxy)) + r.Idlewatcher = gperr.Collect(errs, idlewatcher.ValidateConfig, r.Container) } if !r.UseHealthCheck() && (r.UseLoadBalance() || r.UseIdleWatcher()) { @@ -120,9 +120,9 @@ func (r *Route) Validate() (err E.Error) { return err } -func (r *Route) Start(parent task.Parent) (err E.Error) { +func (r *Route) Start(parent task.Parent) (err gperr.Error) { if r.impl == nil { - return E.New("route not initialized") + return gperr.New("route not initialized") } return r.impl.Start(parent) } diff --git a/internal/route/rules/do.go b/internal/route/rules/do.go index 6490987..f00c20d 100644 --- a/internal/route/rules/do.go +++ b/internal/route/rules/do.go @@ -6,9 +6,9 @@ import ( "strconv" "strings" - E "github.com/yusing/go-proxy/internal/error" - gphttp "github.com/yusing/go-proxy/internal/net/http" - "github.com/yusing/go-proxy/internal/net/http/reverseproxy" + "github.com/yusing/go-proxy/internal/gperr" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" + "github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy" "github.com/yusing/go-proxy/internal/net/types" "github.com/yusing/go-proxy/internal/utils/strutils" ) @@ -47,7 +47,7 @@ var commands = map[string]struct { "to": "the path to rewrite to, must start with /", }, }, - validate: func(args []string) (any, E.Error) { + validate: func(args []string) (any, gperr.Error) { if len(args) != 2 { return nil, ErrExpectTwoArgs } @@ -109,7 +109,7 @@ var commands = map[string]struct { "text": "the error message to return", }, }, - validate: func(args []string) (any, E.Error) { + validate: func(args []string) (any, gperr.Error) { if len(args) != 2 { return nil, ErrExpectTwoArgs } @@ -137,7 +137,7 @@ var commands = map[string]struct { "realm": "the authentication realm", }, }, - validate: func(args []string) (any, E.Error) { + validate: func(args []string) (any, gperr.Error) { if len(args) == 1 { return args[0], nil } @@ -176,7 +176,7 @@ var commands = map[string]struct { "value": "the value to set", }, }, - validate: func(args []string) (any, E.Error) { + validate: func(args []string) (any, gperr.Error) { return validateModField(ModFieldSet, args) }, build: func(args any) CommandHandler { @@ -191,7 +191,7 @@ var commands = map[string]struct { "value": "the value to add", }, }, - validate: func(args []string) (any, E.Error) { + validate: func(args []string) (any, gperr.Error) { return validateModField(ModFieldAdd, args) }, build: func(args any) CommandHandler { @@ -205,7 +205,7 @@ var commands = map[string]struct { "field": "the field to remove", }, }, - validate: func(args []string) (any, E.Error) { + validate: func(args []string) (any, gperr.Error) { return validateModField(ModFieldRemove, args) }, build: func(args any) CommandHandler { diff --git a/internal/route/rules/errors.go b/internal/route/rules/errors.go index d30093c..ec9e86e 100644 --- a/internal/route/rules/errors.go +++ b/internal/route/rules/errors.go @@ -1,18 +1,20 @@ package rules -import E "github.com/yusing/go-proxy/internal/error" +import ( + "github.com/yusing/go-proxy/internal/gperr" +) var ( - ErrUnterminatedQuotes = E.New("unterminated quotes") - ErrUnsupportedEscapeChar = E.New("unsupported escape char") - ErrUnknownDirective = E.New("unknown directive") - ErrInvalidArguments = E.New("invalid arguments") - ErrInvalidOnTarget = E.New("invalid `rule.on` target") - ErrInvalidCommandSequence = E.New("invalid command sequence") - ErrInvalidSetTarget = E.New("invalid `rule.set` target") + ErrUnterminatedQuotes = gperr.New("unterminated quotes") + ErrUnsupportedEscapeChar = gperr.New("unsupported escape char") + ErrUnknownDirective = gperr.New("unknown directive") + ErrInvalidArguments = gperr.New("invalid arguments") + ErrInvalidOnTarget = gperr.New("invalid `rule.on` target") + ErrInvalidCommandSequence = gperr.New("invalid command sequence") + ErrInvalidSetTarget = gperr.New("invalid `rule.set` target") - ErrExpectNoArg = E.Wrap(ErrInvalidArguments, "expect no arg") - ErrExpectOneArg = E.Wrap(ErrInvalidArguments, "expect 1 arg") - ErrExpectTwoArgs = E.Wrap(ErrInvalidArguments, "expect 2 args") - ErrExpectKVOptionalV = E.Wrap(ErrInvalidArguments, "expect 'key' or 'key value'") + ErrExpectNoArg = gperr.Wrap(ErrInvalidArguments, "expect no arg") + ErrExpectOneArg = gperr.Wrap(ErrInvalidArguments, "expect 1 arg") + ErrExpectTwoArgs = gperr.Wrap(ErrInvalidArguments, "expect 2 args") + ErrExpectKVOptionalV = gperr.Wrap(ErrInvalidArguments, "expect 'key' or 'key value'") ) diff --git a/internal/route/rules/on.go b/internal/route/rules/on.go index e0b1837..8c9e29f 100644 --- a/internal/route/rules/on.go +++ b/internal/route/rules/on.go @@ -3,7 +3,7 @@ package rules import ( "net/http" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/net/types" "github.com/yusing/go-proxy/internal/utils/strutils" ) @@ -240,7 +240,7 @@ func (on *RuleOn) Parse(v string) error { lines := strutils.SplitLine(v) checkAnd := make(CheckMatchAll, 0, len(lines)) - errs := E.NewBuilder("rule.on syntax errors") + errs := gperr.NewBuilder("rule.on syntax errors") for i, line := range lines { if line == "" { continue @@ -265,11 +265,11 @@ func (on *RuleOn) MarshalText() ([]byte, error) { return []byte(on.String()), nil } -func parseOn(line string) (Checker, E.Error) { +func parseOn(line string) (Checker, gperr.Error) { ors := strutils.SplitRune(line, '|') if len(ors) > 1 { - errs := E.NewBuilder("rule.on syntax errors") + errs := gperr.NewBuilder("rule.on syntax errors") checkOr := make(CheckMatchSingle, len(ors)) for i, or := range ors { curCheckers, err := parseOn(or) diff --git a/internal/route/rules/on_test.go b/internal/route/rules/on_test.go index 7c671ce..fb60ffc 100644 --- a/internal/route/rules/on_test.go +++ b/internal/route/rules/on_test.go @@ -7,7 +7,7 @@ import ( "net/url" "testing" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" . "github.com/yusing/go-proxy/internal/utils/testing" "golang.org/x/crypto/bcrypt" ) @@ -16,7 +16,7 @@ func TestParseOn(t *testing.T) { tests := []struct { name string input string - wantErr E.Error + wantErr gperr.Error }{ // header { diff --git a/internal/route/rules/parser.go b/internal/route/rules/parser.go index 7ebc689..dc317b0 100644 --- a/internal/route/rules/parser.go +++ b/internal/route/rules/parser.go @@ -4,7 +4,7 @@ import ( "bytes" "unicode" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) var escapedChars = map[rune]rune{ @@ -23,7 +23,7 @@ var escapedChars = map[rune]rune{ // // error 403 "Forbidden 'foo' 'bar'" // error 403 Forbidden\ \"foo\"\ \"bar\". -func parse(v string) (subject string, args []string, err E.Error) { +func parse(v string) (subject string, args []string, err gperr.Error) { buf := bytes.NewBuffer(make([]byte, 0, len(v))) escaped := false diff --git a/internal/route/rules/parser_test.go b/internal/route/rules/parser_test.go index f43f284..b5743ae 100644 --- a/internal/route/rules/parser_test.go +++ b/internal/route/rules/parser_test.go @@ -4,7 +4,7 @@ import ( "strconv" "testing" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" . "github.com/yusing/go-proxy/internal/utils/testing" ) @@ -14,7 +14,7 @@ func TestParser(t *testing.T) { input string subject string args []string - wantErr E.Error + wantErr gperr.Error }{ { name: "basic", diff --git a/internal/route/rules/validate.go b/internal/route/rules/validate.go index e894309..58a7dd8 100644 --- a/internal/route/rules/validate.go +++ b/internal/route/rules/validate.go @@ -6,13 +6,13 @@ import ( "path" "strings" - E "github.com/yusing/go-proxy/internal/error" - gphttp "github.com/yusing/go-proxy/internal/net/http" + "github.com/yusing/go-proxy/internal/gperr" + gphttp "github.com/yusing/go-proxy/internal/net/gphttp" "github.com/yusing/go-proxy/internal/net/types" ) type ( - ValidateFunc func(args []string) (any, E.Error) + ValidateFunc func(args []string) (any, gperr.Error) Tuple[T1, T2 any] struct { First T1 Second T2 @@ -29,7 +29,7 @@ func (t *Tuple[T1, T2]) String() string { } // toStrTuple returns *StrTuple. -func toStrTuple(args []string) (any, E.Error) { +func toStrTuple(args []string) (any, gperr.Error) { if len(args) != 2 { return nil, ErrExpectTwoArgs } @@ -37,7 +37,7 @@ func toStrTuple(args []string) (any, E.Error) { } // toKVOptionalV returns *StrTuple that value is optional. -func toKVOptionalV(args []string) (any, E.Error) { +func toKVOptionalV(args []string) (any, gperr.Error) { switch len(args) { case 1: return &StrTuple{args[0], ""}, nil @@ -49,7 +49,7 @@ func toKVOptionalV(args []string) (any, E.Error) { } // validateURL returns types.URL with the URL validated. -func validateURL(args []string) (any, E.Error) { +func validateURL(args []string) (any, gperr.Error) { if len(args) != 1 { return nil, ErrExpectOneArg } @@ -61,7 +61,7 @@ func validateURL(args []string) (any, E.Error) { } // validateAbsoluteURL returns types.URL with the URL validated. -func validateAbsoluteURL(args []string) (any, E.Error) { +func validateAbsoluteURL(args []string) (any, gperr.Error) { if len(args) != 1 { return nil, ErrExpectOneArg } @@ -79,7 +79,7 @@ func validateAbsoluteURL(args []string) (any, E.Error) { } // validateCIDR returns types.CIDR with the CIDR validated. -func validateCIDR(args []string) (any, E.Error) { +func validateCIDR(args []string) (any, gperr.Error) { if len(args) != 1 { return nil, ErrExpectOneArg } @@ -94,7 +94,7 @@ func validateCIDR(args []string) (any, E.Error) { } // validateURLPath returns string with the path validated. -func validateURLPath(args []string) (any, E.Error) { +func validateURLPath(args []string) (any, gperr.Error) { if len(args) != 1 { return nil, ErrExpectOneArg } @@ -112,8 +112,8 @@ func validateURLPath(args []string) (any, E.Error) { } // validateURLPaths returns []string with each element validated. -func validateURLPaths(paths []string) (any, E.Error) { - errs := E.NewBuilder("invalid url paths") +func validateURLPaths(paths []string) (any, gperr.Error) { + errs := gperr.NewBuilder("invalid url paths") for i, p := range paths { val, err := validateURLPath([]string{p}) if err != nil { @@ -129,7 +129,7 @@ func validateURLPaths(paths []string) (any, E.Error) { } // validateFSPath returns string with the path validated. -func validateFSPath(args []string) (any, E.Error) { +func validateFSPath(args []string) (any, gperr.Error) { if len(args) != 1 { return nil, ErrExpectOneArg } @@ -141,7 +141,7 @@ func validateFSPath(args []string) (any, E.Error) { } // validateMethod returns string with the method validated. -func validateMethod(args []string) (any, E.Error) { +func validateMethod(args []string) (any, gperr.Error) { if len(args) != 1 { return nil, ErrExpectOneArg } @@ -153,7 +153,7 @@ func validateMethod(args []string) (any, E.Error) { } // validateUserBCryptPassword returns *HashedCrendential with the password validated. -func validateUserBCryptPassword(args []string) (any, E.Error) { +func validateUserBCryptPassword(args []string) (any, gperr.Error) { if len(args) != 2 { return nil, ErrExpectTwoArgs } @@ -161,7 +161,7 @@ func validateUserBCryptPassword(args []string) (any, E.Error) { } // validateModField returns CommandHandler with the field validated. -func validateModField(mod FieldModifier, args []string) (CommandHandler, E.Error) { +func validateModField(mod FieldModifier, args []string) (CommandHandler, gperr.Error) { setField, ok := modFields[args[0]] if !ok { return nil, ErrInvalidSetTarget.Subject(args[0]) diff --git a/internal/route/stream.go b/internal/route/stream.go index 3ec3112..7f4c206 100755 --- a/internal/route/stream.go +++ b/internal/route/stream.go @@ -7,7 +7,7 @@ import ( "github.com/rs/zerolog" "github.com/yusing/go-proxy/internal/docker" "github.com/yusing/go-proxy/internal/docker/idlewatcher" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" net "github.com/yusing/go-proxy/internal/net/types" "github.com/yusing/go-proxy/internal/route/routes" @@ -30,7 +30,7 @@ type StreamRoute struct { l zerolog.Logger } -func NewStreamRoute(base *Route) (route.Route, E.Error) { +func NewStreamRoute(base *Route) (route.Route, gperr.Error) { // TODO: support non-coherent scheme return &StreamRoute{ Route: base, @@ -46,9 +46,9 @@ func (r *StreamRoute) String() string { } // Start implements task.TaskStarter. -func (r *StreamRoute) Start(parent task.Parent) E.Error { +func (r *StreamRoute) Start(parent task.Parent) gperr.Error { if existing, ok := routes.GetStreamRoute(r.TargetName()); ok { - return E.Errorf("route already exists: from provider %s and %s", existing.ProviderName(), r.ProviderName()) + return gperr.Errorf("route already exists: from provider %s and %s", existing.ProviderName(), r.ProviderName()) } r.task = parent.Subtask("stream." + r.TargetName()) r.Stream = NewStream(r) @@ -81,14 +81,14 @@ func (r *StreamRoute) Start(parent task.Parent) E.Error { if err := r.Stream.Setup(); err != nil { r.task.Finish(err) - return E.From(err) + return gperr.Wrap(err) } r.l.Info().Int("port", r.Port.Listening).Msg("listening") if r.HealthMon != nil { if err := r.HealthMon.Start(r.task); err != nil { - E.LogWarn("health monitor error", err, &r.l) + gperr.LogWarn("health monitor error", err, &r.l) } } @@ -128,7 +128,7 @@ func (r *StreamRoute) acceptConnections() { select { case <-r.task.Context().Done(): default: - E.LogError("accept connection error", err, &r.l) + gperr.LogError("accept connection error", err, &r.l) } r.task.Finish(err) return @@ -139,7 +139,7 @@ func (r *StreamRoute) acceptConnections() { go func() { err := r.Stream.Handle(conn) if err != nil && !errors.Is(err, context.Canceled) { - E.LogError("handle connection error", err, &r.l) + gperr.LogError("handle connection error", err, &r.l) } }() } diff --git a/internal/route/types/port.go b/internal/route/types/port.go index 89ce88f..57c08fd 100644 --- a/internal/route/types/port.go +++ b/internal/route/types/port.go @@ -3,7 +3,7 @@ package types import ( "strconv" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/utils/strutils" ) @@ -13,8 +13,8 @@ type Port struct { } var ( - ErrInvalidPortSyntax = E.New("invalid port syntax, expect [listening_port:]target_port") - ErrPortOutOfRange = E.New("port out of range") + ErrInvalidPortSyntax = gperr.New("invalid port syntax, expect [listening_port:]target_port") + ErrPortOutOfRange = gperr.New("port out of range") ) // Parse implements strutils.Parser. @@ -28,7 +28,7 @@ func (p *Port) Parse(v string) (err error) { var err2 error p.Listening, err = strconv.Atoi(parts[0]) p.Proxy, err2 = strconv.Atoi(parts[1]) - err = E.Join(err, err2) + err = gperr.Join(err, err2) default: return ErrInvalidPortSyntax.Subject(v) } diff --git a/internal/route/types/route.go b/internal/route/types/route.go index 87a027d..2fe2ed3 100644 --- a/internal/route/types/route.go +++ b/internal/route/types/route.go @@ -11,7 +11,7 @@ import ( "github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/watcher/health" - loadbalance "github.com/yusing/go-proxy/internal/net/http/loadbalancer/types" + loadbalance "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types" ) type ( diff --git a/internal/route/types/scheme.go b/internal/route/types/scheme.go index 6830c6e..cbb4ce2 100644 --- a/internal/route/types/scheme.go +++ b/internal/route/types/scheme.go @@ -1,12 +1,12 @@ package types import ( - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) type Scheme string -var ErrInvalidScheme = E.New("invalid scheme") +var ErrInvalidScheme = gperr.New("invalid scheme") const ( SchemeHTTP Scheme = "http" @@ -16,7 +16,7 @@ const ( SchemeFileServer Scheme = "fileserver" ) -func (s Scheme) Validate() E.Error { +func (s Scheme) Validate() gperr.Error { switch s { case SchemeHTTP, SchemeHTTPS, SchemeTCP, SchemeUDP, SchemeFileServer: diff --git a/internal/route/udp_forwarder.go b/internal/route/udp_forwarder.go index d33b91b..62149af 100644 --- a/internal/route/udp_forwarder.go +++ b/internal/route/udp_forwarder.go @@ -6,7 +6,7 @@ import ( "net" "sync" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/net/types" F "github.com/yusing/go-proxy/internal/utils/functional" @@ -192,7 +192,7 @@ func (w *UDPForwarder) Handle(streamConn types.StreamConn) error { } func (w *UDPForwarder) Close() error { - errs := E.NewBuilder("errors closing udp conn") + errs := gperr.NewBuilder("errors closing udp conn") w.mu.Lock() defer w.mu.Unlock() w.connMap.RangeAll(func(key string, conn *UDPConn) { diff --git a/internal/task/task.go b/internal/task/task.go index 19a5f8a..2421a13 100644 --- a/internal/task/task.go +++ b/internal/task/task.go @@ -8,7 +8,7 @@ import ( "time" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/utils/strutils" ) @@ -19,7 +19,7 @@ type ( // and returns an error if it fails to start. // // callerSubtask.Finish must be called when start fails or the object is finished. - Start(parent Parent) E.Error + Start(parent Parent) gperr.Error Task() *Task } TaskFinisher interface { diff --git a/internal/utils/io.go b/internal/utils/io.go index 10e526d..6a5b6cf 100644 --- a/internal/utils/io.go +++ b/internal/utils/io.go @@ -8,7 +8,7 @@ import ( "sync" "syscall" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) // TODO: move to "utils/io". @@ -90,10 +90,10 @@ func NewBidirectionalPipe(ctx context.Context, rw1 io.ReadWriteCloser, rw2 io.Re } } -func (p BidirectionalPipe) Start() E.Error { +func (p BidirectionalPipe) Start() gperr.Error { var wg sync.WaitGroup wg.Add(2) - b := E.NewBuilder("bidirectional pipe error") + b := gperr.NewBuilder("bidirectional pipe error") go func() { b.Add(p.pSrcDst.Start()) wg.Done() diff --git a/internal/utils/serialization.go b/internal/utils/serialization.go index 6830efd..0cc4f98 100644 --- a/internal/utils/serialization.go +++ b/internal/utils/serialization.go @@ -11,7 +11,7 @@ import ( "time" "github.com/go-playground/validator/v10" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/utils/functional" "github.com/yusing/go-proxy/internal/utils/strutils" "gopkg.in/yaml.v3" @@ -20,15 +20,15 @@ import ( type SerializedObject = map[string]any type MapUnmarshaller interface { - UnmarshalMap(m map[string]any) E.Error + UnmarshalMap(m map[string]any) gperr.Error } var ( - ErrInvalidType = E.New("invalid type") - ErrNilValue = E.New("nil") - ErrUnsettable = E.New("unsettable") - ErrUnsupportedConversion = E.New("unsupported conversion") - ErrUnknownField = E.New("unknown field") + ErrInvalidType = gperr.New("invalid type") + ErrNilValue = gperr.New("nil") + ErrUnsettable = gperr.New("unsettable") + ErrUnsupportedConversion = gperr.New("unsupported conversion") + ErrUnknownField = gperr.New("unknown field") ) var ( @@ -89,8 +89,8 @@ func extractFields(t reflect.Type) (all, anonymous []reflect.StructField) { return fields, anonymous } -func ValidateWithFieldTags(s any) E.Error { - errs := E.NewBuilder("validate error") +func ValidateWithFieldTags(s any) gperr.Error { + errs := gperr.NewBuilder("validate error") err := validate.Struct(s) var valErrs validator.ValidationErrors if errors.As(err, &valErrs) { @@ -107,13 +107,13 @@ func ValidateWithFieldTags(s any) E.Error { return errs.Error() } -func ValidateWithCustomValidator(v reflect.Value) E.Error { +func ValidateWithCustomValidator(v reflect.Value) gperr.Error { isStruct := false for { switch v.Kind() { case reflect.Pointer, reflect.Interface: if v.IsNil() { - return E.Errorf("validate: v is %w", ErrNilValue) + return gperr.Errorf("validate: v is %w", ErrNilValue) } if validate, ok := v.Interface().(CustomValidator); ok { return validate.Validate() @@ -134,14 +134,14 @@ func ValidateWithCustomValidator(v reflect.Value) E.Error { } } -func dive(dst reflect.Value) (v reflect.Value, t reflect.Type, err E.Error) { +func dive(dst reflect.Value) (v reflect.Value, t reflect.Type, err gperr.Error) { dstT := dst.Type() for { switch dst.Kind() { case reflect.Pointer, reflect.Interface: if dst.IsNil() { if !dst.CanSet() { - err = E.Errorf("dive: dst is %w and is not settable", ErrNilValue) + err = gperr.Errorf("dive: dst is %w and is not settable", ErrNilValue) return } dst.Set(New(dstT.Elem())) @@ -158,7 +158,7 @@ func dive(dst reflect.Value) (v reflect.Value, t reflect.Type, err E.Error) { case reflect.Slice: dst.Set(reflect.MakeSlice(dstT, 0, 0)) default: - err = E.Errorf("deserialize: %w for dst %s", ErrInvalidType, dstT.String()) + err = gperr.Errorf("deserialize: %w for dst %s", ErrInvalidType, dstT.String()) return } } @@ -180,7 +180,7 @@ func dive(dst reflect.Value) (v reflect.Value, t reflect.Type, err E.Error) { // If the target value is a map[string]any the SerializedObject will be deserialized into the map. // // The function returns an error if the target value is not a struct or a map[string]any, or if there is an error during deserialization. -func Deserialize(src SerializedObject, dst any) (err E.Error) { +func Deserialize(src SerializedObject, dst any) (err gperr.Error) { dstV := reflect.ValueOf(dst) dstT := dstV.Type() @@ -189,7 +189,7 @@ func Deserialize(src SerializedObject, dst any) (err E.Error) { dstV.Set(reflect.Zero(dstT)) return nil } - return E.Errorf("deserialize: src is %w and dst is not settable\n%s", ErrNilValue, debug.Stack()) + return gperr.Errorf("deserialize: src is %w and dst is not settable\n%s", ErrNilValue, debug.Stack()) } if dstT.Implements(mapUnmarshalerType) { @@ -209,7 +209,7 @@ func Deserialize(src SerializedObject, dst any) (err E.Error) { // convert target fields to lower no-snake // then check if the field of data is in the target - errs := E.NewBuilder("deserialize error") + errs := gperr.NewBuilder("deserialize error") switch dstV.Kind() { case reflect.Struct, reflect.Interface: @@ -302,9 +302,9 @@ func isIntFloat(t reflect.Kind) bool { // // Returns: // - error: the error occurred during conversion, or nil if no error occurred. -func Convert(src reflect.Value, dst reflect.Value) E.Error { +func Convert(src reflect.Value, dst reflect.Value) gperr.Error { if !dst.IsValid() { - return E.Errorf("convert: dst is %w", ErrNilValue) + return gperr.Errorf("convert: dst is %w", ErrNilValue) } if !src.IsValid() { @@ -312,7 +312,7 @@ func Convert(src reflect.Value, dst reflect.Value) E.Error { dst.Set(reflect.Zero(dst.Type())) return nil } - return E.Errorf("convert: src is %w", ErrNilValue) + return gperr.Errorf("convert: src is %w", ErrNilValue) } srcT := src.Type() @@ -379,7 +379,7 @@ func Convert(src reflect.Value, dst reflect.Value) E.Error { if dstT.Kind() != reflect.Slice { return ErrUnsupportedConversion.Subject(dstT.String() + " to " + srcT.String()) } - sliceErrs := E.NewBuilder("slice conversion errors") + sliceErrs := gperr.NewBuilder("slice conversion errors") newSlice := reflect.MakeSlice(dstT, src.Len(), src.Len()) i := 0 for j, v := range src.Seq2() { @@ -401,7 +401,7 @@ func Convert(src reflect.Value, dst reflect.Value) E.Error { return ErrUnsupportedConversion.Subjectf("%s to %s", srcT, dstT) } -func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.Error) { +func ConvertString(src string, dst reflect.Value) (convertible bool, convErr gperr.Error) { convertible = true dstT := dst.Type() if dst.Kind() == reflect.Ptr { @@ -423,7 +423,7 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.E } d, err := time.ParseDuration(src) if err != nil { - return true, E.From(err) + return true, gperr.Wrap(err) } dst.Set(reflect.ValueOf(d)) return @@ -443,14 +443,14 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.E i, err = strconv.ParseFloat(src, dstT.Bits()) } if err != nil { - return true, E.From(err) + return true, gperr.Wrap(err) } dst.Set(reflect.ValueOf(i).Convert(dstT)) return } // check if (*T).Convertor is implemented if parser, ok := dst.Addr().Interface().(strutils.Parser); ok { - return true, E.From(parser.Parse(src)) + return true, gperr.Wrap(parser.Parse(src)) } // yaml like var tmp any @@ -462,7 +462,7 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.E if !isMultiline && src[0] != '-' { values := strutils.CommaSeperatedList(src) dst.Set(reflect.MakeSlice(dst.Type(), len(values), len(values))) - errs := E.NewBuilder("invalid slice values") + errs := gperr.NewBuilder("invalid slice values") for i, v := range values { err := Convert(reflect.ValueOf(v), dst.Index(i)) if err != nil { @@ -477,14 +477,14 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.E sl := make([]any, 0) err := yaml.Unmarshal([]byte(src), &sl) if err != nil { - return true, E.From(err) + return true, gperr.Wrap(err) } tmp = sl case reflect.Map, reflect.Struct: rawMap := make(SerializedObject) err := yaml.Unmarshal([]byte(src), &rawMap) if err != nil { - return true, E.From(err) + return true, gperr.Wrap(err) } tmp = rawMap default: @@ -493,17 +493,17 @@ func ConvertString(src string, dst reflect.Value) (convertible bool, convErr E.E return true, Convert(reflect.ValueOf(tmp), dst) } -func DeserializeYAML[T any](data []byte, target *T) E.Error { +func DeserializeYAML[T any](data []byte, target *T) gperr.Error { m := make(map[string]any) if err := yaml.Unmarshal(data, m); err != nil { - return E.From(err) + return gperr.Wrap(err) } return Deserialize(m, target) } -func DeserializeYAMLMap[V any](data []byte) (_ functional.Map[string, V], err E.Error) { +func DeserializeYAMLMap[V any](data []byte) (_ functional.Map[string, V], err gperr.Error) { m := make(map[string]any) - if err = E.From(yaml.Unmarshal(data, m)); err != nil { + if err = gperr.Wrap(yaml.Unmarshal(data, m)); err != nil { return } m2 := make(map[string]V, len(m)) diff --git a/internal/utils/validation.go b/internal/utils/validation.go index 32db124..490c348 100644 --- a/internal/utils/validation.go +++ b/internal/utils/validation.go @@ -2,15 +2,15 @@ package utils import ( "github.com/go-playground/validator/v10" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) var validate = validator.New() -var ErrValidationError = E.New("validation error") +var ErrValidationError = gperr.New("validation error") type CustomValidator interface { - Validate() E.Error + Validate() gperr.Error } func Validator() *validator.Validate { diff --git a/internal/watcher/directory_watcher.go b/internal/watcher/directory_watcher.go index 171d59e..45cca6a 100644 --- a/internal/watcher/directory_watcher.go +++ b/internal/watcher/directory_watcher.go @@ -8,7 +8,7 @@ import ( "github.com/fsnotify/fsnotify" "github.com/rs/zerolog" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/task" "github.com/yusing/go-proxy/internal/watcher/events" @@ -24,7 +24,7 @@ type DirWatcher struct { mu sync.Mutex eventCh chan Event - errCh chan E.Error + errCh chan gperr.Error task *task.Task } @@ -55,14 +55,14 @@ func NewDirectoryWatcher(parent task.Parent, dirPath string) *DirWatcher { w: w, fwMap: make(map[string]*fileWatcher), eventCh: make(chan Event), - errCh: make(chan E.Error), + errCh: make(chan gperr.Error), task: parent.Subtask("dir_watcher(" + dirPath + ")"), } go helper.start() return helper } -func (h *DirWatcher) Events(_ context.Context) (<-chan Event, <-chan E.Error) { +func (h *DirWatcher) Events(_ context.Context) (<-chan Event, <-chan gperr.Error) { return h.eventCh, h.errCh } @@ -78,7 +78,7 @@ func (h *DirWatcher) Add(relPath string) Watcher { s = &fileWatcher{ relPath: relPath, eventCh: make(chan Event), - errCh: make(chan E.Error), + errCh: make(chan gperr.Error), } h.fwMap[relPath] = s return s @@ -162,7 +162,7 @@ func (h *DirWatcher) start() { return } select { - case h.errCh <- E.From(err): + case h.errCh <- gperr.Wrap(err): default: } } diff --git a/internal/watcher/docker_watcher.go b/internal/watcher/docker_watcher.go index 647357e..89b8a0d 100644 --- a/internal/watcher/docker_watcher.go +++ b/internal/watcher/docker_watcher.go @@ -7,7 +7,7 @@ import ( docker_events "github.com/docker/docker/api/types/events" "github.com/docker/docker/api/types/filters" D "github.com/yusing/go-proxy/internal/docker" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/watcher/events" ) @@ -61,7 +61,7 @@ func NewDockerWatcherWithClient(client *D.SharedClient) DockerWatcher { } } -func (w DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.Error) { +func (w DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan gperr.Error) { return w.EventsWithOptions(ctx, optionsDefault) } @@ -71,9 +71,9 @@ func (w DockerWatcher) Close() { } } -func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerListOptions) (<-chan Event, <-chan E.Error) { +func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerListOptions) (<-chan Event, <-chan gperr.Error) { eventCh := make(chan Event, 100) - errCh := make(chan E.Error, 10) + errCh := make(chan gperr.Error, 10) go func() { defer func() { @@ -89,7 +89,7 @@ func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerList retryTicker := time.NewTicker(dockerWatcherRetryInterval) for err != nil { attempts++ - errCh <- E.Errorf("docker connection attempt #%d: %w", attempts, err) + errCh <- gperr.Errorf("docker connection attempt #%d: %w", attempts, err) select { case <-ctx.Done(): retryTicker.Stop() @@ -126,7 +126,7 @@ func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerList if err == nil { continue } - errCh <- E.From(err) + errCh <- gperr.Wrap(err) select { case <-ctx.Done(): return diff --git a/internal/watcher/events/event_queue.go b/internal/watcher/events/event_queue.go index 563c8cd..276a2d9 100644 --- a/internal/watcher/events/event_queue.go +++ b/internal/watcher/events/event_queue.go @@ -5,7 +5,7 @@ import ( "time" "github.com/yusing/go-proxy/internal/common" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/task" ) @@ -19,7 +19,7 @@ type ( onError OnErrorFunc } OnFlushFunc = func(events []Event) - OnErrorFunc = func(err E.Error) + OnErrorFunc = func(err gperr.Error) ) const eventQueueCapacity = 10 @@ -50,13 +50,13 @@ func NewEventQueue(queueTask *task.Task, flushInterval time.Duration, onFlush On } } -func (e *EventQueue) Start(eventCh <-chan Event, errCh <-chan E.Error) { +func (e *EventQueue) Start(eventCh <-chan Event, errCh <-chan gperr.Error) { origOnFlush := e.onFlush // recover panic in onFlush when in production mode e.onFlush = func(events []Event) { defer func() { if err := recover(); err != nil { - e.onError(E.New("recovered panic in onFlush"). + e.onError(gperr.New("recovered panic in onFlush"). Withf("%v", err). Subject(e.task.Name())) if common.IsDebug { diff --git a/internal/watcher/file_watcher.go b/internal/watcher/file_watcher.go index a53025d..41989a1 100644 --- a/internal/watcher/file_watcher.go +++ b/internal/watcher/file_watcher.go @@ -3,15 +3,15 @@ package watcher import ( "context" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" ) type fileWatcher struct { relPath string eventCh chan Event - errCh chan E.Error + errCh chan gperr.Error } -func (fw *fileWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.Error) { +func (fw *fileWatcher) Events(ctx context.Context) (<-chan Event, <-chan gperr.Error) { return fw.eventCh, fw.errCh } diff --git a/internal/watcher/health/monitor/monitor.go b/internal/watcher/health/monitor/monitor.go index 0d76877..86d13f9 100644 --- a/internal/watcher/health/monitor/monitor.go +++ b/internal/watcher/health/monitor/monitor.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/logging" "github.com/yusing/go-proxy/internal/metrics" "github.com/yusing/go-proxy/internal/net/types" @@ -57,9 +57,9 @@ func (mon *monitor) ContextWithTimeout(cause string) (ctx context.Context, cance } // Start implements task.TaskStarter. -func (mon *monitor) Start(parent task.Parent) E.Error { +func (mon *monitor) Start(parent task.Parent) gperr.Error { if mon.config.Interval <= 0 { - return E.From(ErrNegativeInterval) + return gperr.Wrap(ErrNegativeInterval) } mon.service = parent.Name() diff --git a/internal/watcher/watcher.go b/internal/watcher/watcher.go index e33cd55..1c51ec8 100644 --- a/internal/watcher/watcher.go +++ b/internal/watcher/watcher.go @@ -3,12 +3,12 @@ package watcher import ( "context" - E "github.com/yusing/go-proxy/internal/error" + "github.com/yusing/go-proxy/internal/gperr" "github.com/yusing/go-proxy/internal/watcher/events" ) type Event = events.Event type Watcher interface { - Events(ctx context.Context) (<-chan Event, <-chan E.Error) + Events(ctx context.Context) (<-chan Event, <-chan gperr.Error) }