package main import ( "fmt" "os" "strconv" "strings" "time" "github.com/rs/zerolog/log" "gopkg.in/yaml.v2" ) type config struct { Jobs []jobconfig `yaml:"jobs"` } type jobconfig struct { Name string `yaml:"name"` Hour string `yaml:"hour"` Minute string `yaml:"minute"` Command string `yaml:"command"` } func ReadFromFile(path string) (config, error) { f, err := os.ReadFile(path) if err != nil { return config{}, fmt.Errorf(ErrWrapTemplate, ErrCantReadConfigFile, err) } c := config{} err = yaml.Unmarshal(f, &c) if err != nil { return config{}, fmt.Errorf(ErrWrapTemplate, ErrCantParseConfigFile, err) } return c, nil } func (jc jobconfig) MatchCurrentTime(t time.Time) (bool, error) { matchHour, err := matchTime(jc.Hour, t.Hour()) if err != nil { return false, err } if !matchHour { return false, nil } matchMinute, err := matchTime(jc.Minute, t.Minute()) if err != nil { return false, err } if !matchMinute { return false, nil } return true, nil } func matchTime(pattern string, currentValue int) (bool, error) { pattern = strings.TrimSpace(pattern) log.Debug().Str("pattern", pattern).Int("currentValue", currentValue).Msg("Check if Pattern match current Value") // All numbers if pattern == "*" { return true, nil } // Multible arguments details := strings.Split(pattern, ",") if len(details) > 1 { for i := range details { res, err := matchTime(details[i], currentValue) if err != nil { return false, fmt.Errorf(ErrWrapTemplate, ErrCantParseTimePattern, err) } if res { return res, nil } } return false, nil // Non of the part match so nothing will match } // Singel number valueAsInt, err := strconv.Atoi(pattern) if err == nil { if valueAsInt == currentValue { return true, nil } return false, nil } // Normal ranges no ranges with defision if strings.Contains(pattern, "-") && !strings.Contains(pattern, "/") { smallNumber, largeNumber, err := getNumbersOfRange(pattern) if err != nil { return false, err } if smallNumber < currentValue && largeNumber > currentValue { return true, nil } return false, nil } if strings.Contains(pattern, "/") { numbers := strings.Split(pattern, "/") if len(numbers) != 2 { return false, fmt.Errorf(ErrWrapTemplate, ErrCantParseTimePattern, "pattern dont include 2 numbers") } numberDivisor, err := strconv.Atoi(numbers[1]) if err != nil { return false, fmt.Errorf(ErrWrapTemplate, ErrCantParseTimePattern, err) } if numbers[0] == "*" { res := currentValue % numberDivisor if res == 0 { return true, nil } return false, nil } if strings.Contains(numbers[0], "-") { smallNumber, largeNumber, err := getNumbersOfRange(numbers[0]) if err != nil { return false, err } if !(smallNumber < currentValue && largeNumber > currentValue) { return false, nil } newValue := currentValue - smallNumber res := newValue % numberDivisor if res == 0 { return true, nil } return false, nil } } // Cant Parse the time return false, ErrCantParseTimePattern } func getNumbersOfRange(pattern string) (int, int, error) { numbers := strings.Split(pattern, "-") if len(numbers) != 2 { return 0, 0, fmt.Errorf(ErrWrapTemplate, ErrCantParseTimePattern, "range include more than 2 parameter") } smallNumber, err := strconv.Atoi(strings.TrimSpace(numbers[0])) if err != nil { return 0, 0, fmt.Errorf(ErrWrapTemplate, ErrCantParseTimePattern, err) } largeNumber, err := strconv.Atoi(strings.TrimSpace(numbers[1])) if err != nil { return 0, 0, fmt.Errorf(ErrWrapTemplate, ErrCantParseTimePattern, err) } if smallNumber >= largeNumber { return 0, 0, fmt.Errorf(ErrWrapTemplate, ErrCantParseTimePattern, "smaler number should be first") } return smallNumber, largeNumber, nil }