diff --git a/config/accountscfg.go b/config/accountscfg.go index 46f927a9b..34bdf7034 100644 --- a/config/accountscfg.go +++ b/config/accountscfg.go @@ -46,55 +46,22 @@ func (acS *AccountSCfg) loadFromJSONCfg(jsnCfg *AccountSJsonCfg) (err error) { acS.IndexedSelects = *jsnCfg.Indexed_selects } if jsnCfg.Attributes_conns != nil { - acS.AttributeSConns = make([]string, len(*jsnCfg.Attributes_conns)) - for idx, conn := range *jsnCfg.Attributes_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - acS.AttributeSConns[idx] = conn - if conn == utils.MetaInternal { - acS.AttributeSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes) - } - } + acS.AttributeSConns = updateInternalConns(*jsnCfg.Attributes_conns, utils.MetaAttributes) } if jsnCfg.Rates_conns != nil { - acS.RateSConns = make([]string, len(*jsnCfg.Rates_conns)) - for idx, conn := range *jsnCfg.Rates_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - acS.RateSConns[idx] = conn - if conn == utils.MetaInternal { - acS.RateSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRateS) - } - } + acS.RateSConns = updateInternalConns(*jsnCfg.Rates_conns, utils.MetaRateS) } if jsnCfg.Thresholds_conns != nil { - acS.ThresholdSConns = make([]string, len(*jsnCfg.Thresholds_conns)) - for idx, conn := range *jsnCfg.Thresholds_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - acS.ThresholdSConns[idx] = conn - if conn == utils.MetaInternal { - acS.ThresholdSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) - } - } + acS.ThresholdSConns = updateInternalConns(*jsnCfg.Thresholds_conns, utils.MetaThresholds) } if jsnCfg.String_indexed_fields != nil { - sif := make([]string, len(*jsnCfg.String_indexed_fields)) - for i, fID := range *jsnCfg.String_indexed_fields { - sif[i] = fID - } - acS.StringIndexedFields = &sif + acS.StringIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*jsnCfg.String_indexed_fields)) } if jsnCfg.Prefix_indexed_fields != nil { - pif := make([]string, len(*jsnCfg.Prefix_indexed_fields)) - for i, fID := range *jsnCfg.Prefix_indexed_fields { - pif[i] = fID - } - acS.PrefixIndexedFields = &pif + acS.PrefixIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*jsnCfg.Prefix_indexed_fields)) } if jsnCfg.Suffix_indexed_fields != nil { - sif := make([]string, len(*jsnCfg.Suffix_indexed_fields)) - for i, fID := range *jsnCfg.Suffix_indexed_fields { - sif[i] = fID - } - acS.SuffixIndexedFields = &sif + acS.SuffixIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*jsnCfg.Suffix_indexed_fields)) } if jsnCfg.Nested_fields != nil { acS.NestedFields = *jsnCfg.Nested_fields @@ -119,55 +86,22 @@ func (acS *AccountSCfg) AsMapInterface() (initialMP map[string]interface{}) { utils.MaxIterations: acS.MaxIterations, } if acS.AttributeSConns != nil { - attributeSConns := make([]string, len(acS.AttributeSConns)) - for i, item := range acS.AttributeSConns { - attributeSConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAttributes) { - attributeSConns[i] = utils.MetaInternal - } - } - initialMP[utils.AttributeSConnsCfg] = attributeSConns + initialMP[utils.AttributeSConnsCfg] = getInternalJSONConns(acS.AttributeSConns) } if acS.RateSConns != nil { - rateSConns := make([]string, len(acS.RateSConns)) - for i, item := range acS.RateSConns { - rateSConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaRateS) { - rateSConns[i] = utils.MetaInternal - } - } - initialMP[utils.RateSConnsCfg] = rateSConns + initialMP[utils.RateSConnsCfg] = getInternalJSONConns(acS.RateSConns) } if acS.ThresholdSConns != nil { - thresholdSConns := make([]string, len(acS.ThresholdSConns)) - for i, item := range acS.ThresholdSConns { - thresholdSConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) { - thresholdSConns[i] = utils.MetaInternal - } - } - initialMP[utils.ThresholdSConnsCfg] = thresholdSConns + initialMP[utils.ThresholdSConnsCfg] = getInternalJSONConns(acS.ThresholdSConns) } if acS.StringIndexedFields != nil { - stringIndexedFields := make([]string, len(*acS.StringIndexedFields)) - for i, item := range *acS.StringIndexedFields { - stringIndexedFields[i] = item - } - initialMP[utils.StringIndexedFieldsCfg] = stringIndexedFields + initialMP[utils.StringIndexedFieldsCfg] = utils.CloneStringSlice(*acS.StringIndexedFields) } if acS.PrefixIndexedFields != nil { - prefixIndexedFields := make([]string, len(*acS.PrefixIndexedFields)) - for i, item := range *acS.PrefixIndexedFields { - prefixIndexedFields[i] = item - } - initialMP[utils.PrefixIndexedFieldsCfg] = prefixIndexedFields + initialMP[utils.PrefixIndexedFieldsCfg] = utils.CloneStringSlice(*acS.PrefixIndexedFields) } if acS.SuffixIndexedFields != nil { - suffixIndexedFields := make([]string, len(*acS.SuffixIndexedFields)) - for i, item := range *acS.SuffixIndexedFields { - suffixIndexedFields[i] = item - } - initialMP[utils.SuffixIndexedFieldsCfg] = suffixIndexedFields + initialMP[utils.SuffixIndexedFieldsCfg] = utils.CloneStringSlice(*acS.SuffixIndexedFields) } if acS.MaxUsage != nil { initialMP[utils.MaxUsage] = acS.MaxUsage.String() @@ -185,43 +119,76 @@ func (acS AccountSCfg) Clone() (cln *AccountSCfg) { MaxUsage: acS.MaxUsage, } if acS.AttributeSConns != nil { - cln.AttributeSConns = make([]string, len(acS.AttributeSConns)) - for i, con := range acS.AttributeSConns { - cln.AttributeSConns[i] = con - } + cln.AttributeSConns = utils.CloneStringSlice(acS.AttributeSConns) } if acS.RateSConns != nil { - cln.RateSConns = make([]string, len(acS.RateSConns)) - for i, con := range acS.RateSConns { - cln.RateSConns[i] = con - } + cln.RateSConns = utils.CloneStringSlice(acS.RateSConns) } if acS.ThresholdSConns != nil { - cln.ThresholdSConns = make([]string, len(acS.ThresholdSConns)) - for i, con := range acS.ThresholdSConns { - cln.ThresholdSConns[i] = con - } + cln.ThresholdSConns = utils.CloneStringSlice(acS.ThresholdSConns) } if acS.StringIndexedFields != nil { - idx := make([]string, len(*acS.StringIndexedFields)) - for i, dx := range *acS.StringIndexedFields { - idx[i] = dx - } - cln.StringIndexedFields = &idx + cln.StringIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*acS.StringIndexedFields)) } if acS.PrefixIndexedFields != nil { - idx := make([]string, len(*acS.PrefixIndexedFields)) - for i, dx := range *acS.PrefixIndexedFields { - idx[i] = dx - } - cln.PrefixIndexedFields = &idx + cln.PrefixIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*acS.PrefixIndexedFields)) } if acS.SuffixIndexedFields != nil { - idx := make([]string, len(*acS.SuffixIndexedFields)) - for i, dx := range *acS.SuffixIndexedFields { - idx[i] = dx - } - cln.SuffixIndexedFields = &idx + cln.SuffixIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*acS.SuffixIndexedFields)) } return } + +// Account service config section +type AccountSJsonCfg struct { + Enabled *bool + Indexed_selects *bool + Attributes_conns *[]string + Rates_conns *[]string + Thresholds_conns *[]string + String_indexed_fields *[]string + Prefix_indexed_fields *[]string + Suffix_indexed_fields *[]string + Nested_fields *bool // applies when indexed fields is not defined + Max_iterations *int + Max_usage *string +} + +func diffAccountSJsonCfg(d *AccountSJsonCfg, v1, v2 *AccountSCfg) *AccountSJsonCfg { + if d == nil { + d = new(AccountSJsonCfg) + } + if v1.Enabled != v2.Enabled { + d.Enabled = utils.BoolPointer(v2.Enabled) + } + if !utils.SliceStringEqual(v1.AttributeSConns, v2.AttributeSConns) { + d.Attributes_conns = utils.SliceStringPointer(getInternalJSONConns(v2.AttributeSConns)) + } + if !utils.SliceStringEqual(v1.RateSConns, v2.RateSConns) { + d.Rates_conns = utils.SliceStringPointer(getInternalJSONConns(v2.RateSConns)) + } + if !utils.SliceStringEqual(v1.ThresholdSConns, v2.ThresholdSConns) { + d.Thresholds_conns = utils.SliceStringPointer(getInternalJSONConns(v2.ThresholdSConns)) + } + if v1.IndexedSelects != v2.IndexedSelects { + d.Indexed_selects = utils.BoolPointer(v2.IndexedSelects) + } + d.String_indexed_fields = diffIndexSlice(d.String_indexed_fields, v1.StringIndexedFields, v2.StringIndexedFields) + d.Prefix_indexed_fields = diffIndexSlice(d.Prefix_indexed_fields, v1.PrefixIndexedFields, v2.PrefixIndexedFields) + d.Suffix_indexed_fields = diffIndexSlice(d.Suffix_indexed_fields, v1.SuffixIndexedFields, v2.SuffixIndexedFields) + if v1.NestedFields != v2.NestedFields { + d.Nested_fields = utils.BoolPointer(v2.NestedFields) + } + if v1.MaxIterations != v2.MaxIterations { + d.Max_iterations = utils.IntPointer(v2.MaxIterations) + } + if v2.MaxUsage != nil { + if v1.MaxUsage == nil || + v1.MaxUsage.Cmp(v2.MaxUsage.Big) != 0 { + d.Max_usage = utils.StringPointer(v2.MaxUsage.String()) + } + } else { + d.Max_usage = nil + } + return d +} diff --git a/config/actionscfg.go b/config/actionscfg.go index 8537bedb6..38d1797d1 100644 --- a/config/actionscfg.go +++ b/config/actionscfg.go @@ -40,89 +40,38 @@ func (acS *ActionSCfg) loadFromJSONCfg(jsnCfg *ActionSJsonCfg) (err error) { if jsnCfg == nil { return } - if jsnCfg.Cdrs_conns != nil { - acS.CDRsConns = make([]string, len(*jsnCfg.Cdrs_conns)) - for idx, connID := range *jsnCfg.Cdrs_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - acS.CDRsConns[idx] = connID - if connID == utils.MetaInternal { - acS.CDRsConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs) - } - } - } - if jsnCfg.Ees_conns != nil { - acS.EEsConns = make([]string, len(*jsnCfg.Ees_conns)) - for idx, connID := range *jsnCfg.Ees_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - acS.EEsConns[idx] = connID - if connID == utils.MetaInternal { - acS.EEsConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs) - } - } - } - if jsnCfg.Thresholds_conns != nil { - acS.ThresholdSConns = make([]string, len(*jsnCfg.Thresholds_conns)) - for idx, connID := range *jsnCfg.Thresholds_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - acS.ThresholdSConns[idx] = connID - if connID == utils.MetaInternal { - acS.ThresholdSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) - } - } - } - if jsnCfg.Stats_conns != nil { - acS.StatSConns = make([]string, len(*jsnCfg.Stats_conns)) - for idx, connID := range *jsnCfg.Stats_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - acS.StatSConns[idx] = connID - if connID == utils.MetaInternal { - acS.StatSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats) - } - } - } - if jsnCfg.Accounts_conns != nil { - acS.AccountSConns = make([]string, len(*jsnCfg.Accounts_conns)) - for idx, connID := range *jsnCfg.Accounts_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - acS.AccountSConns[idx] = connID - if connID == utils.MetaInternal { - acS.AccountSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAccounts) - } - } - } if jsnCfg.Enabled != nil { acS.Enabled = *jsnCfg.Enabled } + if jsnCfg.Cdrs_conns != nil { + acS.CDRsConns = updateInternalConns(*jsnCfg.Cdrs_conns, utils.MetaCDRs) + } + if jsnCfg.Ees_conns != nil { + acS.EEsConns = updateInternalConns(*jsnCfg.Ees_conns, utils.MetaEEs) + } + if jsnCfg.Thresholds_conns != nil { + acS.ThresholdSConns = updateInternalConns(*jsnCfg.Thresholds_conns, utils.MetaThresholds) + } + if jsnCfg.Stats_conns != nil { + acS.StatSConns = updateInternalConns(*jsnCfg.Stats_conns, utils.MetaStats) + } + if jsnCfg.Accounts_conns != nil { + acS.AccountSConns = updateInternalConns(*jsnCfg.Accounts_conns, utils.MetaAccounts) + } if jsnCfg.Tenants != nil { - tnt := make([]string, len(*jsnCfg.Tenants)) - for i, fID := range *jsnCfg.Tenants { - tnt[i] = fID - } - acS.Tenants = &tnt + acS.Tenants = utils.SliceStringPointer(utils.CloneStringSlice(*jsnCfg.Tenants)) } if jsnCfg.Indexed_selects != nil { acS.IndexedSelects = *jsnCfg.Indexed_selects } if jsnCfg.String_indexed_fields != nil { - sif := make([]string, len(*jsnCfg.String_indexed_fields)) - for i, fID := range *jsnCfg.String_indexed_fields { - sif[i] = fID - } - acS.StringIndexedFields = &sif + acS.StringIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*jsnCfg.String_indexed_fields)) } if jsnCfg.Prefix_indexed_fields != nil { - pif := make([]string, len(*jsnCfg.Prefix_indexed_fields)) - for i, fID := range *jsnCfg.Prefix_indexed_fields { - pif[i] = fID - } - acS.PrefixIndexedFields = &pif + acS.PrefixIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*jsnCfg.Prefix_indexed_fields)) } if jsnCfg.Suffix_indexed_fields != nil { - sif := make([]string, len(*jsnCfg.Suffix_indexed_fields)) - for i, fID := range *jsnCfg.Suffix_indexed_fields { - sif[i] = fID - } - acS.SuffixIndexedFields = &sif + acS.SuffixIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*jsnCfg.Suffix_indexed_fields)) } if jsnCfg.Nested_fields != nil { acS.NestedFields = *jsnCfg.Nested_fields @@ -138,82 +87,31 @@ func (acS *ActionSCfg) AsMapInterface() (initialMP map[string]interface{}) { utils.NestedFieldsCfg: acS.NestedFields, } if acS.CDRsConns != nil { - CDRsConns := make([]string, len(acS.CDRsConns)) - for i, item := range acS.CDRsConns { - CDRsConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaCDRs) { - CDRsConns[i] = utils.MetaInternal - } - } - initialMP[utils.CDRsConnsCfg] = CDRsConns + initialMP[utils.CDRsConnsCfg] = getInternalJSONConns(acS.CDRsConns) } if acS.ThresholdSConns != nil { - threshSConns := make([]string, len(acS.ThresholdSConns)) - for i, item := range acS.ThresholdSConns { - threshSConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaThresholds) { - threshSConns[i] = utils.MetaInternal - } - } - initialMP[utils.ThresholdSConnsCfg] = threshSConns + initialMP[utils.ThresholdSConnsCfg] = getInternalJSONConns(acS.ThresholdSConns) } if acS.StatSConns != nil { - statSConns := make([]string, len(acS.StatSConns)) - for i, item := range acS.StatSConns { - statSConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStats) { - statSConns[i] = utils.MetaInternal - } - } - initialMP[utils.StatSConnsCfg] = statSConns + initialMP[utils.StatSConnsCfg] = getInternalJSONConns(acS.StatSConns) } if acS.AccountSConns != nil { - accountSConns := make([]string, len(acS.AccountSConns)) - for i, item := range acS.AccountSConns { - accountSConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAccounts) { - accountSConns[i] = utils.MetaInternal - } - } - initialMP[utils.AccountSConnsCfg] = accountSConns + initialMP[utils.AccountSConnsCfg] = getInternalJSONConns(acS.AccountSConns) } if acS.EEsConns != nil { - eesConns := make([]string, len(acS.EEsConns)) - for i, item := range acS.EEsConns { - eesConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaEEs) { - eesConns[i] = utils.MetaInternal - } - } - initialMP[utils.EEsConnsCfg] = eesConns + initialMP[utils.EEsConnsCfg] = getInternalJSONConns(acS.EEsConns) } if acS.Tenants != nil { - Tenants := make([]string, len(*acS.Tenants)) - for i, item := range *acS.Tenants { - Tenants[i] = item - } - initialMP[utils.Tenants] = Tenants + initialMP[utils.Tenants] = utils.CloneStringSlice(*acS.Tenants) } if acS.StringIndexedFields != nil { - stringIndexedFields := make([]string, len(*acS.StringIndexedFields)) - for i, item := range *acS.StringIndexedFields { - stringIndexedFields[i] = item - } - initialMP[utils.StringIndexedFieldsCfg] = stringIndexedFields + initialMP[utils.StringIndexedFieldsCfg] = utils.CloneStringSlice(*acS.StringIndexedFields) } if acS.PrefixIndexedFields != nil { - prefixIndexedFields := make([]string, len(*acS.PrefixIndexedFields)) - for i, item := range *acS.PrefixIndexedFields { - prefixIndexedFields[i] = item - } - initialMP[utils.PrefixIndexedFieldsCfg] = prefixIndexedFields + initialMP[utils.PrefixIndexedFieldsCfg] = utils.CloneStringSlice(*acS.PrefixIndexedFields) } if acS.SuffixIndexedFields != nil { - suffixIndexedFields := make([]string, len(*acS.SuffixIndexedFields)) - for i, item := range *acS.SuffixIndexedFields { - suffixIndexedFields[i] = item - } - initialMP[utils.SuffixIndexedFieldsCfg] = suffixIndexedFields + initialMP[utils.SuffixIndexedFieldsCfg] = utils.CloneStringSlice(*acS.SuffixIndexedFields) } return } @@ -226,62 +124,91 @@ func (acS ActionSCfg) Clone() (cln *ActionSCfg) { NestedFields: acS.NestedFields, } if acS.CDRsConns != nil { - cln.CDRsConns = make([]string, len(acS.CDRsConns)) - for i, con := range acS.CDRsConns { - cln.CDRsConns[i] = con - } + cln.CDRsConns = utils.CloneStringSlice(acS.CDRsConns) } if acS.ThresholdSConns != nil { - cln.ThresholdSConns = make([]string, len(acS.ThresholdSConns)) - for i, con := range acS.ThresholdSConns { - cln.ThresholdSConns[i] = con - } + cln.ThresholdSConns = utils.CloneStringSlice(acS.ThresholdSConns) } if acS.StatSConns != nil { - cln.StatSConns = make([]string, len(acS.StatSConns)) - for i, con := range acS.StatSConns { - cln.StatSConns[i] = con - } + cln.StatSConns = utils.CloneStringSlice(acS.StatSConns) } if acS.AccountSConns != nil { - cln.AccountSConns = make([]string, len(acS.AccountSConns)) - for i, con := range acS.AccountSConns { - cln.AccountSConns[i] = con - } + cln.AccountSConns = utils.CloneStringSlice(acS.AccountSConns) } if acS.EEsConns != nil { - cln.EEsConns = make([]string, len(acS.EEsConns)) - for i, k := range acS.EEsConns { - cln.EEsConns[i] = k - } + cln.EEsConns = utils.CloneStringSlice(acS.EEsConns) } if acS.Tenants != nil { - tnt := make([]string, len(*acS.Tenants)) - for i, dx := range *acS.Tenants { - tnt[i] = dx - } - cln.Tenants = &tnt + cln.Tenants = utils.SliceStringPointer(utils.CloneStringSlice(*acS.Tenants)) } if acS.StringIndexedFields != nil { - idx := make([]string, len(*acS.StringIndexedFields)) - for i, dx := range *acS.StringIndexedFields { - idx[i] = dx - } - cln.StringIndexedFields = &idx + cln.StringIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*acS.StringIndexedFields)) } if acS.PrefixIndexedFields != nil { - idx := make([]string, len(*acS.PrefixIndexedFields)) - for i, dx := range *acS.PrefixIndexedFields { - idx[i] = dx - } - cln.PrefixIndexedFields = &idx + cln.PrefixIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*acS.PrefixIndexedFields)) } if acS.SuffixIndexedFields != nil { - idx := make([]string, len(*acS.SuffixIndexedFields)) - for i, dx := range *acS.SuffixIndexedFields { - idx[i] = dx - } - cln.SuffixIndexedFields = &idx + cln.SuffixIndexedFields = utils.SliceStringPointer(utils.CloneStringSlice(*acS.SuffixIndexedFields)) } return } + +// Action service config section +type ActionSJsonCfg struct { + Enabled *bool + Cdrs_conns *[]string + Ees_conns *[]string + Thresholds_conns *[]string + Stats_conns *[]string + Accounts_conns *[]string + Tenants *[]string + Indexed_selects *bool + String_indexed_fields *[]string + Prefix_indexed_fields *[]string + Suffix_indexed_fields *[]string + Nested_fields *bool // applies when indexed fields is not defined +} + +func diffActionSJsonCfg(d *ActionSJsonCfg, v1, v2 *ActionSCfg) *ActionSJsonCfg { + if d == nil { + d = new(ActionSJsonCfg) + } + if v1.Enabled != v2.Enabled { + d.Enabled = utils.BoolPointer(v2.Enabled) + } + if !utils.SliceStringEqual(v1.CDRsConns, v2.CDRsConns) { + d.Cdrs_conns = utils.SliceStringPointer(getInternalJSONConns(v2.CDRsConns)) + } + if !utils.SliceStringEqual(v1.EEsConns, v2.EEsConns) { + d.Ees_conns = utils.SliceStringPointer(getInternalJSONConns(v2.EEsConns)) + } + if !utils.SliceStringEqual(v1.ThresholdSConns, v2.ThresholdSConns) { + d.Thresholds_conns = utils.SliceStringPointer(getInternalJSONConns(v2.ThresholdSConns)) + } + if !utils.SliceStringEqual(v1.StatSConns, v2.StatSConns) { + d.Stats_conns = utils.SliceStringPointer(getInternalJSONConns(v2.StatSConns)) + } + if !utils.SliceStringEqual(v1.AccountSConns, v2.AccountSConns) { + d.Accounts_conns = utils.SliceStringPointer(getInternalJSONConns(v2.AccountSConns)) + } + + if v1.Tenants != v2.Tenants { + d.Tenants = utils.SliceStringPointer(utils.CloneStringSlice(*v2.Tenants)) + } + if v1.IndexedSelects != v2.IndexedSelects { + d.Indexed_selects = utils.BoolPointer(v2.IndexedSelects) + } + if v1.StringIndexedFields != v2.StringIndexedFields { + d.String_indexed_fields = diffIndexSlice(d.String_indexed_fields, v1.StringIndexedFields, v2.StringIndexedFields) + } + if v1.PrefixIndexedFields != v2.PrefixIndexedFields { + d.Prefix_indexed_fields = diffIndexSlice(d.Prefix_indexed_fields, v1.PrefixIndexedFields, v2.PrefixIndexedFields) + } + if v1.SuffixIndexedFields != v2.SuffixIndexedFields { + d.Suffix_indexed_fields = diffIndexSlice(d.Suffix_indexed_fields, v1.SuffixIndexedFields, v2.SuffixIndexedFields) + } + if v1.NestedFields != v2.NestedFields { + d.Nested_fields = utils.BoolPointer(v2.NestedFields) + } + return d +} diff --git a/config/config.go b/config/config.go index 0a58575db..45848f7f8 100644 --- a/config/config.go +++ b/config/config.go @@ -229,8 +229,7 @@ func newCGRConfig(config []byte) (cfg *CGRConfig, err error) { dfltKamConnConfig = cfg.kamAgentCfg.EvapiConns[0] dfltAstConnCfg = cfg.asteriskAgentCfg.AsteriskConns[0] dfltLoaderConfig = cfg.loaderCfg[0].Clone() - dfltRemoteHost = new(RemoteHost) - *dfltRemoteHost = *cfg.rpcConns[utils.MetaLocalHost].Conns[0] + dfltRemoteHost = cfg.rpcConns[utils.MetaLocalHost].Conns[0].Clone() err = cfg.checkConfigSanity() return } diff --git a/config/diametercfg.go b/config/diametercfg.go index 150fd83fa..7ae106b1b 100644 --- a/config/diametercfg.go +++ b/config/diametercfg.go @@ -20,7 +20,6 @@ package config import ( "github.com/cgrates/cgrates/utils" - "github.com/cgrates/rpcclient" ) // DiameterAgentCfg the config section that describes the Diameter Agent @@ -59,15 +58,7 @@ func (da *DiameterAgentCfg) loadFromJSONCfg(jsnCfg *DiameterAgentJsonCfg, separa da.DictionariesPath = *jsnCfg.Dictionaries_path } if jsnCfg.Sessions_conns != nil { - da.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) - for idx, attrConn := range *jsnCfg.Sessions_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - da.SessionSConns[idx] = attrConn - if attrConn == utils.MetaInternal || - attrConn == rpcclient.BiRPCInternal { - da.SessionSConns[idx] = utils.ConcatenatedKey(attrConn, utils.MetaSessionS) - } - } + da.SessionSConns = updateBiRPCInternalConns(*jsnCfg.Sessions_conns, utils.MetaSessionS) } if jsnCfg.Origin_host != nil { da.OriginHost = *jsnCfg.Origin_host @@ -143,16 +134,7 @@ func (da *DiameterAgentCfg) AsMapInterface(separator string) (initialMP map[stri initialMP[utils.RequestProcessorsCfg] = requestProcessors if da.SessionSConns != nil { - sessionSConns := make([]string, len(da.SessionSConns)) - for i, item := range da.SessionSConns { - sessionSConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) { - sessionSConns[i] = utils.MetaInternal - } else if item == utils.ConcatenatedKey(rpcclient.BiRPCInternal, utils.MetaSessionS) { - sessionSConns[i] = rpcclient.BiRPCInternal - } - } - initialMP[utils.SessionSConnsCfg] = sessionSConns + initialMP[utils.SessionSConnsCfg] = getBiRPCInternalJSONConns(da.SessionSConns) } return } @@ -175,10 +157,7 @@ func (da DiameterAgentCfg) Clone() (cln *DiameterAgentCfg) { ForcedDisconnect: da.ForcedDisconnect, } if da.SessionSConns != nil { - cln.SessionSConns = make([]string, len(da.SessionSConns)) - for i, con := range da.SessionSConns { - cln.SessionSConns[i] = con - } + cln.SessionSConns = utils.CloneStringSlice(da.SessionSConns) } if da.RequestProcessors != nil { cln.RequestProcessors = make([]*RequestProcessor, len(da.RequestProcessors)) @@ -188,3 +167,72 @@ func (da DiameterAgentCfg) Clone() (cln *DiameterAgentCfg) { } return } + +// DiameterAgent configuration +type DiameterAgentJsonCfg struct { + Enabled *bool + Listen *string + Listen_net *string + Dictionaries_path *string + Sessions_conns *[]string + Origin_host *string + Origin_realm *string + Vendor_id *int + Product_name *string + Concurrent_requests *int + Synced_conn_requests *bool + Asr_template *string + Rar_template *string + Forced_disconnect *string + Request_processors *[]*ReqProcessorJsnCfg +} + +func diffDiameterAgentJsonCfg(d *DiameterAgentJsonCfg, v1, v2 *DiameterAgentCfg, separator string) *DiameterAgentJsonCfg { + if d == nil { + d = new(DiameterAgentJsonCfg) + } + if v1.Enabled != v2.Enabled { + d.Enabled = utils.BoolPointer(v2.Enabled) + } + if v1.ListenNet != v2.ListenNet { + d.Listen_net = utils.StringPointer(v2.ListenNet) + } + if v1.Listen != v2.Listen { + d.Listen = utils.StringPointer(v2.Listen) + } + if v1.DictionariesPath != v2.DictionariesPath { + d.Dictionaries_path = utils.StringPointer(v2.DictionariesPath) + } + if !utils.SliceStringEqual(v1.SessionSConns, v2.SessionSConns) { + d.Sessions_conns = utils.SliceStringPointer(getBiRPCInternalJSONConns(v2.SessionSConns)) + } + if v1.OriginHost != v2.OriginHost { + d.Origin_host = utils.StringPointer(v2.OriginHost) + } + if v1.OriginRealm != v2.OriginRealm { + d.Origin_realm = utils.StringPointer(v2.OriginRealm) + } + if v1.VendorID != v2.VendorID { + d.Vendor_id = utils.IntPointer(v2.VendorID) + } + if v1.ProductName != v2.ProductName { + d.Product_name = utils.StringPointer(v2.ProductName) + } + if v1.ConcurrentReqs != v2.ConcurrentReqs { + d.Concurrent_requests = utils.IntPointer(v2.ConcurrentReqs) + } + if v1.SyncedConnReqs != v2.SyncedConnReqs { + d.Synced_conn_requests = utils.BoolPointer(v2.SyncedConnReqs) + } + if v1.ASRTemplate != v2.ASRTemplate { + d.Asr_template = utils.StringPointer(v2.ASRTemplate) + } + if v1.RARTemplate != v2.RARTemplate { + d.Rar_template = utils.StringPointer(v2.RARTemplate) + } + if v1.ForcedDisconnect != v2.ForcedDisconnect { + d.Forced_disconnect = utils.StringPointer(v2.ForcedDisconnect) + } + d.Request_processors = diffReqProcessorsJsnCfg(d.Request_processors, v1.RequestProcessors, v2.RequestProcessors, separator) + return d +} diff --git a/config/dnsagntcfg.go b/config/dnsagntcfg.go index c23c96658..3e6301d52 100644 --- a/config/dnsagntcfg.go +++ b/config/dnsagntcfg.go @@ -130,108 +130,3 @@ func (da DNSAgentCfg) Clone() (cln *DNSAgentCfg) { } return } - -// RequestProcessor is the request processor configuration -type RequestProcessor struct { - ID string - Tenant RSRParsers - Filters []string - Flags utils.FlagsWithParams - Timezone string - RequestFields []*FCTemplate - ReplyFields []*FCTemplate -} - -func (rp *RequestProcessor) loadFromJSONCfg(jsnCfg *ReqProcessorJsnCfg, sep string) (err error) { - if jsnCfg == nil { - return nil - } - if jsnCfg.ID != nil { - rp.ID = *jsnCfg.ID - } - if jsnCfg.Filters != nil { - rp.Filters = make([]string, len(*jsnCfg.Filters)) - for i, fltr := range *jsnCfg.Filters { - rp.Filters[i] = fltr - } - } - if jsnCfg.Flags != nil { - rp.Flags = utils.FlagsWithParamsFromSlice(*jsnCfg.Flags) - } - if jsnCfg.Timezone != nil { - rp.Timezone = *jsnCfg.Timezone - } - if jsnCfg.Tenant != nil { - if rp.Tenant, err = NewRSRParsers(*jsnCfg.Tenant, sep); err != nil { - return err - } - } - if jsnCfg.Request_fields != nil { - if rp.RequestFields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Request_fields, sep); err != nil { - return - } - } - if jsnCfg.Reply_fields != nil { - if rp.ReplyFields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Reply_fields, sep); err != nil { - return - } - } - return nil -} - -// AsMapInterface returns the config as a map[string]interface{} -func (rp *RequestProcessor) AsMapInterface(separator string) (initialMP map[string]interface{}) { - initialMP = map[string]interface{}{ - utils.IDCfg: rp.ID, - utils.FiltersCfg: rp.Filters, - utils.FlagsCfg: rp.Flags.SliceFlags(), - utils.TimezoneCfg: rp.Timezone, - } - if rp.Tenant != nil { - initialMP[utils.TenantCfg] = rp.Tenant.GetRule(separator) - } - if rp.RequestFields != nil { - requestFields := make([]map[string]interface{}, len(rp.RequestFields)) - for i, item := range rp.RequestFields { - requestFields[i] = item.AsMapInterface(separator) - } - initialMP[utils.RequestFieldsCfg] = requestFields - } - if rp.ReplyFields != nil { - replyFields := make([]map[string]interface{}, len(rp.ReplyFields)) - for i, item := range rp.ReplyFields { - replyFields[i] = item.AsMapInterface(separator) - } - initialMP[utils.ReplyFieldsCfg] = replyFields - } - return -} - -// Clone returns a deep copy of APIBanCfg -func (rp RequestProcessor) Clone() (cln *RequestProcessor) { - cln = &RequestProcessor{ - ID: rp.ID, - Tenant: rp.Tenant.Clone(), - Flags: rp.Flags.Clone(), - Timezone: rp.Timezone, - } - if rp.Filters != nil { - cln.Filters = make([]string, len(rp.Filters)) - for i, fltr := range rp.Filters { - cln.Filters[i] = fltr - } - } - if rp.RequestFields != nil { - cln.RequestFields = make([]*FCTemplate, len(rp.RequestFields)) - for i, rf := range rp.RequestFields { - cln.RequestFields[i] = rf.Clone() - } - } - if rp.ReplyFields != nil { - cln.ReplyFields = make([]*FCTemplate, len(rp.ReplyFields)) - for i, rf := range rp.ReplyFields { - cln.ReplyFields[i] = rf.Clone() - } - } - return -} diff --git a/config/kamagentcfg.go b/config/kamagentcfg.go index e1f7ab2d6..2ad8bdcd9 100644 --- a/config/kamagentcfg.go +++ b/config/kamagentcfg.go @@ -20,7 +20,6 @@ package config import ( "github.com/cgrates/cgrates/utils" - "github.com/cgrates/rpcclient" ) // NewDfltKamConnConfig returns the first cached default value for a KamConnCfg connection @@ -28,8 +27,7 @@ func NewDfltKamConnConfig() *KamConnCfg { if dfltKamConnConfig == nil { return new(KamConnCfg) // No defaults, most probably we are building the defaults now } - dfltVal := *dfltKamConnConfig - return &dfltVal + return dfltKamConnConfig.Clone() } // KamConnCfg represents one connection instance towards Kamailio @@ -90,15 +88,7 @@ func (ka *KamAgentCfg) loadFromJSONCfg(jsnCfg *KamAgentJsonCfg) error { ka.Enabled = *jsnCfg.Enabled } if jsnCfg.Sessions_conns != nil { - ka.SessionSConns = make([]string, len(*jsnCfg.Sessions_conns)) - for idx, attrConn := range *jsnCfg.Sessions_conns { - // if we have the connection internal we change the name so we can have internal rpc for each subsystem - ka.SessionSConns[idx] = attrConn - if attrConn == utils.MetaInternal || - attrConn == rpcclient.BiRPCInternal { - ka.SessionSConns[idx] = utils.ConcatenatedKey(attrConn, utils.MetaSessionS) - } - } + ka.SessionSConns = updateBiRPCInternalConns(*jsnCfg.Sessions_conns, utils.MetaSessionS) } if jsnCfg.Create_cdr != nil { ka.CreateCdr = *jsnCfg.Create_cdr @@ -131,16 +121,7 @@ func (ka *KamAgentCfg) AsMapInterface() (initialMP map[string]interface{}) { initialMP[utils.EvapiConnsCfg] = evapiConns } if ka.SessionSConns != nil { - sessionSConns := make([]string, len(ka.SessionSConns)) - for i, item := range ka.SessionSConns { - sessionSConns[i] = item - if item == utils.ConcatenatedKey(utils.MetaInternal, utils.MetaSessionS) { - sessionSConns[i] = utils.MetaInternal - } else if item == utils.ConcatenatedKey(rpcclient.BiRPCInternal, utils.MetaSessionS) { - sessionSConns[i] = rpcclient.BiRPCInternal - } - } - initialMP[utils.SessionSConnsCfg] = sessionSConns + initialMP[utils.SessionSConnsCfg] = getBiRPCInternalJSONConns(ka.SessionSConns) } return } @@ -153,10 +134,7 @@ func (ka KamAgentCfg) Clone() (cln *KamAgentCfg) { Timezone: ka.Timezone, } if ka.SessionSConns != nil { - cln.SessionSConns = make([]string, len(ka.SessionSConns)) - for i, con := range ka.SessionSConns { - cln.SessionSConns[i] = con - } + cln.SessionSConns = utils.CloneStringSlice(ka.SessionSConns) } if ka.EvapiConns != nil { cln.EvapiConns = make([]*KamConnCfg, len(ka.EvapiConns)) @@ -166,3 +144,74 @@ func (ka KamAgentCfg) Clone() (cln *KamAgentCfg) { } return } + +// Represents one connection instance towards Kamailio +type KamConnJsonCfg struct { + Alias *string + Address *string + Reconnects *int +} + +func diffKamConnJsonCfg(v1, v2 *KamConnCfg) (d *KamConnJsonCfg) { + d = new(KamConnJsonCfg) + if v1.Alias != v2.Alias { + d.Alias = utils.StringPointer(v2.Alias) + } + if v1.Address != v2.Address { + d.Address = utils.StringPointer(v2.Address) + } + if v1.Reconnects != v2.Reconnects { + d.Reconnects = utils.IntPointer(v2.Reconnects) + } + return +} + +// KamAgentJsonCfg kamailio config section +type KamAgentJsonCfg struct { + Enabled *bool + Sessions_conns *[]string + Create_cdr *bool + Evapi_conns *[]*KamConnJsonCfg + Timezone *string +} + +func equalsKamConnsCfg(v1, v2 []*KamConnCfg) bool { + if len(v1) != len(v2) { + return false + } + for i := range v2 { + if v1[i].Alias != v2[i].Alias || + v1[i].Address != v2[i].Address || + v1[i].Reconnects != v2[i].Reconnects { + return false + } + } + return true +} + +func diffKamAgentJsonCfg(d *KamAgentJsonCfg, v1, v2 *KamAgentCfg) *KamAgentJsonCfg { + if d == nil { + d = new(KamAgentJsonCfg) + } + if v1.Enabled != v2.Enabled { + d.Enabled = utils.BoolPointer(v2.Enabled) + } + if !utils.SliceStringEqual(v1.SessionSConns, v2.SessionSConns) { + d.Sessions_conns = utils.SliceStringPointer(getBiRPCInternalJSONConns(v2.SessionSConns)) + } + if v1.CreateCdr != v2.CreateCdr { + d.Create_cdr = utils.BoolPointer(v2.CreateCdr) + } + if !equalsKamConnsCfg(v1.EvapiConns, v2.EvapiConns) { + dft := NewDfltKamConnConfig() + conns := make([]*KamConnJsonCfg, len(v2.EvapiConns)) + for i, conn := range v2.EvapiConns { + conns[i] = diffKamConnJsonCfg(dft, conn) + } + d.Evapi_conns = &conns + } + if v1.Timezone != v2.Timezone { + d.Timezone = utils.StringPointer(v2.Timezone) + } + return d +} diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 937122da8..f44d239a7 100644 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -26,63 +26,6 @@ import ( "github.com/cgrates/rpcclient" ) -type RPCConnsJson map[string]*RPCConnJson -type RPCConnJson struct { - Strategy *string - PoolSize *int - Conns *[]*RemoteHostJson -} - -// Represents one connection instance towards a rater/cdrs server -type RemoteHostJson struct { - Id *string - Address *string - Transport *string - Synchronous *bool - Tls *bool -} - -// SM-Kamailio config section -type KamAgentJsonCfg struct { - Enabled *bool - Sessions_conns *[]string - Create_cdr *bool - Evapi_conns *[]*KamConnJsonCfg - Timezone *string -} - -// Represents one connection instance towards Kamailio -type KamConnJsonCfg struct { - Alias *string - Address *string - Reconnects *int -} - -// Represents one connection instance towards OpenSIPS -type OsipsConnJsonCfg struct { - Mi_addr *string - Reconnects *int -} - -// DiameterAgent configuration -type DiameterAgentJsonCfg struct { - Enabled *bool - Listen *string - Listen_net *string - Dictionaries_path *string - Sessions_conns *[]string - Origin_host *string - Origin_realm *string - Vendor_id *int - Product_name *string - Concurrent_requests *int - Synced_conn_requests *bool - Asr_template *string - Rar_template *string - Forced_disconnect *string - Request_processors *[]*ReqProcessorJsnCfg -} - // Radius Agent configuration section type RadiusAgentJsonCfg struct { Enabled *bool @@ -116,16 +59,6 @@ type DNSAgentJsonCfg struct { Request_processors *[]*ReqProcessorJsnCfg } -type ReqProcessorJsnCfg struct { - ID *string - Filters *[]string - Tenant *string - Timezone *string - Flags *[]string - Request_fields *[]*FcTemplateJsonCfg - Reply_fields *[]*FcTemplateJsonCfg -} - // ChargerSJsonCfg service config section type ChargerSJsonCfg struct { Enabled *bool @@ -339,37 +272,6 @@ type ConfigSCfgJson struct { Root_dir *string } -// Action service config section -type ActionSJsonCfg struct { - Enabled *bool - Cdrs_conns *[]string - Ees_conns *[]string - Thresholds_conns *[]string - Stats_conns *[]string - Accounts_conns *[]string - Tenants *[]string - Indexed_selects *bool - String_indexed_fields *[]string - Prefix_indexed_fields *[]string - Suffix_indexed_fields *[]string - Nested_fields *bool // applies when indexed fields is not defined -} - -// Account service config section -type AccountSJsonCfg struct { - Enabled *bool - Indexed_selects *bool - Attributes_conns *[]string - Rates_conns *[]string - Thresholds_conns *[]string - String_indexed_fields *[]string - Prefix_indexed_fields *[]string - Suffix_indexed_fields *[]string - Nested_fields *bool // applies when indexed fields is not defined - Max_iterations *int - Max_usage *string -} - // updateInternalConns updates the connection list by specifying the subsystem for internal connections func updateInternalConns(conns []string, subsystem string) (c []string) { subsystem = utils.MetaInternal + utils.ConcatenatedKeySep + subsystem diff --git a/config/loaderscfg.go b/config/loaderscfg.go index 8e50da459..bc51adc7a 100644 --- a/config/loaderscfg.go +++ b/config/loaderscfg.go @@ -29,8 +29,7 @@ func NewDfltLoaderSCfg() *LoaderSCfg { if dfltLoaderConfig == nil { return new(LoaderSCfg) } - dfltVal := *dfltLoaderConfig - return &dfltVal + return dfltLoaderConfig.Clone() } // LoaderSCfgs to export some methods for LoaderS profiles @@ -196,7 +195,7 @@ func (l LoaderSCfg) Clone() (cln *LoaderSCfg) { DryRun: l.DryRun, RunDelay: l.RunDelay, LockFileName: l.LockFileName, - CacheSConns: make([]string, len(l.CacheSConns)), + CacheSConns: utils.CloneStringSlice(l.CacheSConns), FieldSeparator: l.FieldSeparator, TpInDir: l.TpInDir, TpOutDir: l.TpOutDir, diff --git a/config/reqprocessorcfg.go b/config/reqprocessorcfg.go new file mode 100644 index 000000000..d1e89871a --- /dev/null +++ b/config/reqprocessorcfg.go @@ -0,0 +1,202 @@ +/* +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 "github.com/cgrates/cgrates/utils" + +// RequestProcessor is the request processor configuration +type RequestProcessor struct { + ID string + Tenant RSRParsers + Filters []string + Flags utils.FlagsWithParams + Timezone string + RequestFields []*FCTemplate + ReplyFields []*FCTemplate +} + +func (rp *RequestProcessor) loadFromJSONCfg(jsnCfg *ReqProcessorJsnCfg, sep string) (err error) { + if jsnCfg == nil { + return nil + } + if jsnCfg.ID != nil { + rp.ID = *jsnCfg.ID + } + if jsnCfg.Filters != nil { + rp.Filters = utils.CloneStringSlice(*jsnCfg.Filters) + } + if jsnCfg.Flags != nil { + rp.Flags = utils.FlagsWithParamsFromSlice(*jsnCfg.Flags) + } + if jsnCfg.Timezone != nil { + rp.Timezone = *jsnCfg.Timezone + } + if jsnCfg.Tenant != nil { + if rp.Tenant, err = NewRSRParsers(*jsnCfg.Tenant, sep); err != nil { + return + } + } + if jsnCfg.Request_fields != nil { + if rp.RequestFields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Request_fields, sep); err != nil { + return + } + } + if jsnCfg.Reply_fields != nil { + if rp.ReplyFields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Reply_fields, sep); err != nil { + return + } + } + return +} + +// AsMapInterface returns the config as a map[string]interface{} +func (rp *RequestProcessor) AsMapInterface(separator string) (initialMP map[string]interface{}) { + initialMP = map[string]interface{}{ + utils.IDCfg: rp.ID, + utils.FiltersCfg: utils.CloneStringSlice(rp.Filters), + utils.FlagsCfg: rp.Flags.SliceFlags(), + utils.TimezoneCfg: rp.Timezone, + } + if rp.Tenant != nil { + initialMP[utils.TenantCfg] = rp.Tenant.GetRule(separator) + } + if rp.RequestFields != nil { + requestFields := make([]map[string]interface{}, len(rp.RequestFields)) + for i, item := range rp.RequestFields { + requestFields[i] = item.AsMapInterface(separator) + } + initialMP[utils.RequestFieldsCfg] = requestFields + } + if rp.ReplyFields != nil { + replyFields := make([]map[string]interface{}, len(rp.ReplyFields)) + for i, item := range rp.ReplyFields { + replyFields[i] = item.AsMapInterface(separator) + } + initialMP[utils.ReplyFieldsCfg] = replyFields + } + return +} + +// Clone returns a deep copy of APIBanCfg +func (rp RequestProcessor) Clone() (cln *RequestProcessor) { + cln = &RequestProcessor{ + ID: rp.ID, + Tenant: rp.Tenant.Clone(), + Flags: rp.Flags.Clone(), + Timezone: rp.Timezone, + } + if rp.Filters != nil { + cln.Filters = utils.CloneStringSlice(rp.Filters) + } + if rp.RequestFields != nil { + cln.RequestFields = make([]*FCTemplate, len(rp.RequestFields)) + for i, rf := range rp.RequestFields { + cln.RequestFields[i] = rf.Clone() + } + } + if rp.ReplyFields != nil { + cln.ReplyFields = make([]*FCTemplate, len(rp.ReplyFields)) + for i, rf := range rp.ReplyFields { + cln.ReplyFields[i] = rf.Clone() + } + } + return +} + +type ReqProcessorJsnCfg struct { + ID *string + Filters *[]string + Tenant *string + Timezone *string + Flags *[]string + Request_fields *[]*FcTemplateJsonCfg + Reply_fields *[]*FcTemplateJsonCfg +} + +func diffReqProcessorJsnCfg(d *ReqProcessorJsnCfg, v1, v2 *RequestProcessor, separator string) *ReqProcessorJsnCfg { + if d == nil { + d = new(ReqProcessorJsnCfg) + } + if v1.ID != v2.ID { + d.ID = utils.StringPointer(v2.ID) + } + tnt1 := v1.Tenant.GetRule(separator) + tnt2 := v2.Tenant.GetRule(separator) + if tnt1 != tnt2 { + d.Tenant = utils.StringPointer(tnt2) + } + if !utils.SliceStringEqual(v1.Filters, v2.Filters) { + d.Filters = utils.SliceStringPointer(utils.CloneStringSlice(v2.Filters)) + } + flag1 := v1.Flags.SliceFlags() + flag2 := v2.Flags.SliceFlags() + if !utils.SliceStringEqual(flag1, flag2) { + d.Flags = utils.SliceStringPointer(flag2) + } + if v1.Timezone != v2.Timezone { + d.Timezone = utils.StringPointer(v2.Timezone) + } + var req []*FcTemplateJsonCfg + if d.Request_fields != nil { + req = *d.Request_fields + } + req = diffFcTemplateJsonCfg(req, v1.RequestFields, v2.RequestFields, separator) + d.Request_fields = &req + + var rply []*FcTemplateJsonCfg + if d.Reply_fields != nil { + rply = *d.Reply_fields + } + rply = diffFcTemplateJsonCfg(rply, v1.ReplyFields, v2.ReplyFields, separator) + d.Reply_fields = &rply + return d +} +func getReqProcessorJsnCfg(d []*ReqProcessorJsnCfg, id string) (*ReqProcessorJsnCfg, int) { + for i, v := range d { + if v.ID != nil && *v.ID == id { + return v, i + } + } + return nil, -1 +} + +func getRequestProcessor(d []*RequestProcessor, id string) *RequestProcessor { + for _, v := range d { + if v.ID == id { + return v + } + } + return new(RequestProcessor) +} + +func diffReqProcessorsJsnCfg(d *[]*ReqProcessorJsnCfg, v1, v2 []*RequestProcessor, separator string) *[]*ReqProcessorJsnCfg { + if d == nil || *d == nil { + d = &[]*ReqProcessorJsnCfg{} + } + for _, val := range v2 { + dv, i := getReqProcessorJsnCfg(*d, val.ID) + dv = diffReqProcessorJsnCfg(dv, getRequestProcessor(v1, val.ID), val, separator) + if i == -1 { + *d = append(*d, dv) + } else { + (*d)[i] = dv + } + } + return d +} diff --git a/config/rpcconn.go b/config/rpcconn.go index 325c270a6..97df58b17 100644 --- a/config/rpcconn.go +++ b/config/rpcconn.go @@ -28,8 +28,7 @@ func NewDfltRemoteHost() *RemoteHost { if dfltRemoteHost == nil { return new(RemoteHost) // No defaults, most probably we are building the defaults now } - dfltVal := *dfltRemoteHost // Copy the value instead of it's pointer - return &dfltVal + return dfltRemoteHost.Clone() } // NewDfltRPCConn returns the default value for a RPCConn @@ -215,3 +214,98 @@ func RemoveRPCCons(rpcConns RPCConns, hosts utils.StringSet) (connIDs utils.Stri } return } + +// Represents one connection instance towards a rater/cdrs server +type RemoteHostJson struct { + Id *string + Address *string + Transport *string + Synchronous *bool + Tls *bool +} + +func diffRemoteHostJson(v1, v2 *RemoteHost) (d *RemoteHostJson) { + d = new(RemoteHostJson) + if v1.ID != v2.ID { + d.Id = utils.StringPointer(v2.ID) + } + if v1.Address != v2.Address { + d.Address = utils.StringPointer(v2.Address) + } + if v1.Transport != v2.Transport { + d.Transport = utils.StringPointer(v2.Transport) + } + if v1.Synchronous != v2.Synchronous { + d.Synchronous = utils.BoolPointer(v2.Synchronous) + } + if v1.TLS != v2.TLS { + d.Tls = utils.BoolPointer(v2.TLS) + } + return +} + +type RPCConnJson struct { + Strategy *string + PoolSize *int + Conns *[]*RemoteHostJson +} + +func diffRPCConnJson(d *RPCConnJson, v1, v2 *RPCConn) *RPCConnJson { + if d == nil { + d = new(RPCConnJson) + } + if v1.Strategy != v2.Strategy { + d.Strategy = utils.StringPointer(v2.Strategy) + } + if v1.PoolSize != v2.PoolSize { + d.PoolSize = utils.IntPointer(v2.PoolSize) + } + if v2.Conns != nil { + conns := make([]*RemoteHostJson, len(v2.Conns)) + dft := NewDfltRemoteHost() + for i, conn := range v2.Conns { + conns[i] = diffRemoteHostJson(dft, conn) + } + d.Conns = &conns + } + return d +} + +func equalsRemoteHosts(v1, v2 []*RemoteHost) bool { + if len(v1) != len(v2) { + return false + } + for i := range v2 { + if v1[i].ID != v2[i].ID || + v1[i].Address != v2[i].Address || + v1[i].Transport != v2[i].Transport || + v1[i].Synchronous != v2[i].Synchronous || + v1[i].TLS != v2[i].TLS { + return false + } + } + return true +} + +func equalsRPCConn(v1, v2 *RPCConn) bool { + return (v1 == nil && v2 == nil) || + (v1 != nil && v2 != nil && + v1.Strategy == v2.Strategy && + v1.PoolSize == v2.PoolSize && + equalsRemoteHosts(v1.Conns, v2.Conns)) +} + +type RPCConnsJson map[string]*RPCConnJson + +func diffRPCConnsJson(d RPCConnsJson, v1, v2 RPCConns) RPCConnsJson { + if d == nil { + d = make(RPCConnsJson) + } + dft := NewDfltRPCConn() + for k, val := range v2 { + if !equalsRPCConn(v1[k], val) { + d[k] = diffRPCConnJson(d[k], dft, val) + } + } + return d +}