package main import ( "encoding/json" "fmt" "os" "path/filepath" "strings" "sync" ) type ParsedConf struct { RulesFp string `json:"rulesPath"` LogFp string `json:"logPath"` Compression bool `json:"compress"` SizeToRotate string `json:"sizeToRotate"` Port string `json:"port"` } type Config struct { MappingFilePath string MappingRules ImportRulesMappings sync.Mutex } type ImportRulesMappings struct { Mappings []struct { Protocol string `json:"protocol"` VanityUrl string `json:"vanity_url"` RealUrl string `json:"real_url"` } `json:"mappings"` } type ImportRuleStruct struct { VanityUrl string Proto string RepoUrl string } // isFile - check if fp is a valid file func isFile(fp string) bool { info, err := os.Stat(fp) if os.IsNotExist(err) || !info.Mode().IsRegular() { return false } return true } // load mapping file func (c *Config) LoadMappingFile(fp string) error { var mapping ImportRulesMappings mappingFilePath := fp if len(c.MappingFilePath) == 0 { ok := isFile(mappingFilePath) if !ok { return fmt.Errorf("mappingfile %s is not found", mappingFilePath) } } else { mappingFilePath = c.MappingFilePath } mappingFile, err := os.Open(mappingFilePath) if err != nil { return err } defer mappingFile.Close() err = json.NewDecoder(mappingFile).Decode(&mapping) if err != nil { return err } c.MappingRules = mapping if len(c.MappingFilePath) == 0 { c.MappingFilePath = mappingFilePath } return nil } // generate default locations for all the config files func getDefaults() (map[string]string, error) { m := make(map[string]string) confDir, err := os.UserConfigDir() if err != nil { return m, err } homeDir, err := os.UserHomeDir() if err != nil { return m, err } m["rulesFp"] = filepath.Join(confDir, "gocustomcurls", "rules.json") m["confFp"] = filepath.Join(confDir, "gocustomcurls", "config.json") m["logFp"] = filepath.Join(homeDir, ".gocustomurls", "logs", "app.log") return m, nil } // generate and write to a location, the default values for the config.json file func generateDefaultConfigFile(defaultObj map[string]string) (ParsedConf, error) { var p ParsedConf var err error var defaults map[string]string if len(defaultObj) == 0 { defaults, err = getDefaults() } else { defaults = defaultObj } if err != nil { return p, err } parentDir := filepath.Dir(defaults["confFp"]) err = os.MkdirAll(parentDir, 0755) if err != nil { return p, err } f, err := os.OpenFile(defaults["confFp"], os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) if err != nil { return p, err } defer f.Close() p.RulesFp = defaults["rulesFp"] p.LogFp = defaults["logFp"] p.Port = "7070" p.Compression = true p.SizeToRotate = "5MiB" jsonString, _ := json.Marshal(p) err = os.WriteFile(defaults["confFp"], jsonString, 0666) if err != nil { return p, err } return p, nil } func checkIfSizeIsConfigured(fsize string) (bool, error) { suffixes := []string{"KB", "MB", "GB"} var found string for _, suffix := range suffixes { if strings.HasSuffix(fsize, suffix) { found = suffix } } if len(found) == 0 { return false, fmt.Errorf("%s has the incorrect suffix, Please use one of this suffixes {\"KB\", \"MB\", \"GB\"}", fsize) } return true, nil } // load the main config file func (c *Config) LoadMainConfigFile(fp string) (ParsedConf, error) { var conf ParsedConf var err error c.Lock() defer c.Unlock() ok := isFile(fp) if !ok { // generate config file errorLog.Println("Warning, generating default config file") conf, err = generateDefaultConfigFile(map[string]string{}) if err != nil { return conf, err } c.MappingFilePath = conf.RulesFp return conf, nil } f, err := os.Open(fp) if err != nil { return conf, err } defer f.Close() err = json.NewDecoder(f).Decode(&conf) if err != nil { return conf, err } _, err = checkIfSizeIsConfigured(conf.SizeToRotate) if err != nil { return conf, err } c.MappingFilePath = conf.RulesFp return conf, nil }