diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go index fe33bc81e..f50590f6c 100644 --- a/cmd/cgr-loader/cgr-loader.go +++ b/cmd/cgr-loader/cgr-loader.go @@ -23,6 +23,7 @@ import ( "github.com/cgrates/cgrates/timespans" "log" "path" + "regexp" ) var ( @@ -44,8 +45,32 @@ var ( sep rune ) +type validator struct { + fn string + re *regexp.Regexp + message string +} + func main() { flag.Parse() + dataFilesValidators := []*validator{ + &validator{destinationsFn, regexp.MustCompile(`(?:\w+\s*,\s*){1}(?:\d+.?\d*){1}$`), "Tag[0-9A-Za-z_),Prefix[0-9]"}, + &validator{ratesFn, regexp.MustCompile(`(?:\w+\s*,\s*){2}(?:\d+.?\d*){4}$`), "Tag[0-9A-Za-z_],DestinationsTag[0-9A-Za-z_],ConnectFee,Price,PricedUnits,RateIncrement"}, + &validator{timingsFn, regexp.MustCompile(`(?:\w+\s*,\s*){1}(?:\*all\s*,\s*|(?:\d{1,4};?)+\s*,\s*|\s*,\s*){4}(?:\d{2}:\d{2}:\d{2}|\*asap){1}$`), "Tag,Years,Months,MonthDays,WeekDays,Time"}, + &validator{ratetimingsFn, regexp.MustCompile(`(?:\w+\s*,\s*){3}(?:\d+.?\d*){1}$`), "Tag,RatesTag,TimingProfile,Weight"}, + &validator{ratingprofilesFn, regexp.MustCompile(`(?:\w+\s*,\s*){1}(?:\d+\s*,\s*){1}(?:OUT\s*,\s*|IN\s*,\s*){1}(?:\*all\s*,\s*|[\w:\.]+\s*,\s*){1}(?:\w*\s*,\s*){1}(?:\w+\s*,\s*){1}(?:\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z){1}$`), "Tenant,TOR,Direction,Subject,RatesFallbackSubject,RatesTimingTag,ActivationTime"}, + &validator{actionsFn, regexp.MustCompile(`(?:\w+\s*,\s*){3}(?:OUT\s*,\s*|IN\s*,\s*){1}(?:\d+\s*,\s*){1}(?:\w+\s*,\s*|\*all\s*,\s*){1}(?:ABSOLUTE\s*,\s*|PERCENT\s*,\s*|\s*,\s*){1}(?:\d*\.?\d*\s*,?\s*){3}$`), "Tag,Action,BalanceTag,Direction,Units,DestinationTag,PriceType,PriceValue,MinutesWeight,Weight"}, + &validator{actiontimingsFn, regexp.MustCompile(`(?:\w+\s*,\s*){3}(?:\d+\.?\d*){1}`), "Tag,ActionsTag,TimingTag, Weight"}, + &validator{actiontriggersFn, regexp.MustCompile(`(?:\w+\s*,\s*){2}(?:OUT\s*,\s*|IN\s*,\s*){1}(?:\d+\.?\d*\s*,\s*){1}(?:\w+\s*,\s*|\*all\s*,\s*){1}(?:\w+\s*,\s*){1}(?:\d+\.?\d*){1}$`), "Tag,BalanceTag,ThresholdValue,Direction,DestinationTag,ActionsTag,Weight"}, + &validator{accountactionsFn, regexp.MustCompile(`(?:OUT\s*,\s*|IN\s*,\s*){1}`), "Tenant,Account,Direction,ActionTimingsTag,ActionTriggersTag"}, + } + for _, v := range dataFilesValidators { + err := timespans.ValidateCSVData(v.fn, v.re) + if err != nil { + log.Fatal(err, "\n\t", v.message) + } + } + sep = []rune(*separator)[0] csvr := timespans.NewFileCSVReader() err := csvr.LoadDestinations(path.Join(*dataPath, destinationsFn), sep) diff --git a/timespans/csvreader_helpers.go b/timespans/csvreader_helpers.go index 27b6aede7..6b30ffe6d 100644 --- a/timespans/csvreader_helpers.go +++ b/timespans/csvreader_helpers.go @@ -19,7 +19,12 @@ along with this program. If not, see package timespans import ( + "bufio" + "errors" + "fmt" "log" + "os" + "regexp" "strconv" ) @@ -124,14 +129,29 @@ func (cds CallDescriptors) getKey(key string) *CallDescriptor { return nil } -/*func (cds CallDescriptors) setIntervalEndTime() { - for _, cd := range cds { - for _, ap := range cd.ActivationPeriods { - for x, i := range ap.Intervals { - if x < len(ap.Intervals)-1 { - i.EndTime = ap.Intervals[x+1].StartTime - } +func ValidateCSVData(fn string, re *regexp.Regexp) (err error) { + fin, err := os.Open(fn) + if err != nil { + return + } + defer fin.Close() + r := bufio.NewReader(fin) + line_number := 1 + for { + line, truncated, err := r.ReadLine() + if err != nil { + break + } + if truncated { + return errors.New("line too long") + } + // skip the header line + if line_number > 1 { + if !re.Match(line) { + return errors.New(fmt.Sprintf("%s: error on line %d: %s", fn, line_number, line)) } } + line_number++ } -}*/ + return +}