/* 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 Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see */ package config import ( "slices" "github.com/cgrates/cgrates/utils" ) // RequestProcessor is the request processor configuration type RequestProcessor struct { ID string Tenant utils.RSRParsers Filters []string Flags utils.FlagsWithParams Timezone string RequestFields []*FCTemplate ReplyFields []*FCTemplate } func (rp *RequestProcessor) loadFromJSONCfg(jsnCfg *ReqProcessorJsnCfg) (err error) { if jsnCfg == nil { return nil } if jsnCfg.ID != nil { rp.ID = *jsnCfg.ID } if jsnCfg.Filters != nil { rp.Filters = slices.Clone(*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 = utils.NewRSRParsers(*jsnCfg.Tenant, utils.RSRSep); err != nil { return } } if jsnCfg.Request_fields != nil { if rp.RequestFields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Request_fields); err != nil { return } } if jsnCfg.Reply_fields != nil { if rp.ReplyFields, err = FCTemplatesFromFCTemplatesJSONCfg(*jsnCfg.Reply_fields); err != nil { return } } return } // AsMapInterface returns the config as a map[string]any func (rp *RequestProcessor) AsMapInterface() (initialMP map[string]any) { initialMP = map[string]any{ utils.IDCfg: rp.ID, utils.FiltersCfg: slices.Clone(rp.Filters), utils.FlagsCfg: rp.Flags.SliceFlags(), utils.TimezoneCfg: rp.Timezone, } if rp.Tenant != nil { initialMP[utils.TenantCfg] = rp.Tenant.GetRule() } if rp.RequestFields != nil { requestFields := make([]map[string]any, len(rp.RequestFields)) for i, item := range rp.RequestFields { requestFields[i] = item.AsMapInterface() } initialMP[utils.RequestFieldsCfg] = requestFields } if rp.ReplyFields != nil { replyFields := make([]map[string]any, len(rp.ReplyFields)) for i, item := range rp.ReplyFields { replyFields[i] = item.AsMapInterface() } 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 = slices.Clone(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) *ReqProcessorJsnCfg { if d == nil { d = new(ReqProcessorJsnCfg) } if v1.ID != v2.ID { d.ID = utils.StringPointer(v2.ID) } tnt1 := v1.Tenant.GetRule() tnt2 := v2.Tenant.GetRule() if tnt1 != tnt2 { d.Tenant = utils.StringPointer(tnt2) } if !slices.Equal(v1.Filters, v2.Filters) { d.Filters = utils.SliceStringPointer(slices.Clone(v2.Filters)) } flag1 := v1.Flags.SliceFlags() flag2 := v2.Flags.SliceFlags() if !slices.Equal(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) if req != nil { d.Request_fields = &req } var rply []*FcTemplateJsonCfg if d.Reply_fields != nil { rply = *d.Reply_fields } rply = diffFcTemplateJsonCfg(rply, v1.ReplyFields, v2.ReplyFields) if rply != nil { 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) *[]*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) if i == -1 { *d = append(*d, dv) } else { (*d)[i] = dv } } return d } func appendRequestProcessors(to []*RequestProcessor, from *[]*ReqProcessorJsnCfg) (_ []*RequestProcessor, err error) { if from == nil { return to, nil } for _, rpJsn := range *from { rp := new(RequestProcessor) var haveID bool if rpJsn.ID != nil { for _, rpTo := range to { if rpTo.ID == *rpJsn.ID { rp = rpTo // Will load data into the one set haveID = true break } } } if err = rp.loadFromJSONCfg(rpJsn); err != nil { return } if !haveID { to = append(to, rp) } } return to, nil } func equalsRequestProcessors(v1, v2 []*RequestProcessor) bool { if len(v1) != len(v2) { return false } for i := range v2 { if v1[i].ID != v2[i].ID || !slices.Equal(v1[i].Tenant.AsStringSlice(), v2[i].Tenant.AsStringSlice()) || !slices.Equal(v1[i].Filters, v2[i].Filters) || !slices.Equal(v1[i].Flags.SliceFlags(), v2[i].Flags.SliceFlags()) || v1[i].Timezone != v2[i].Timezone || !fcTemplatesEqual(v1[i].RequestFields, v2[i].RequestFields) || !fcTemplatesEqual(v1[i].ReplyFields, v2[i].ReplyFields) { return false } } return true }