diff --git a/.github/workflows/bin-release.yml b/.github/workflows/bin-release.yml index f86deb6..3f0e7b5 100644 --- a/.github/workflows/bin-release.yml +++ b/.github/workflows/bin-release.yml @@ -1,4 +1,4 @@ -# .github/workflows/release.yaml +name: Bin release on: release: types: [created] diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..f40d365 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,23 @@ +name: Lint + +on: + push: + pull_request: + +jobs: + lint: + name: Run on Ubuntu + runs-on: ubuntu-latest + steps: + - name: Clone the code + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '~1.22' + + - name: Run linter + uses: golangci/golangci-lint-action@v6 + with: + version: v1.61 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d8fa27c..c55ce02 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: CI +name: Release on: push: tags: diff --git a/.github/workflows/go.yml b/.github/workflows/test.yml similarity index 96% rename from .github/workflows/go.yml rename to .github/workflows/test.yml index fc445e6..e3d4de6 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Go +name: Test on: push: diff --git a/docs/quickstart/route.md b/docs/quickstart/route.md index 92dda32..a0836ea 100644 --- a/docs/quickstart/route.md +++ b/docs/quickstart/route.md @@ -135,6 +135,7 @@ gateway: - https://example.com - https://example2.com - https://example4.com + insecureSkipVerify: true methods: [] healthCheck: path: "/health/live" diff --git a/examples/goma.yml b/examples/goma.yml index abf3181..ab41911 100644 --- a/examples/goma.yml +++ b/examples/goma.yml @@ -87,6 +87,7 @@ gateway: backends: - https://example.com - https://example2.com + insecureSkipVerify: true methods: - GET # Route healthcheck diff --git a/internal/config.go b/internal/config.go index 84a34e9..72ad4ff 100644 --- a/internal/config.go +++ b/internal/config.go @@ -30,8 +30,6 @@ import ( "os" ) -var cfg *Gateway - // Config reads config file and returns Gateway func (GatewayServer) Config(configFile string) (*GatewayServer, error) { if util.FileExists(configFile) { diff --git a/internal/cors_type.go b/internal/cors_type.go new file mode 100644 index 0000000..717cf43 --- /dev/null +++ b/internal/cors_type.go @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Jonas Kaninda + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package pkg + +type Cors struct { + // Cors Allowed origins, + //e.g: + // + // - http://localhost:80 + // + // - https://example.com + Origins []string `yaml:"origins"` + // + //e.g: + // + //Access-Control-Allow-Origin: '*' + // + // Access-Control-Allow-Methods: 'GET, POST, PUT, DELETE, OPTIONS' + // + // Access-Control-Allow-Cors: 'Content-Type, Authorization' + Headers map[string]string `yaml:"headers"` +} diff --git a/internal/gateway_type.go b/internal/gateway_type.go new file mode 100644 index 0000000..23467c5 --- /dev/null +++ b/internal/gateway_type.go @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Jonas Kaninda + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package pkg + +// Gateway contains Goma Proxy Gateway's configs +type Gateway struct { + // SSLCertFile SSL Certificate file + SSLCertFile string `yaml:"sslCertFile" env:"GOMA_SSL_CERT_FILE, overwrite"` + // SSLKeyFile SSL Private key file + SSLKeyFile string `yaml:"sslKeyFile" env:"GOMA_SSL_KEY_FILE, overwrite"` + // Redis contains redis database details + Redis Redis `yaml:"redis"` + // WriteTimeout defines proxy write timeout + WriteTimeout int `yaml:"writeTimeout" env:"GOMA_WRITE_TIMEOUT, overwrite"` + // ReadTimeout defines proxy read timeout + ReadTimeout int `yaml:"readTimeout" env:"GOMA_READ_TIMEOUT, overwrite"` + // IdleTimeout defines proxy idle timeout + IdleTimeout int `yaml:"idleTimeout" env:"GOMA_IDLE_TIMEOUT, overwrite"` + // RateLimit Defines the number of request peer minutes + RateLimit int `yaml:"rateLimit" env:"GOMA_RATE_LIMIT, overwrite"` + // BlockCommonExploits enable, disable block common exploits + BlockCommonExploits bool `yaml:"blockCommonExploits"` + AccessLog string `yaml:"accessLog" env:"GOMA_ACCESS_LOG, overwrite"` + ErrorLog string `yaml:"errorLog" env:"GOMA_ERROR_LOG=, overwrite"` + LogLevel string `yaml:"logLevel" env:"GOMA_LOG_LEVEL, overwrite"` + // DisableHealthCheckStatus enable and disable routes health check + DisableHealthCheckStatus bool `yaml:"disableHealthCheckStatus"` + // DisableRouteHealthCheckError allows enabling and disabling backend healthcheck errors + DisableRouteHealthCheckError bool `yaml:"disableRouteHealthCheckError"` + //Disable allows enabling and disabling displaying routes on start + DisableDisplayRouteOnStart bool `yaml:"disableDisplayRouteOnStart"` + // DisableKeepAlive allows enabling and disabling KeepALive server + DisableKeepAlive bool `yaml:"disableKeepAlive"` + EnableMetrics bool `yaml:"enableMetrics"` + // InterceptErrors holds the status codes to intercept the error from backend + InterceptErrors []int `yaml:"interceptErrors"` + // Cors holds proxy global cors + Cors Cors `yaml:"cors"` + + // Routes holds proxy routes + Routes []Route `yaml:"routes"` +} diff --git a/internal/handler.go b/internal/handler.go index 4036850..5d53df1 100644 --- a/internal/handler.go +++ b/internal/handler.go @@ -18,6 +18,7 @@ limitations under the License. import ( "context" "encoding/json" + "fmt" "github.com/gorilla/mux" "github.com/jkaninda/goma-gateway/pkg/logger" "net/http" @@ -56,32 +57,33 @@ func CORSHandler(cors Cors) mux.MiddlewareFunc { func ProxyErrorHandler(w http.ResponseWriter, r *http.Request, err error) { logger.Error("Proxy error: %v", err) w.WriteHeader(http.StatusBadGateway) - _, err = w.Write([]byte("Bad Gateway")) + _, err = w.Write([]byte(fmt.Sprintf("%d %s ", http.StatusBadGateway, http.StatusText(http.StatusBadGateway)))) if err != nil { return } - return } // HealthCheckHandler handles health check of routes func (heathRoute HealthCheckRoute) HealthCheckHandler(w http.ResponseWriter, r *http.Request) { logger.Debug("%s %s %s %s", r.Method, r.RemoteAddr, r.URL, r.UserAgent()) + healthRoutes := healthCheckRoutes(heathRoute.Routes) wg := sync.WaitGroup{} - wg.Add(len(heathRoute.Routes)) + wg.Add(len(healthRoutes)) var routes []HealthCheckRouteResponse - for _, health := range healthCheckRoutes(heathRoute.Routes) { + for _, health := range healthRoutes { go func() { - defer wg.Done() err := health.Check() if err != nil { if heathRoute.DisableRouteHealthCheckError { routes = append(routes, HealthCheckRouteResponse{Name: health.Name, Status: "unhealthy", Error: "Route healthcheck errors disabled"}) + } else { + routes = append(routes, HealthCheckRouteResponse{Name: health.Name, Status: "unhealthy", Error: "Error: " + err.Error()}) } - routes = append(routes, HealthCheckRouteResponse{Name: health.Name, Status: "unhealthy", Error: "Error: " + err.Error()}) } else { logger.Debug("Route %s is healthy", health.Name) routes = append(routes, HealthCheckRouteResponse{Name: health.Name, Status: "healthy", Error: ""}) } + defer wg.Done() }() diff --git a/internal/healthCheck.go b/internal/healthCheck.go index 012c518..406ad50 100644 --- a/internal/healthCheck.go +++ b/internal/healthCheck.go @@ -16,6 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ import ( + "crypto/tls" "fmt" "github.com/jkaninda/goma-gateway/pkg/logger" "github.com/jkaninda/goma-gateway/util" @@ -36,8 +37,14 @@ func (health Health) Check() error { if err != nil { return fmt.Errorf("error route %s: creating HealthCheck request: %v ", health.Name, err) } + // Create custom transport with TLS configuration + transport := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: health.InsecureSkipVerify, // Skip SSL certificate verification + }, + } // Perform the request to the route's healthcheck - client := &http.Client{Timeout: health.TimeOut} + client := &http.Client{Transport: transport, Timeout: health.TimeOut} healthResp, err := client.Do(healthReq) if err != nil { logger.Debug("Error route %s: performing HealthCheck request: %v ", health.Name, err) @@ -46,6 +53,7 @@ func (health Health) Check() error { defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { + logger.Debug("Error performing HealthCheck request: %v ", err) } }(healthResp.Body) if len(health.HealthyStatuses) > 0 { diff --git a/internal/helpers.go b/internal/helpers.go index 7c47ecb..1b02d34 100644 --- a/internal/helpers.go +++ b/internal/helpers.go @@ -118,20 +118,22 @@ func healthCheckRoutes(routes []Route) []Health { if len(route.Backends) > 0 { for index, backend := range route.Backends { health := Health{ - Name: fmt.Sprintf("%s - [%d]", route.Name, index), - URL: backend + route.HealthCheck.Path, - TimeOut: timeout, - HealthyStatuses: route.HealthCheck.HealthyStatuses, + Name: fmt.Sprintf("%s - [%d]", route.Name, index), + URL: backend + route.HealthCheck.Path, + TimeOut: timeout, + HealthyStatuses: route.HealthCheck.HealthyStatuses, + InsecureSkipVerify: route.InsecureSkipVerify, } healthRoutes = append(healthRoutes, health) } } else { health := Health{ - Name: route.Name, - URL: route.Destination + route.HealthCheck.Path, - TimeOut: timeout, - HealthyStatuses: route.HealthCheck.HealthyStatuses, + Name: route.Name, + URL: route.Destination + route.HealthCheck.Path, + TimeOut: timeout, + HealthyStatuses: route.HealthCheck.HealthyStatuses, + InsecureSkipVerify: route.InsecureSkipVerify, } healthRoutes = append(healthRoutes, health) } diff --git a/internal/middleware.go b/internal/middleware.go index 3ee792a..aa7b146 100644 --- a/internal/middleware.go +++ b/internal/middleware.go @@ -19,11 +19,7 @@ func getMiddleware(rules []string, middlewares []Middleware) (Middleware, error) func doesExist(tyName string) bool { middlewareList := []string{BasicAuth, JWTAuth, AccessMiddleware} - if slices.Contains(middlewareList, tyName) { - return true - - } - return false + return slices.Contains(middlewareList, tyName) } func GetMiddleware(rule string, middlewares []Middleware) (Middleware, error) { for _, m := range middlewares { diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index c2e6461..985bb95 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -79,7 +79,7 @@ func (jwtAuth JwtAuth) AuthMiddleware(next http.Handler) http.Handler { defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { - + logger.Error("Error closing body: %v", err) } }(authResp.Body) // Inject specific header tp the current request's header diff --git a/internal/middleware/types.go b/internal/middleware/types.go index ad3d613..27d1cda 100644 --- a/internal/middleware/types.go +++ b/internal/middleware/types.go @@ -26,13 +26,13 @@ import ( // RateLimiter defines requests limit properties. type RateLimiter struct { - requests int - id string - window time.Duration - clientMap map[string]*Client - mu sync.Mutex - origins []string - hosts []string + requests int + id string + window time.Duration + clientMap map[string]*Client + mu sync.Mutex + origins []string + //hosts []string redisBased bool } diff --git a/internal/middleware_type.go b/internal/middleware_type.go new file mode 100644 index 0000000..acd33a3 --- /dev/null +++ b/internal/middleware_type.go @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Jonas Kaninda + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package pkg + +// Middleware defined the route middleware +type Middleware struct { + //Path contains the name of middleware and must be unique + Name string `yaml:"name"` + // Type contains authentication types + // + // basic, jwt, auth0, rateLimit, access + Type string `yaml:"type"` // Middleware type [basic, jwt, auth0, rateLimit, access] + Paths []string `yaml:"paths"` // Protected paths + // Rule contains rule type of + Rule interface{} `yaml:"rule"` // Middleware rule +} diff --git a/internal/route.go b/internal/route.go index 3c3655b..dd9c077 100644 --- a/internal/route.go +++ b/internal/route.go @@ -236,10 +236,15 @@ func (gatewayServer GatewayServer) Initialize() *mux.Router { logger.Info("Block common exploits enabled") router.Use(middleware.BlockExploitsMiddleware) } + id := string(rune(rIndex)) + if len(route.Name) != 0 { + // Use route name as ID + id = util.Slug(route.Name) + } // Apply route rate limit if route.RateLimit > 0 { rateLimit := middleware.RateLimit{ - Id: string(rune(rIndex)), // Use route index as ID + Id: id, // Use route index as ID Requests: route.RateLimit, Window: time.Minute, // requests per minute Origins: route.Cors.Origins, diff --git a/internal/route_type.go b/internal/route_type.go new file mode 100644 index 0000000..11bd21e --- /dev/null +++ b/internal/route_type.go @@ -0,0 +1,58 @@ +/* + * Copyright 2024 Jonas Kaninda + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package pkg + +// Route defines gateway route +type Route struct { + // Path defines route path + Path string `yaml:"path"` + // Name defines route name + Name string `yaml:"name"` + //Host Domain/host based request routing + //Host string `yaml:"host"` + //Hosts Domains/hosts based request routing + Hosts []string `yaml:"hosts"` + // Rewrite rewrites route path to desired path + // + // E.g. /cart to / => It will rewrite /cart path to / + Rewrite string `yaml:"rewrite"` + // + // Methods allowed method + Methods []string `yaml:"methods"` + // Destination Defines backend URL + Destination string `yaml:"destination"` + Backends []string `yaml:"backends"` + InsecureSkipVerify bool `yaml:"insecureSkipVerify"` + // HealthCheck Defines the backend is health + HealthCheck RouteHealthCheck `yaml:"healthCheck"` + // Cors contains the route cors headers + Cors Cors `yaml:"cors"` + RateLimit int `yaml:"rateLimit"` + // DisableHostFording Disable X-forwarded header. + // + // [X-Forwarded-Host, X-Forwarded-For, Host, Scheme ] + // + // It will not match the backend route + DisableHostFording bool `yaml:"disableHostFording"` + // InterceptErrors holds the status codes to intercept the error from backend + InterceptErrors []int `yaml:"interceptErrors"` + // BlockCommonExploits enable, disable block common exploits + BlockCommonExploits bool `yaml:"blockCommonExploits"` + // Middlewares Defines route middleware from Middleware names + Middlewares []string `yaml:"middlewares"` +} diff --git a/internal/server_test.go b/internal/server_test.go index d91e8fd..da298e9 100644 --- a/internal/server_test.go +++ b/internal/server_test.go @@ -24,11 +24,11 @@ func TestCheckConfig(t *testing.T) { TestInit(t) err := initConfig(configFile) if err != nil { - t.Fatalf(err.Error()) + t.Fatal("Error init config:", err) } err = CheckConfig(configFile) if err != nil { - t.Fatalf(err.Error()) + t.Fatalf("Error checking config: %s", err.Error()) } log.Println("Goma Gateway configuration file checked successfully") } @@ -37,7 +37,7 @@ func TestStart(t *testing.T) { TestInit(t) err := initConfig(configFile) if err != nil { - t.Fatalf(err.Error()) + t.Fatalf("Error initializing config: %s", err.Error()) } g := GatewayServer{} gatewayServer, err := g.Config(configFile) diff --git a/internal/types.go b/internal/types.go index 91a4df8..e358156 100644 --- a/internal/types.go +++ b/internal/types.go @@ -19,37 +19,14 @@ package pkg import ( "context" - "github.com/gorilla/mux" "time" ) -type Config struct { - file string -} type BasicRuleMiddleware struct { Username string `yaml:"username"` Password string `yaml:"password"` } -type Cors struct { - // Cors Allowed origins, - //e.g: - // - // - http://localhost:80 - // - // - https://example.com - Origins []string `yaml:"origins"` - // - //e.g: - // - //Access-Control-Allow-Origin: '*' - // - // Access-Control-Allow-Methods: 'GET, POST, PUT, DELETE, OPTIONS' - // - // Access-Control-Allow-Cors: 'Content-Type, Authorization' - Headers map[string]string `yaml:"headers"` -} - // JWTRuleMiddleware authentication using HTTP GET method // // JWTRuleMiddleware contains the authentication details @@ -114,101 +91,6 @@ type AccessRuleMiddleware struct { ResponseCode int `yaml:"responseCode"` // HTTP Response code } -// Middleware defined the route middleware -type Middleware struct { - //Path contains the name of middleware and must be unique - Name string `yaml:"name"` - // Type contains authentication types - // - // basic, jwt, auth0, rateLimit, access - Type string `yaml:"type"` // Middleware type [basic, jwt, auth0, rateLimit, access] - Paths []string `yaml:"paths"` // Protected paths - // Rule contains rule type of - Rule interface{} `yaml:"rule"` // Middleware rule -} -type MiddlewareName struct { - name string `yaml:"name"` -} - -// Route defines gateway route -type Route struct { - // Path defines route path - Path string `yaml:"path"` - // Name defines route name - Name string `yaml:"name"` - //Host Domain/host based request routing - //Host string `yaml:"host"` - //Hosts Domains/hosts based request routing - Hosts []string `yaml:"hosts"` - // Rewrite rewrites route path to desired path - // - // E.g. /cart to / => It will rewrite /cart path to / - Rewrite string `yaml:"rewrite"` - // - // Methods allowed method - Methods []string `yaml:"methods"` - // Destination Defines backend URL - Destination string `yaml:"destination"` - Backends []string `yaml:"backends"` - InsecureSkipVerify bool `yaml:"insecureSkipVerify"` - // HealthCheck Defines the backend is health - HealthCheck RouteHealthCheck `yaml:"healthCheck"` - // Cors contains the route cors headers - Cors Cors `yaml:"cors"` - RateLimit int `yaml:"rateLimit"` - // DisableHostFording Disable X-forwarded header. - // - // [X-Forwarded-Host, X-Forwarded-For, Host, Scheme ] - // - // It will not match the backend route - DisableHostFording bool `yaml:"disableHostFording"` - // InterceptErrors holds the status codes to intercept the error from backend - InterceptErrors []int `yaml:"interceptErrors"` - // BlockCommonExploits enable, disable block common exploits - BlockCommonExploits bool `yaml:"blockCommonExploits"` - // Middlewares Defines route middleware from Middleware names - Middlewares []string `yaml:"middlewares"` -} - -// Gateway contains Goma Proxy Gateway's configs -type Gateway struct { - // SSLCertFile SSL Certificate file - SSLCertFile string `yaml:"sslCertFile" env:"GOMA_SSL_CERT_FILE, overwrite"` - // SSLKeyFile SSL Private key file - SSLKeyFile string `yaml:"sslKeyFile" env:"GOMA_SSL_KEY_FILE, overwrite"` - // Redis contains redis database details - Redis Redis `yaml:"redis"` - // WriteTimeout defines proxy write timeout - WriteTimeout int `yaml:"writeTimeout" env:"GOMA_WRITE_TIMEOUT, overwrite"` - // ReadTimeout defines proxy read timeout - ReadTimeout int `yaml:"readTimeout" env:"GOMA_READ_TIMEOUT, overwrite"` - // IdleTimeout defines proxy idle timeout - IdleTimeout int `yaml:"idleTimeout" env:"GOMA_IDLE_TIMEOUT, overwrite"` - // RateLimit Defines the number of request peer minutes - RateLimit int `yaml:"rateLimit" env:"GOMA_RATE_LIMIT, overwrite"` - // BlockCommonExploits enable, disable block common exploits - BlockCommonExploits bool `yaml:"blockCommonExploits"` - AccessLog string `yaml:"accessLog" env:"GOMA_ACCESS_LOG, overwrite"` - ErrorLog string `yaml:"errorLog" env:"GOMA_ERROR_LOG=, overwrite"` - LogLevel string `yaml:"logLevel" env:"GOMA_LOG_LEVEL, overwrite"` - // DisableHealthCheckStatus enable and disable routes health check - DisableHealthCheckStatus bool `yaml:"disableHealthCheckStatus"` - // DisableRouteHealthCheckError allows enabling and disabling backend healthcheck errors - DisableRouteHealthCheckError bool `yaml:"disableRouteHealthCheckError"` - //Disable allows enabling and disabling displaying routes on start - DisableDisplayRouteOnStart bool `yaml:"disableDisplayRouteOnStart"` - // DisableKeepAlive allows enabling and disabling KeepALive server - DisableKeepAlive bool `yaml:"disableKeepAlive"` - EnableMetrics bool `yaml:"enableMetrics"` - // InterceptErrors holds the status codes to intercept the error from backend - InterceptErrors []int `yaml:"interceptErrors"` - // Cors holds proxy global cors - Cors Cors `yaml:"cors"` - - // Routes holds proxy routes - Routes []Route `yaml:"routes"` -} - type RouteHealthCheck struct { Path string `yaml:"path"` Interval string `yaml:"interval"` @@ -236,24 +118,16 @@ type GatewayServer struct { middlewares []Middleware } type ProxyRoute struct { - path string - rewrite string - destination string - backends []string - healthCheck RouteHealthCheck + path string + rewrite string + destination string + backends []string + //healthCheck RouteHealthCheck methods []string cors Cors disableHostFording bool insecureSkipVerify bool } -type RoutePath struct { - route Route - path string - rules []string - middlewares []Middleware - router *mux.Router -} - type HealthCheckRoute struct { DisableRouteHealthCheckError bool Routes []Route @@ -282,11 +156,12 @@ type JWTSecret struct { // Health represents the health check content for a route type Health struct { - Name string - URL string - TimeOut time.Duration - Interval string - HealthyStatuses []int + Name string + URL string + TimeOut time.Duration + Interval string + HealthyStatuses []int + InsecureSkipVerify bool } type Redis struct { // Addr redis hostname and port number : diff --git a/internal/var.go b/internal/var.go index b57bb0d..b4ded35 100644 --- a/internal/var.go +++ b/internal/var.go @@ -3,16 +3,11 @@ package pkg const ConfigDir = "/etc/goma/" // Default configuration file const ConfigFile = "/etc/goma/goma.yml" // Default configuration file const accessControlAllowOrigin = "Access-Control-Allow-Origin" // Cors -const serverName = "Goma" const gatewayName = "Goma Gateway" const AccessMiddleware = "access" // access middleware const BasicAuth = "basic" // basic authentication middleware const JWTAuth = "jwt" // JWT authentication middleware const OAuth = "oauth" // OAuth authentication middleware -const applicationJson = "application/json" -const textPlain = "text/plain" -const applicationXml = "application/xml" - // Round-robin counter var counter uint32 diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index b9e18b8..3ca6d3b 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -26,11 +26,6 @@ import ( "github.com/jkaninda/goma-gateway/util" ) -type Logger struct { - msg string - args interface{} -} - // Info returns info log func Info(msg string, args ...interface{}) { log.SetOutput(getStd(util.GetStringEnv("GOMA_ACCESS_LOG", "/dev/stdout"))) diff --git a/util/helpers.go b/util/helpers.go index c896cc5..f3aaf51 100644 --- a/util/helpers.go +++ b/util/helpers.go @@ -142,3 +142,17 @@ func ParseDuration(durationStr string) (time.Duration, error) { } return duration, nil } + +func Slug(text string) string { + // Convert to lowercase + text = strings.ToLower(text) + + // Replace spaces and special characters with hyphens + re := regexp.MustCompile(`[^\w]+`) + text = re.ReplaceAllString(text, "-") + + // Remove leading and trailing hyphens + text = strings.Trim(text, "-") + + return text +}