/* Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments Copyright (C) ITsysCOM GmbH This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see */ package config import ( "time" "github.com/cgrates/cgrates/utils" ) // ERsCfg the config for ERs type ERsCfg struct { Enabled bool SessionSConns []string Readers []*EventReaderCfg PartialCacheTTL time.Duration } func (erS *ERsCfg) loadFromJSONCfg(jsnCfg *ERsJsonCfg, msgTemplates map[string][]*FCTemplate, sep string, dfltRdrCfg *EventReaderCfg) (err error) { if jsnCfg == nil { return } if jsnCfg.Enabled != nil { erS.Enabled = *jsnCfg.Enabled } if jsnCfg.Sessions_conns != nil { erS.SessionSConns = updateInternalConns(*jsnCfg.Sessions_conns, utils.MetaSessionS) } if jsnCfg.Partial_cache_ttl != nil { if erS.PartialCacheTTL, err = utils.ParseDurationWithNanosecs(*jsnCfg.Partial_cache_ttl); err != nil { return } } return erS.appendERsReaders(jsnCfg.Readers, msgTemplates, sep, dfltRdrCfg) } func (erS *ERsCfg) appendERsReaders(jsnReaders *[]*EventReaderJsonCfg, msgTemplates map[string][]*FCTemplate, sep string, dfltRdrCfg *EventReaderCfg) (err error) { if jsnReaders == nil { return } for _, jsnReader := range *jsnReaders { var rdr *EventReaderCfg if jsnReader.Id != nil { for _, reader := range erS.Readers { if reader.ID == *jsnReader.Id { rdr = reader break } } } if rdr == nil { if dfltRdrCfg != nil { rdr = dfltRdrCfg.Clone() } else { rdr = new(EventReaderCfg) rdr.Opts = make(map[string]interface{}) } erS.Readers = append(erS.Readers, rdr) } if err := rdr.loadFromJSONCfg(jsnReader, msgTemplates, sep); err != nil { return err } } return nil } // Clone returns a deep copy of ERsCfg func (erS *ERsCfg) Clone() (cln *ERsCfg) { cln = &ERsCfg{ Enabled: erS.Enabled, SessionSConns: make([]string, len(erS.SessionSConns)), Readers: make([]*EventReaderCfg, len(erS.Readers)), PartialCacheTTL: erS.PartialCacheTTL, } if erS.SessionSConns != nil { cln.SessionSConns = utils.CloneStringSlice(erS.SessionSConns) } for idx, rdr := range erS.Readers { cln.Readers[idx] = rdr.Clone() } return } // AsMapInterface returns the config as a map[string]interface{} func (erS *ERsCfg) AsMapInterface(separator string) (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.EnabledCfg: erS.Enabled, utils.PartialCacheTTLCfg: "0", } if erS.PartialCacheTTL != 0 { initialMP[utils.PartialCacheTTLCfg] = erS.PartialCacheTTL.String() } if erS.SessionSConns != nil { initialMP[utils.SessionSConnsCfg] = getInternalJSONConns(erS.SessionSConns) } if erS.Readers != nil { readers := make([]map[string]interface{}, len(erS.Readers)) for i, item := range erS.Readers { readers[i] = item.AsMapInterface(separator) } initialMP[utils.ReadersCfg] = readers } return } // EventReaderCfg the event for the Event Reader type EventReaderCfg struct { ID string Type string RunDelay time.Duration ConcurrentReqs int SourcePath string ProcessedPath string Opts map[string]interface{} Tenant RSRParsers Timezone string Filters []string Flags utils.FlagsWithParams Fields []*FCTemplate PartialCommitFields []*FCTemplate CacheDumpFields []*FCTemplate } func (er *EventReaderCfg) loadFromJSONCfg(jsnCfg *EventReaderJsonCfg, msgTemplates map[string][]*FCTemplate, sep string) (err error) { if jsnCfg == nil { return } if jsnCfg.Id != nil { er.ID = *jsnCfg.Id } if jsnCfg.Type != nil { er.Type = *jsnCfg.Type } if jsnCfg.Run_delay != nil { if er.RunDelay, err = utils.ParseDurationWithNanosecs(*jsnCfg.Run_delay); err != nil { return } } if jsnCfg.Concurrent_requests != nil { er.ConcurrentReqs = *jsnCfg.Concurrent_requests } if jsnCfg.Source_path != nil { er.SourcePath = *jsnCfg.Source_path } if jsnCfg.Processed_path != nil { er.ProcessedPath = *jsnCfg.Processed_path } if jsnCfg.Tenant != nil { if er.Tenant, err = NewRSRParsers(*jsnCfg.Tenant, sep); err != nil { return err } } if jsnCfg.Timezone != nil { er.Timezone = *jsnCfg.Timezone } if jsnCfg.Filters != nil { er.Filters = utils.CloneStringSlice(*jsnCfg.Filters) } if jsnCfg.Flags != nil { er.Flags = utils.FlagsWithParamsFromSlice(*jsnCfg.Flags) } if jsnCfg.Fields != nil { if er.Fields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Fields, sep); err != nil { return err } if tpls, err := InflateTemplates(er.Fields, msgTemplates); err != nil { return err } else if tpls != nil { er.Fields = tpls } } if jsnCfg.Cache_dump_fields != nil { if er.CacheDumpFields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Cache_dump_fields, sep); err != nil { return err } if tpls, err := InflateTemplates(er.CacheDumpFields, msgTemplates); err != nil { return err } else if tpls != nil { er.CacheDumpFields = tpls } } if jsnCfg.Partial_commit_fields != nil { if er.PartialCommitFields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Partial_commit_fields, sep); err != nil { return err } if tpls, err := InflateTemplates(er.PartialCommitFields, msgTemplates); err != nil { return err } else if tpls != nil { er.PartialCommitFields = tpls } } if jsnCfg.Opts != nil { for k, v := range jsnCfg.Opts { er.Opts[k] = v } } return } // Clone returns a deep copy of EventReaderCfg func (er EventReaderCfg) Clone() (cln *EventReaderCfg) { cln = &EventReaderCfg{ ID: er.ID, Type: er.Type, RunDelay: er.RunDelay, ConcurrentReqs: er.ConcurrentReqs, SourcePath: er.SourcePath, ProcessedPath: er.ProcessedPath, Tenant: er.Tenant.Clone(), Timezone: er.Timezone, Flags: er.Flags.Clone(), Opts: make(map[string]interface{}), } if er.Filters != nil { cln.Filters = utils.CloneStringSlice(er.Filters) } if er.Fields != nil { cln.Fields = make([]*FCTemplate, len(er.Fields)) for idx, fld := range er.Fields { cln.Fields[idx] = fld.Clone() } } if er.CacheDumpFields != nil { cln.CacheDumpFields = make([]*FCTemplate, len(er.CacheDumpFields)) for idx, fld := range er.CacheDumpFields { cln.CacheDumpFields[idx] = fld.Clone() } } if er.PartialCommitFields != nil { cln.PartialCommitFields = make([]*FCTemplate, len(er.PartialCommitFields)) for idx, fld := range er.PartialCommitFields { cln.PartialCommitFields[idx] = fld.Clone() } } for k, v := range er.Opts { cln.Opts[k] = v } return } // AsMapInterface returns the config as a map[string]interface{} func (er *EventReaderCfg) AsMapInterface(separator string) (initialMP map[string]interface{}) { initialMP = map[string]interface{}{ utils.IDCfg: er.ID, utils.TypeCfg: er.Type, utils.ConcurrentRequestsCfg: er.ConcurrentReqs, utils.SourcePathCfg: er.SourcePath, utils.ProcessedPathCfg: er.ProcessedPath, utils.TenantCfg: er.Tenant.GetRule(separator), utils.TimezoneCfg: er.Timezone, utils.FiltersCfg: er.Filters, utils.FlagsCfg: []string{}, utils.RunDelayCfg: "0", } opts := make(map[string]interface{}) for k, v := range er.Opts { opts[k] = v } initialMP[utils.OptsCfg] = opts if flags := er.Flags.SliceFlags(); flags != nil { initialMP[utils.FlagsCfg] = flags } if er.Fields != nil { fields := make([]map[string]interface{}, len(er.Fields)) for i, item := range er.Fields { fields[i] = item.AsMapInterface(separator) } initialMP[utils.FieldsCfg] = fields } if er.CacheDumpFields != nil { cacheDumpFields := make([]map[string]interface{}, len(er.CacheDumpFields)) for i, item := range er.CacheDumpFields { cacheDumpFields[i] = item.AsMapInterface(separator) } initialMP[utils.CacheDumpFieldsCfg] = cacheDumpFields } if er.PartialCommitFields != nil { parCFields := make([]map[string]interface{}, len(er.PartialCommitFields)) for i, item := range er.PartialCommitFields { parCFields[i] = item.AsMapInterface(separator) } initialMP[utils.PartialCommitFieldsCfg] = parCFields } if er.RunDelay > 0 { initialMP[utils.RunDelayCfg] = er.RunDelay.String() } else if er.RunDelay < 0 { initialMP[utils.RunDelayCfg] = "-1" } return } // EventReaderSJsonCfg is the configuration of a single EventReader type EventReaderJsonCfg struct { Id *string Type *string Run_delay *string Concurrent_requests *int Source_path *string Processed_path *string Opts map[string]interface{} Tenant *string Timezone *string Filters *[]string Flags *[]string Fields *[]*FcTemplateJsonCfg Partial_commit_fields *[]*FcTemplateJsonCfg Cache_dump_fields *[]*FcTemplateJsonCfg } func diffEventReaderJsonCfg(d *EventReaderJsonCfg, v1, v2 *EventReaderCfg, separator string) *EventReaderJsonCfg { if d == nil { d = new(EventReaderJsonCfg) } if v1.ID != v2.ID { d.Id = utils.StringPointer(v2.ID) } if v1.Type != v2.Type { d.Type = utils.StringPointer(v2.Type) } if v1.RunDelay != v2.RunDelay { d.Run_delay = utils.StringPointer(v2.RunDelay.String()) } if v1.ConcurrentReqs != v2.ConcurrentReqs { d.Concurrent_requests = utils.IntPointer(v2.ConcurrentReqs) } if v1.SourcePath != v2.SourcePath { d.Source_path = utils.StringPointer(v2.SourcePath) } if v1.ProcessedPath != v2.ProcessedPath { d.Processed_path = utils.StringPointer(v2.ProcessedPath) } d.Opts = diffMap(d.Opts, v1.Opts, v2.Opts) tnt1 := v1.Tenant.GetRule(separator) tnt2 := v2.Tenant.GetRule(separator) if tnt1 != tnt2 { d.Tenant = utils.StringPointer(tnt2) } if v1.Timezone != v2.Timezone { d.Timezone = utils.StringPointer(v2.Timezone) } if !utils.SliceStringEqual(v1.Filters, v2.Filters) { d.Filters = &v2.Filters } flgs1 := v1.Flags.SliceFlags() flgs2 := v2.Flags.SliceFlags() if !utils.SliceStringEqual(flgs1, flgs2) { d.Flags = &flgs2 } var flds []*FcTemplateJsonCfg if d.Fields != nil { flds = *d.Fields } flds = diffFcTemplateJsonCfg(flds, v1.Fields, v2.Fields, separator) if flds != nil { d.Fields = &flds } var pcf []*FcTemplateJsonCfg if d.Partial_commit_fields != nil { pcf = *d.Partial_commit_fields } pcf = diffFcTemplateJsonCfg(pcf, v1.PartialCommitFields, v2.PartialCommitFields, separator) if pcf != nil { d.Partial_commit_fields = &pcf } var cdf []*FcTemplateJsonCfg if d.Cache_dump_fields != nil { cdf = *d.Cache_dump_fields } cdf = diffFcTemplateJsonCfg(cdf, v1.CacheDumpFields, v2.CacheDumpFields, separator) if cdf != nil { d.Cache_dump_fields = &cdf } return d } func getEventReaderJsonCfg(d []*EventReaderJsonCfg, id string) (*EventReaderJsonCfg, int) { for i, v := range d { if v.Id != nil && *v.Id == id { return v, i } } return nil, -1 } func getEventReaderCfg(d []*EventReaderCfg, id string) *EventReaderCfg { for _, v := range d { if v.ID == id { return v } } return new(EventReaderCfg) } func diffEventReadersJsonCfg(d *[]*EventReaderJsonCfg, v1, v2 []*EventReaderCfg, separator string) *[]*EventReaderJsonCfg { if d == nil || *d == nil { d = &[]*EventReaderJsonCfg{} } for _, val := range v2 { dv, i := getEventReaderJsonCfg(*d, val.ID) dv = diffEventReaderJsonCfg(dv, getEventReaderCfg(v1, val.ID), val, separator) if i == -1 { *d = append(*d, dv) } else { (*d)[i] = dv } } return d } // EventReaderSJsonCfg contains the configuration of EventReaderService type ERsJsonCfg struct { Enabled *bool Sessions_conns *[]string Readers *[]*EventReaderJsonCfg Partial_cache_ttl *string } func diffERsJsonCfg(d *ERsJsonCfg, v1, v2 *ERsCfg, separator string) *ERsJsonCfg { if d == nil { d = new(ERsJsonCfg) } if v1.Enabled != v2.Enabled { d.Enabled = utils.BoolPointer(v2.Enabled) } if !utils.SliceStringEqual(v1.SessionSConns, v2.SessionSConns) { d.Sessions_conns = utils.SliceStringPointer(getInternalJSONConns(v2.SessionSConns)) } if v1.PartialCacheTTL != v2.PartialCacheTTL { d.Partial_cache_ttl = utils.StringPointer(v2.PartialCacheTTL.String()) } d.Readers = diffEventReadersJsonCfg(d.Readers, v1.Readers, v2.Readers, separator) return d }