package config import ( "regexp" "strings" "github.com/zeevdiukman/go-config" ) const VIPER_NAME string = "config" const VIPER_TYPE string = "yaml" const VIPER_PATH string = "./assets/config/." const SERVICES_KEY string = "http.services" const ROUTERS_KEY string = "http.routers" const ENTRYPOINTS_KEY string = "entrypoints" const TLS_KEY string = "tls.certproviders" type Config struct { HTTP *HTTP TLS *TLS EntryPoints EntryPoints } type HTTP struct { Routers Routers Services Services } type TLS struct { CertProviders CertProviders } type CertProviders map[string]*CertProvider type CertProvider struct { Key string Cert string } type Services map[string]*Service type Service struct { URL string } type EntryPoints map[string]*EntryPoint type EntryPoint struct { Address string TLS *EntryPointTLS } type EntryPointTLS struct { Enabled bool } type Routers map[string]*Router type Router struct { EntryPoint string Service string Rules *Rules TLS *RouterTLS } type RouterTLS struct { CertProvider string } type Rules struct { Raw string Map map[string]*Rule } type Rule struct { Name string Value string } func NewConfig() *Config { c := config.NewConfig(VIPER_NAME, VIPER_TYPE, VIPER_PATH) c.Load() appConfig := &Config{ HTTP: &HTTP{ Routers: Routers{}, Services: Services{}, }, TLS: &TLS{ CertProviders: CertProviders{}, }, EntryPoints: EntryPoints{}, } appConfig.InitRouters(c) appConfig.InitServices(c) appConfig.InitEntryPoints(c) appConfig.InitTLS(c) return appConfig } func (r Routers) ForEach(fn func(routerName string, routerConfig *Router)) { for k, v := range r { fn(k, v) } } func (ep EntryPoints) ForEach(fn func(entryPointName string, entryPointConfig *EntryPoint)) { forEach(ep, fn) } func (s Services) ForEach(fn func(serviceName string, serviceConfig *Service)) { forEach(s, fn) } func (c *Config) InitRouters(vConfig *config.Config) { c.HTTP.Routers = make(Routers) for k, v := range vConfig.Sub(ROUTERS_KEY).AllSettings() { val := v.(map[string]any) var tls string = "" var services string = "" var rawRules string = "" var entryPoint string = "" if value, ok := val["service"]; ok { services = value.(string) } if value, ok := val["rules"]; ok { rawRules = value.(string) } if value, ok := val["entrypoint"]; ok { entryPoint = value.(string) } if value, ok := val["tls"]; ok { tls = value.(map[string]any)["certprovider"].(string) } rls := &Rules{ Raw: rawRules, Map: make(map[string]*Rule), } r := &Router{ Service: services, Rules: rls, EntryPoint: entryPoint, TLS: &RouterTLS{CertProvider: tls}, } r.ForRuleFunc("Domain", func(domain string) { r.Rules.Map["Domain"] = &Rule{ Name: "Domain", Value: domain, } }) r.ForRuleFunc("Path", func(path string) { r.Rules.Map["Path"] = &Rule{ Name: "Path", Value: path, } }) c.HTTP.Routers[k] = r } } func (c *Config) InitServices(vConfig *config.Config) { c.HTTP.Services = make(map[string]*Service) for k, v := range vConfig.Sub(SERVICES_KEY).AllSettings() { c.HTTP.Services[k] = &Service{ URL: v.(string), } } } func (c *Config) InitEntryPoints(vConfig *config.Config) { c.EntryPoints = make(EntryPoints) for k, v := range vConfig.Sub(ENTRYPOINTS_KEY).AllSettings() { v := v.(map[string]any) address := "" enabled := false if v, ok := v["tls"]; ok { if v, ok := v.(map[string]any)["enabled"]; ok { enabled = v.(bool) } } if value, ok := v["address"]; ok { address = value.(string) } c.EntryPoints[k] = &EntryPoint{ Address: address, TLS: &EntryPointTLS{ Enabled: enabled, }, } } } func (c *Config) InitTLS(vConfig *config.Config) { c.TLS.CertProviders = make(map[string]*CertProvider) for k, v := range vConfig.Sub(TLS_KEY).AllSettings() { cert := v.(map[string]any)["cert"].(string) key := v.(map[string]any)["key"].(string) c.TLS.CertProviders[k] = &CertProvider{ Cert: cert, Key: key, } } } func forEach[K comparable, V comparable](mp map[K]V, fn func(key K, value V)) { for k, v := range mp { fn(k, v) } } func (r *Router) ForRuleFunc(ruleName string, fn func(string)) { rules := r.Rules.Raw rulesSlice := splitStatementByRegex(rules, "\\(`(.*?)`\\)") for idx, rule := range rulesSlice { rule, _ = strings.CutPrefix(rule, ".") if rule == ruleName { fn(rulesSlice[idx+1]) } } } func splitStatementByRegex(str string, regx string) []string { input := str re := regexp.MustCompile(regx) matches := re.FindAllStringSubmatch(input, -1) if len(matches) == 0 { return []string{str} // Return original if no backticks found } result := []string{} lastIndex := 0 for _, match := range matches { startIndex := strings.Index(input, match[0]) if startIndex > lastIndex { result = append(result, input[lastIndex:startIndex]) } result = append(result, match[1]) // Append the content within backticks lastIndex = startIndex + len(match[0]) } if lastIndex < len(input) { result = append(result, input[lastIndex:]) } return result }