From 2d440a046d4af529e7358eca2174c31b68a21278 Mon Sep 17 00:00:00 2001 From: DanB Date: Sun, 14 Jun 2015 19:02:58 +0200 Subject: [PATCH] FreeSWITCH cgr_computelcr channel variable processing, fix logging of callcosts from session manager, improved tutorial_fs testing --- .../cgrates/etc/cgrates/cgrates.json | 158 +----------------- engine/cdrs.go | 5 +- engine/event.go | 1 + engine/lcr.go | 37 ++-- engine/lcr_test.go | 21 +++ engine/storedcdr.go | 3 + general_tests/tutorial_fs_calls_test.go | 9 + sessionmanager/fsevent.go | 28 +++- sessionmanager/fsevent_test.go | 2 +- sessionmanager/fssessionmanager.go | 31 +++- sessionmanager/kamevent.go | 13 +- sessionmanager/osipsevent.go | 9 + utils/consts.go | 2 +- 13 files changed, 135 insertions(+), 184 deletions(-) diff --git a/data/tutorials/fs_evsock/cgrates/etc/cgrates/cgrates.json b/data/tutorials/fs_evsock/cgrates/etc/cgrates/cgrates.json index 783bd3ffc..903d2f953 100644 --- a/data/tutorials/fs_evsock/cgrates/etc/cgrates/cgrates.json +++ b/data/tutorials/fs_evsock/cgrates/etc/cgrates/cgrates.json @@ -7,65 +7,9 @@ // This is what you get when you load CGRateS with an empty configuration file. -//"general": { -// "http_skip_tls_veify": false, // if enabled Http Client will accept any TLS certificate -// "rounding_decimals": 10, // system level precision for floats -// "dbdata_encoding": "msgpack", // encoding used to store object data in strings: -// "tpexport_dir": "/var/log/cgrates/tpe", // path towards export folder for offline Tariff Plans -// "default_reqtype": "*rated", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated> -// "default_category": "call", // default Type of Record to consider when missing from requests -// "default_tenant": "cgrates.org", // default Tenant to consider when missing from requests -// "default_subject": "cgrates", // default rating Subject to consider when missing from requests -//}, - - -//"listen": { -// "rpc_json": "127.0.0.1:2012", // RPC JSON listening address -// "rpc_gob": "127.0.0.1:2013", // RPC GOB listening address -// "http": "127.0.0.1:2080", // HTTP listening address -//}, - - -//"rating_db": { -// "db_type": "redis", // rating subsystem database type: -// "db_host": "127.0.0.1", // rating subsystem database host address -// "db_port": 6379, // rating subsystem port to reach the database -// "db_name": "10", // rating subsystem database name to connect to -// "db_user": "", // rating subsystem username to use when connecting to database -// "db_passwd": "", // rating subsystem password to use when connecting to database -//}, - - -//"accounting_db": { -// "db_type": "redis", // accounting subsystem database: -// "db_host": "127.0.0.1", // accounting subsystem database host address -// "db_port": 6379, // accounting subsystem port to reach the database -// "db_name": "11", // accounting subsystem database name to connect to -// "db_user": "", // accounting subsystem username to use when connecting to database -// "db_passwd": "", // accounting subsystem password to use when connecting to database -//}, - - -//"stor_db": { -// "db_type": "mysql", // stor database type to use: -// "db_host": "127.0.0.1", // the host to connect to -// "db_port": 3306, // the port to reach the stordb -// "db_name": "cgrates", // stor database name -// "db_user": "cgrates", // username to use when connecting to stordb -// "db_passwd": "CGRateS.org", // password to use when connecting to stordb -// "max_open_conns": 0, // maximum database connections opened -// "max_idle_conns": -1, // maximum database connections idle -//}, - - -//"balancer": { -// "enabled": false, // start Balancer service: -//}, - - "rater": { "enabled": true, // enable Rater service: -// "balancer": "", // register to Balancer as worker: <""|internal|x.y.z.y:1234> + "cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> }, @@ -76,36 +20,12 @@ "cdrs": { "enabled": true, // start the CDR Server service: -// "extra_fields": [], // extra fields to store in CDRs for non-generic CDRs -// "rate_cdrs": true, // enable CDR rating calculation -// "store_cdrs": true, // store cdrs in storDb "rater": "internal", // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234> "cdrstats": "internal", // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> -// "reconnects": 5, // number of reconnect attempts to rater or cdrs -// "cdr_replication":[], // replicate the raw CDR to a number of servers }, "cdrstats": { "enabled": true, // starts the cdrstats service: -// "queue_length": 50, // number of items in the stats buffer -// "time_window": "1h", // will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow -// "metrics": ["ASR", "ACD", "ACC"], // stat metric ids to build -// "setup_interval": [], // filter on CDR SetupTime -// "tors": [], // filter on CDR TOR fields -// "cdr_hosts": [], // filter on CDR CdrHost fields -// "cdr_sources": [], // filter on CDR CdrSource fields -// "req_types": [], // filter on CDR ReqType fields -// "directions": [], // filter on CDR Direction fields -// "tenants": [], // filter on CDR Tenant fields -// "categories": [], // filter on CDR Category fields -// "accounts": [], // filter on CDR Account fields -// "subjects": [], // filter on CDR Subject fields -// "destination_prefixes": [], // filter on CDR Destination prefixes -// "usage_interval": [], // filter on CDR Usage -// "mediation_run_ids": [], // filter on CDR MediationRunId fields -// "rated_accounts": [], // filter on CDR RatedAccount fields -// "rated_subjects": [], // filter on CDR RatedSubject fields -// "cost_interval": [], // filter on CDR Cost }, @@ -145,103 +65,27 @@ }, -//"cdrc": { -// "*default": { -// "enabled": false, // enable CDR client functionality -// "cdrs_address": "internal", // address where to reach CDR server. -// "cdr_format": "csv", // CDR file format -// "field_separator": ",", // separator used in case of csv files -// "run_delay": 0, // sleep interval in seconds between consecutive runs, 0 to use automation via inotify -// "data_usage_multiply_factor": 1024, // conversion factor for data usage -// "cdr_in_dir": "/var/log/cgrates/cdrc/in", // absolute path towards the directory where the CDRs are stored -// "cdr_out_dir": "/var/log/cgrates/cdrc/out", // absolute path towards the directory where processed CDRs will be moved -// "cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database -// "cdr_filter": "", // Filter CDR records to import -// "cdr_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value -// {"tag": "tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "2", "mandatory": true}, -// {"tag": "accid", "cdr_field_id": "accid", "type": "cdrfield", "value": "3", "mandatory": true}, -// {"tag": "reqtype", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "4", "mandatory": true}, -// {"tag": "direction", "cdr_field_id": "direction", "type": "cdrfield", "value": "5", "mandatory": true}, -// {"tag": "tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "6", "mandatory": true}, -// {"tag": "category", "cdr_field_id": "category", "type": "cdrfield", "value": "7", "mandatory": true}, -// {"tag": "account", "cdr_field_id": "account", "type": "cdrfield", "value": "8", "mandatory": true}, -// {"tag": "subject", "cdr_field_id": "subject", "type": "cdrfield", "value": "9", "mandatory": true}, -// {"tag": "destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "10", "mandatory": true}, -// {"tag": "setup_time", "cdr_field_id": "setup_time", "type": "cdrfield", "value": "11", "mandatory": true}, -// {"tag": "answer_time", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "12", "mandatory": true}, -// {"tag": "usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "13", "mandatory": true}, -// ], -// } -//}, - - "sm_freeswitch": { "enabled": true, // starts SessionManager service: "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013> "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234> -// "reconnects": 5, // number of reconnect attempts to rater or cdrs "create_cdr": true, // create CDR out of events and sends them to CDRS component -// "cdr_extra_fields": [], // extra fields to store in CDRs in case of processing them "debit_interval": "5s", // interval to perform debits on. -// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this -// "max_call_duration": "3h", // maximum call duration a prepaid call can last -// "min_dur_low_balance": "5s", // threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval) -// "low_balance_ann_file": "", // file to be played when low balance is reached for prepaid calls -// "empty_balance_context": "", // if defined, prepaid calls will be transfered to this context on empty balance -// "empty_balance_ann_file": "", // file to be played before disconnecting prepaid calls on empty balance (applies only if no context defined) "connections":[ // instantiate connections to multiple FreeSWITCH servers {"server": "127.0.0.1:8021", "password": "ClueCon", "reconnects": 15} ], }, -//"sm_kamailio": { -// "enabled": false, // starts SessionManager service: -// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013> -// "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234> -// "reconnects": 5, // number of reconnect attempts to rater or cdrs -// "debit_interval": "10s", // interval to perform debits on. -// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this -// "max_call_duration": "3h", // maximum call duration a prepaid call can last -// "connections":[ // instantiate connections to multiple Kamailio servers -// {"evapi_addr": "127.0.0.1:8448", "reconnects": -1} // reconnects -1 to indefinitely connect -// ], -//}, - - -//"sm_opensips": { -// "enabled": false, // starts SessionManager service: -// "listen_udp": "127.0.0.1:2020", // address where to listen for datagram events coming from OpenSIPS -// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013> -// "cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234> -// "debit_interval": "10s", // interval to perform debits on. -// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this -// "max_call_duration": "3h", // maximum call duration a prepaid call can last -// "events_subscribe_interval": "60s", // automatic events subscription to OpenSIPS, 0 to disable it -// "mi_addr": "127.0.0.1:8020", // address where to reach OpenSIPS MI to send session disconnects -// "reconnects": -1, // reconnects -1 to indefinitely connect -//}, - - - "history_server": { "enabled": true, // starts History service: . "history_dir": "/tmp/cgr_fsevsock/cgrates/history", // location on disk where to store history files. -// "save_interval": "1s", // interval to save changed cache into .git archive }, "history_agent": { "enabled": true, // starts History as a client: . -// "server": "internal", // address where to reach the master history server: }, -//"mailer": { -// "server": "localhost", // the server to use when sending emails out -// "auth_user": "cgrates", // authenticate to email server using this user -// "auth_passwd": "CGRateS.org", // authenticate to email server with this password -// "from_address": "cgr-mailer@localhost.localdomain" // from address used when sending emails out -//}, - } diff --git a/engine/cdrs.go b/engine/cdrs.go index b634dd0fa..cf42c232a 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -108,9 +108,10 @@ type CallCostLog struct { // RPC method, used to log callcosts to db func (self *CdrServer) LogCallCost(ccl *CallCostLog) error { + Logger.Debug(fmt.Sprintf("LogCallCost, callCostLog: %+v, cost: %+v", ccl, ccl.CallCost)) if ccl.CheckDuplicate { cc, err := self.cdrDb.GetCallCostLog(ccl.CgrId, ccl.Source, ccl.RunId) - if err != nil { + if err != nil && err.Error() != "record not found" { return err } if cc != nil { @@ -245,7 +246,7 @@ func (self *CdrServer) getCostFromRater(storedCdr *StoredCdr) (*CallCost, error) } if utils.IsSliceMember([]string{utils.META_PSEUDOPREPAID, utils.META_POSTPAID, utils.PSEUDOPREPAID, utils.POSTPAID}, storedCdr.ReqType) { if err = self.rater.Debit(cd, cc); err == nil { // Debit has occured, we are forced to write the log, even if CDR store is disabled - self.cdrDb.LogCallCost(storedCdr.CgrId, MEDIATOR_SOURCE, storedCdr.MediationRunId, cc) + self.cdrDb.LogCallCost(storedCdr.CgrId, utils.CDRS_SOURCE, storedCdr.MediationRunId, cc) } } else { err = self.rater.GetCost(cd, cc) diff --git a/engine/event.go b/engine/event.go index c145593c8..58d34007a 100644 --- a/engine/event.go +++ b/engine/event.go @@ -51,4 +51,5 @@ type Event interface { AsStoredCdr() *StoredCdr String() string AsEvent(string) Event + ComputeLcr() bool } diff --git a/engine/lcr.go b/engine/lcr.go index 6d86c1702..5b5862752 100644 --- a/engine/lcr.go +++ b/engine/lcr.go @@ -305,21 +305,36 @@ func (lc *LCRCost) LogErrors() { } } +func (lc *LCRCost) SuppliersSlice() ([]string, error) { + if lc.Entry == nil { + return nil, utils.ErrNotFound + } + supps := []string{} + for _, supplCost := range lc.SupplierCosts { + if dtcs, err := utils.NewDTCSFromRPKey(supplCost.Supplier); err != nil { + return nil, err + } else if len(dtcs.Subject) != 0 { + supps = append(supps, dtcs.Subject) + } + } + if len(supps) == 0 { + return nil, utils.ErrNotFound + } + return supps, nil +} + // Returns a list of suppliers separated via func (lc *LCRCost) SuppliersString() (string, error) { - supplStr := "" - if lc.Entry == nil { - return "", utils.ErrNotFound + supps, err := lc.SuppliersSlice() + if err != nil { + return "", err } - for idx, supplCost := range lc.SupplierCosts { - if dtcs, err := utils.NewDTCSFromRPKey(supplCost.Supplier); err != nil { - return "", err - } else { - if idx != 0 { - supplStr += utils.FIELDS_SEP - } - supplStr += dtcs.Subject + supplStr := "" + for idx, suppl := range supps { + if idx != 0 { + supplStr += utils.FIELDS_SEP } + supplStr += suppl } return supplStr, nil } diff --git a/engine/lcr_test.go b/engine/lcr_test.go index bb7f00783..5d5a0d09e 100644 --- a/engine/lcr_test.go +++ b/engine/lcr_test.go @@ -234,6 +234,27 @@ func TestLcrRequestAsCallDescriptor(t *testing.T) { } } +func TestLCRCostSuppliersSlice(t *testing.T) { + lcrCost := new(LCRCost) + if _, err := lcrCost.SuppliersString(); err == nil || err != utils.ErrNotFound { + t.Errorf("Unexpected error received: %v", err) + } + lcrCost = &LCRCost{ + Entry: &LCREntry{DestinationId: utils.ANY, RPCategory: "call", Strategy: LCR_STRATEGY_STATIC, StrategyParams: "ivo12;dan12;rif12", Weight: 10.0}, + SupplierCosts: []*LCRSupplierCost{ + &LCRSupplierCost{Supplier: "*out:tenant12:call:ivo12", Cost: 1.8, Duration: 60 * time.Second}, + &LCRSupplierCost{Supplier: "*out:tenant12:call:dan12", Cost: 0.6, Duration: 60 * time.Second}, + &LCRSupplierCost{Supplier: "*out:tenant12:call:rif12", Cost: 1.2, Duration: 60 * time.Second}, + }, + } + eSuppls := []string{"ivo12", "dan12", "rif12"} + if suppls, err := lcrCost.SuppliersSlice(); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eSuppls, suppls) { + t.Errorf("Expecting: %+v, received: %+v", eSuppls, suppls) + } +} + func TestLCRCostSuppliersString(t *testing.T) { lcrCost := new(LCRCost) if _, err := lcrCost.SuppliersString(); err == nil || err != utils.ErrNotFound { diff --git a/engine/storedcdr.go b/engine/storedcdr.go index 4658199b7..d309a78d7 100644 --- a/engine/storedcdr.go +++ b/engine/storedcdr.go @@ -418,6 +418,9 @@ func (storedCdr *StoredCdr) AsExternalCdr() *ExternalCdr { func (storedCdr *StoredCdr) AsEvent(ignored string) Event { return Event(storedCdr) } +func (storedCdr *StoredCdr) ComputeLcr() bool { + return false +} func (storedCdr *StoredCdr) GetName() string { return storedCdr.CdrSource } diff --git a/general_tests/tutorial_fs_calls_test.go b/general_tests/tutorial_fs_calls_test.go index 06a80a599..6eb546fb2 100644 --- a/general_tests/tutorial_fs_calls_test.go +++ b/general_tests/tutorial_fs_calls_test.go @@ -291,6 +291,9 @@ func TestTutFsCallsCdrs(t *testing.T) { if reply[0].Usage != "67" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) } + if reply[0].Cost == -1.0 { // Cost was not calculated + t.Errorf("Unexpected Cost for CDR: %+v", reply[0]) + } } req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnRated: true} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { @@ -380,6 +383,9 @@ func TestTutFsCallsCdrs(t *testing.T) { if reply[0].Usage != "64" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) } + if reply[0].Cost == -1.0 { // Cost was not calculated + t.Errorf("Unexpected Cost for CDR: %+v", reply[0]) + } } req = utils.RpcCdrsFilter{Accounts: []string{"1007"}, RunIds: []string{utils.META_DEFAULT}} if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil { @@ -399,6 +405,9 @@ func TestTutFsCallsCdrs(t *testing.T) { if reply[0].Usage != "66" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) } + if reply[0].Cost == -1.0 { // Cost was not calculated + t.Errorf("Unexpected Cost for CDR: %+v", reply[0]) + } } } diff --git a/sessionmanager/fsevent.go b/sessionmanager/fsevent.go index 4ae1e889b..cac883215 100644 --- a/sessionmanager/fsevent.go +++ b/sessionmanager/fsevent.go @@ -72,6 +72,7 @@ const ( IGNOREPARK = "variable_cgr_ignorepark" VAR_CGR_DISCONNECT_CAUSE = "variable_" + utils.CGR_DISCONNECT_CAUSE + VAR_CGR_CMPUTELCR = "variable_" + utils.CGR_COMPUTELCR ) // Nice printing for the event object. @@ -362,7 +363,30 @@ func (fsev FSEvent) AsStoredCdr() *engine.StoredCdr { return storCdr } -// Converts a slice of strings into a FS array string +func (fsev FSEvent) ComputeLcr() bool { + if computeLcr, err := strconv.ParseBool(fsev[VAR_CGR_CMPUTELCR]); err != nil { + return false + } else { + return computeLcr + } +} + +// Converts into CallDescriptor due to responder interface needs +func (fsev FSEvent) AsCallDescriptor() (*engine.CallDescriptor, error) { + lcrReq := &engine.LcrRequest{ + Direction: fsev.GetDirection(utils.META_DEFAULT), + Tenant: fsev.GetTenant(utils.META_DEFAULT), + Category: fsev.GetCategory(utils.META_DEFAULT), + Account: fsev.GetAccount(utils.META_DEFAULT), + Subject: fsev.GetSubject(utils.META_DEFAULT), + Destination: fsev.GetDestination(utils.META_DEFAULT), + StartTime: utils.FirstNonEmpty(fsev[SETUP_TIME], fsev[ANSWER_TIME]), + Duration: fsev[DURATION], + } + return lcrReq.AsCallDescriptor() +} + +// Converts a slice of strings into a FS array string, contains len(array) at first index since FS does not support len(ARRAY::) for now func SliceAsFsArray(slc []string) string { arry := "" if len(slc) == 0 { @@ -370,7 +394,7 @@ func SliceAsFsArray(slc []string) string { } for idx, itm := range slc { if idx == 0 { - arry += "ARRAY::" + itm + arry = fmt.Sprintf("ARRAY::%d|:%s", len(slc), itm) } else { arry += "|:" + itm } diff --git a/sessionmanager/fsevent_test.go b/sessionmanager/fsevent_test.go index 6d880e9a0..dbcfff580 100644 --- a/sessionmanager/fsevent_test.go +++ b/sessionmanager/fsevent_test.go @@ -665,7 +665,7 @@ func TestSliceAsFsArray(t *testing.T) { t.Error(fsArray) } items = []string{"item1", "item2", "item3"} - if fsArray := SliceAsFsArray(items); fsArray != "ARRAY::item1|:item2|:item3" { + if fsArray := SliceAsFsArray(items); fsArray != "ARRAY::3|:item1|:item2|:item3" { t.Error(fsArray) } } diff --git a/sessionmanager/fssessionmanager.go b/sessionmanager/fssessionmanager.go index e337ef1f9..399642444 100644 --- a/sessionmanager/fssessionmanager.go +++ b/sessionmanager/fssessionmanager.go @@ -207,15 +207,36 @@ func (sm *FSSessionManager) onChannelPark(ev engine.Event, connId string) { return } sm.setMaxCallDuration(ev.GetUUID(), connId, maxCallDur) - - /*if sm.cfg.ComputeLcr { // Fix here out of channel variable - if err := sm.setCgrLcr(ev, connId); err != nil { - engine.Logger.Err(fmt.Sprintf(" Could not set LCR for %s, error: %s", ev.GetUUID(), err.Error())) + // ComputeLcr + if ev.ComputeLcr() { + cd, err := fsev.AsCallDescriptor() + if err != nil { + engine.Logger.Info(fmt.Sprintf(" LCR_PREPROCESS_ERROR: %s", err.Error())) sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), SYSTEM_ERROR) return } + var lcr engine.LCRCost + if err = sm.Rater().GetLCR(cd, &lcr); err != nil { + engine.Logger.Info(fmt.Sprintf(" LCR_API_ERROR: %s", err.Error())) + sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), SYSTEM_ERROR) + } + if lcr.HasErrors() { + lcr.LogErrors() + sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), SYSTEM_ERROR) + return + } + if supps, err := lcr.SuppliersSlice(); err != nil { + engine.Logger.Info(fmt.Sprintf(" LCR_ERROR: %s", err.Error())) + sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), SYSTEM_ERROR) + return + } else { + fsArray := SliceAsFsArray(supps) + if _, err = sm.conns[connId].SendApiCmd(fmt.Sprintf("uuid_setvar %s %s %s\n\n", ev.GetUUID(), utils.CGR_SUPPLIERS, fsArray)); err != nil { + engine.Logger.Info(fmt.Sprintf(" LCR_ERROR: %s", err.Error())) + sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), SYSTEM_ERROR) + } + } } - */ sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), AUTH_OK) } diff --git a/sessionmanager/kamevent.go b/sessionmanager/kamevent.go index b5f0d479b..2ec757dcf 100644 --- a/sessionmanager/kamevent.go +++ b/sessionmanager/kamevent.go @@ -228,11 +228,6 @@ func (kev KamEvent) GetCdrSource() string { return "KAMAILIO_" + kev.GetName() } -func (kev KamEvent) ComputeLcr() bool { - compute, _ := strconv.ParseBool(kev[utils.CGR_COMPUTELCR]) - return compute -} - func (kev KamEvent) MissingParameter() bool { var nullTime time.Time switch kev.GetName() { @@ -391,3 +386,11 @@ func (kev KamEvent) AsCallDescriptor() (*engine.CallDescriptor, error) { } return lcrReq.AsCallDescriptor() } + +func (kev KamEvent) ComputeLcr() bool { + if computeLcr, err := strconv.ParseBool(kev[utils.CGR_COMPUTELCR]); err != nil { + return false + } else { + return computeLcr + } +} diff --git a/sessionmanager/osipsevent.go b/sessionmanager/osipsevent.go index 63f8700db..6994c5025 100644 --- a/sessionmanager/osipsevent.go +++ b/sessionmanager/osipsevent.go @@ -20,6 +20,7 @@ package sessionmanager import ( "encoding/json" + "strconv" "strings" "time" @@ -298,3 +299,11 @@ func (osipsEv *OsipsEvent) updateDurationFromEvent(updatedOsipsEv *OsipsEvent) e osipsEv.osipsEvent.AttrValues[OSIPS_SIPCODE] = updatedOsipsEv.osipsEvent.AttrValues[OSIPS_SIPCODE] return nil } + +func (osipsEv *OsipsEvent) ComputeLcr() bool { + if computeLcr, err := strconv.ParseBool(osipsEv.osipsEvent.AttrValues[utils.CGR_COMPUTELCR]); err != nil { + return false + } else { + return computeLcr + } +} diff --git a/utils/consts.go b/utils/consts.go index 1c688c31a..59fcf6692 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -172,7 +172,6 @@ const ( LOG_CDR = "cdr_" LOG_MEDIATED_CDR = "mcd_" SESSION_MANAGER_SOURCE = "SMR" - MEDIATOR_SOURCE = "MED" CDRS_SOURCE = "CDRS" SCHED_SOURCE = "SCH" RATER_SOURCE = "RAT" @@ -189,6 +188,7 @@ const ( CGR_AUTHORIZE = "CGR_AUTHORIZE" CONFIG_DIR = "/etc/cgrates/" CGR_SUPPLIER = "cgr_supplier" + CGR_SUPPLIERS = "cgr_suppliers" DISCONNECT_CAUSE = "disconnect_cause" CGR_DISCONNECT_CAUSE = "cgr_disconnectcause" CGR_COMPUTELCR = "cgr_computelcr"