diff --git a/data/conf/samples/tutlocal/cgrates.json b/data/conf/samples/tutlocal/cgrates.json index d4567a697..a0d4d04ce 100644 --- a/data/conf/samples/tutlocal/cgrates.json +++ b/data/conf/samples/tutlocal/cgrates.json @@ -13,12 +13,12 @@ "rater": { "enabled": true, // enable Rater service: "cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> - "users": "internal", + "pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234> + "users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234> }, "scheduler": { "enabled": true, // start Scheduler service: - "save_interval": "5s", }, "cdrs": { @@ -31,8 +31,15 @@ "enabled": true, // starts the cdrstats service: }, -"users": { - "enabled": true, +"pubsubs": { + "enabled": true, // starts PubSub service: . }, + +"users": { + "enabled": true, // starts User service: . + "indexes": ["Uuid"], // user profile field indexes +}, + + } diff --git a/data/tariffplans/tutorial/Users.csv b/data/tariffplans/tutorial/Users.csv index 75936aa6a..1805a970f 100644 --- a/data/tariffplans/tutorial/Users.csv +++ b/data/tariffplans/tutorial/Users.csv @@ -2,5 +2,7 @@ cgrates.org,1001,SysUserName,danb cgrates.org,1001,SysPassword,hisPass321 cgrates.org,1001,Cli,+4986517174963 +cgrates.org,1001,Uuid,388539dfd4f5cefee8f488b78c6c244b9e19138e cgrates.org,1002,SysUserName,rif cgrates.org,1002,RifAttr,RifVal +cgrates.org,1002,Uuid,27f37edec0670fa34cf79076b80ef5021e39c5b5 diff --git a/data/tutorials/fs_evsock/cgrates/etc/cgrates/cgrates.json b/data/tutorials/fs_evsock/cgrates/etc/cgrates/cgrates.json index 45a900faf..8b3d98aa9 100644 --- a/data/tutorials/fs_evsock/cgrates/etc/cgrates/cgrates.json +++ b/data/tutorials/fs_evsock/cgrates/etc/cgrates/cgrates.json @@ -10,6 +10,9 @@ "rater": { "enabled": true, // enable Rater service: "cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> + "historys": "internal", // address where to reach the history service, empty to disable history functionality: <""|internal|x.y.z.y:1234> + "pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234> + "users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234> }, @@ -24,6 +27,7 @@ "cdrstats": "internal", // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234> }, + "cdrstats": { "enabled": true, // starts the cdrstats service: }, @@ -61,7 +65,34 @@ {"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"}, ], "trailer_fields": [], // template of the exported trailer fields - } + }, + "customer_tpl": { + "cdr_format": "csv", // exported CDRs format + "field_separator": ";", + "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes) + "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems) + "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems) + "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT + "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding + "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents) + "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export + "mask_length": 0, // length of the destination suffix to be masked + "export_dir": "/tmp/cgr_fsevsock/cgrates/cdre", // path where the exported CDRs will be placed + "header_fields": [], // template of the exported header fields + "content_fields": [ // template of the exported content fields + {"tag": "CgrId", "cdr_field_id": "cgrid", "type": "cdrfield", "value": "cgrid"}, + {"tag":"AccId", "cdr_field_id": "accid", "type": "cdrfield", "value": "accid"}, + {"tag":"ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "reqtype"}, + {"tag":"Tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "tenant"}, + {"tag":"Category", "cdr_field_id": "category", "type": "cdrfield", "value": "category"}, + {"tag":"Subject", "cdr_field_id": "account", "type": "cdrfield", "value": "account"}, + {"tag":"Destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "~destination:s/^1(\\d+)/+$1/:s/^\\+(\\d+)/00$1/"}, + {"tag":"AnswerTime", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "answer_time", "layout": "2006-01-02T15:04:05Z07:00"}, + {"tag":"Usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "usage"}, + {"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"}, + ], + "trailer_fields": [], + }, }, @@ -77,14 +108,20 @@ }, -"history_server": { - "enabled": true, // starts History service: . +"historys": { + "enabled": true, // starts History service: . "history_dir": "/tmp/cgr_fsevsock/cgrates/history", // location on disk where to store history files. }, -"history_agent": { - "enabled": true, // starts History as a client: . +"pubsubs": { + "enabled": true, // starts PubSub service: . +}, + + +"users": { + "enabled": true, // starts User service: . + "indexes": ["Uuid"], // user profile field indexes }, diff --git a/data/tutorials/fs_evsock/freeswitch/etc/freeswitch_conf.tar.gz b/data/tutorials/fs_evsock/freeswitch/etc/freeswitch_conf.tar.gz index 7349bae0c..f62125994 100644 Binary files a/data/tutorials/fs_evsock/freeswitch/etc/freeswitch_conf.tar.gz and b/data/tutorials/fs_evsock/freeswitch/etc/freeswitch_conf.tar.gz differ diff --git a/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json b/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json index dc7d624a9..770a0ea06 100644 --- a/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json +++ b/data/tutorials/kamevapi/cgrates/etc/cgrates/cgrates.json @@ -7,66 +7,12 @@ // 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> + "cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> + "historys": "internal", // address where to reach the history service, empty to disable history functionality: <""|internal|x.y.z.y:1234> + "pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234> + "users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234> }, @@ -77,35 +23,13 @@ "cdrs": { "enabled": true, // start the CDR Server service: -// "extra_fields": [], // extra fields to store in CDRs for non-generic CDRs -// "store_cdrs": true, // store cdrs in storDb - "rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|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> -// "reconnects": 5, // number of reconnect attempts to rater or cdrs -// "cdr_replication":[], // replicate the raw CDR to a number of servers + "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> }, + "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 }, @@ -172,103 +96,28 @@ }, -//"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 -// "content_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": false, // starts SessionManager service: -// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013> -// "cdrs": "", // 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 -// "cdr_extra_fields": [], // extra fields to store in CDRs in case of processing them -// "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 -// "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": 5} -// ], -//}, - - "sm_kamailio": { "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 -// "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": 5} // 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": "", // 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: . +"historys": { + "enabled": true, // starts History service: . "history_dir": "/tmp/cgr_kamevapi/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: +"pubsubs": { + "enabled": true, // starts PubSub service: . }, -//"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 -//}, +"users": { + "enabled": true, // starts User service: . + "indexes": ["Uuid"], // user profile field indexes +}, + } diff --git a/data/tutorials/kamevapi/kamailio/etc/kamailio/kamailio-cgrates.cfg b/data/tutorials/kamevapi/kamailio/etc/kamailio/kamailio-cgrates.cfg index 954034144..9a837fd5e 100644 --- a/data/tutorials/kamevapi/kamailio/etc/kamailio/kamailio-cgrates.cfg +++ b/data/tutorials/kamevapi/kamailio/etc/kamailio/kamailio-cgrates.cfg @@ -103,7 +103,7 @@ route[CGR_LCR_REPLY] { route[CGR_SESSION_DISCONNECT] { json_get_field("$evapi(msg)", "HashEntry", "$var(HashEntry)"); json_get_field("$evapi(msg)", "HashId", "$var(HashId)"); - son_get_field("$evapi(msg)", "Reason", "$var(Reason)"); + json_get_field("$evapi(msg)", "Reason", "$var(Reason)"); jsonrpc_exec('{"jsonrpc":"2.0","id":1, "method":"dlg.end_dlg","params":[$(var(HashEntry){s.rm,"}),$(var(HashId){s.rm,"})]}'); #$jsonrpl($var(reply)); } diff --git a/data/tutorials/kamevapi/kamailio/etc/kamailio/kamailio.cfg b/data/tutorials/kamevapi/kamailio/etc/kamailio/kamailio.cfg index 6ae550efd..a61eea930 100644 --- a/data/tutorials/kamevapi/kamailio/etc/kamailio/kamailio.cfg +++ b/data/tutorials/kamevapi/kamailio/etc/kamailio/kamailio.cfg @@ -200,9 +200,14 @@ route[CGRATES_AUTH_REPLY] { sl_send_reply("503","CGR_ERROR"); exit; } - if $var(CgrMaxSessionTime) != -1 && !dlg_set_timeout("$var(CgrMaxSessionTime)") { - sl_send_reply("503","CGR_MAX_SESSION_TIME_ERROR"); - exit; + if $var(CgrMaxSessionTime) != -1 { + if $var(CgrMaxSessionTime) == 0 { // Not enough balance, do not allow the call to go through + sl_send_reply("403","Insufficient credit"); + exit; + } else if !dlg_set_timeout("$var(CgrMaxSessionTime)") { + sl_send_reply("503","CGR_MAX_SESSION_TIME_ERROR"); + exit; + } } if $var(CgrSuppliers) != "" { # Enforce the supplier variable to the first one received from CGRateS, more for testing purposes $dlg_var(cgrSupplier) = $(var(CgrSuppliers){s.select,0,,}); diff --git a/data/tutorials/osips_async/cgrates/etc/cgrates/cgrates.json b/data/tutorials/osips_async/cgrates/etc/cgrates/cgrates.json index 288c1ada6..fc500ef2b 100644 --- a/data/tutorials/osips_async/cgrates/etc/cgrates/cgrates.json +++ b/data/tutorials/osips_async/cgrates/etc/cgrates/cgrates.json @@ -10,6 +10,9 @@ "rater": { "enabled": true, // enable Rater service: "cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234> + "historys": "internal", // address where to reach the history service, empty to disable history functionality: <""|internal|x.y.z.y:1234> + "pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234> + "users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234> }, @@ -42,7 +45,7 @@ "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents) "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export "mask_length": 0, // length of the destination suffix to be masked - "export_dir": "/tmp/cgr_fsevsock/cgrates/cdre", // path where the exported CDRs will be placed + "export_dir": "/tmp/cgr_osipsasync/cgrates/cdre", // path where the exported CDRs will be placed "header_fields": [], // template of the exported header fields "content_fields": [ // template of the exported content fields {"tag": "CgrId", "cdr_field_id": "cgrid", "type": "cdrfield", "value": "cgrid"}, @@ -62,7 +65,34 @@ {"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"}, ], "trailer_fields": [], // template of the exported trailer fields - } + }, + "customer_tpl": { + "cdr_format": "csv", // exported CDRs format + "field_separator": ";", + "data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes) + "sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems) + "generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems) + "cost_multiply_factor": 1, // multiply cost before export, eg: add VAT + "cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding + "cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents) + "mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export + "mask_length": 0, // length of the destination suffix to be masked + "export_dir": "/tmp/cgr_osipsasync/cgrates/cdre", // path where the exported CDRs will be placed + "header_fields": [], // template of the exported header fields + "content_fields": [ // template of the exported content fields + {"tag": "CgrId", "cdr_field_id": "cgrid", "type": "cdrfield", "value": "cgrid"}, + {"tag":"AccId", "cdr_field_id": "accid", "type": "cdrfield", "value": "accid"}, + {"tag":"ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "reqtype"}, + {"tag":"Tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "tenant"}, + {"tag":"Category", "cdr_field_id": "category", "type": "cdrfield", "value": "category"}, + {"tag":"Subject", "cdr_field_id": "account", "type": "cdrfield", "value": "account"}, + {"tag":"Destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "~destination:s/^1(\\d+)/+$1/:s/^\\+(\\d+)/00$1/"}, + {"tag":"AnswerTime", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "answer_time", "layout": "2006-01-02T15:04:05Z07:00"}, + {"tag":"Usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "usage"}, + {"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"}, + ], + "trailer_fields": [], + }, }, @@ -78,15 +108,20 @@ }, -"history_server": { - "enabled": true, // starts History service: . +"historys": { + "enabled": true, // starts History service: . "history_dir": "/tmp/cgr_osipsasync/cgrates/history", // location on disk where to store history files. }, -"history_agent": { - "enabled": true, // starts History as a client: . - "server": "internal", // address where to reach the master history server: +"pubsubs": { + "enabled": true, // starts PubSub service: . +}, + + +"users": { + "enabled": true, // starts User service: . + "indexes": ["Uuid"], // user profile field indexes }, diff --git a/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg b/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg index bb8b57d66..c3a8f2990 100644 --- a/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg +++ b/data/tutorials/osips_async/opensips/etc/opensips/opensips.cfg @@ -91,22 +91,22 @@ modparam("db_flatstore", "single_file", 1) loadmodule "acc.so" modparam("acc", "detect_direction", 1) #modparam("acc", "cdr_flag", "CDR") -#modparam("acc", "evi_flag", "CDR") -#modparam("acc", "evi_missed_flag", "CDR") +modparam("acc", "evi_flag", "CDR") +modparam("acc", "evi_missed_flag", "CDR") modparam("acc", "evi_extra", "cgr_reqtype=$avp(cgr_reqtype); cgr_account=$avp(cgr_account); cgr_destination=$avp(cgr_destination); cgr_supplier=$avp(cgr_supplier); dialog_id=$DLG_did") -modparam("acc", "db_url", "flatstore:/tmp") -modparam("acc", "db_flag", "CDR") -modparam("acc", "db_missed_flag", "CDR") -modparam("acc", "db_table_missed_calls", "cgr_missed") -modparam("acc", "db_extra", "cgr_reqtype=$avp(cgr_reqtype); - cgr_account=$avp(cgr_account); - cgr_destination=$avp(cgr_destination); - cgr_supplier=$avp(cgr_supplier); - dialog_id=$DLG_did") +#modparam("acc", "db_url", "flatstore:/tmp") +#modparam("acc", "db_flag", "CDR") +#modparam("acc", "db_missed_flag", "CDR") +#modparam("acc", "db_table_missed_calls", "cgr_missed") +#modparam("acc", "db_extra", "cgr_reqtype=$avp(cgr_reqtype); +# cgr_account=$avp(cgr_account); +# cgr_destination=$avp(cgr_destination); +# cgr_supplier=$avp(cgr_supplier); +# dialog_id=$DLG_did") #### CfgUtils module loadmodule "cfgutils.so" @@ -358,9 +358,6 @@ route[location] { t_reply("404", "Not Found"); exit; } - append_branch(); - append_branch(); - setflag(CDR); } failure_route[missed_call] { diff --git a/engine/cdrs.go b/engine/cdrs.go index 5a0ad538e..39f3b1c9c 100644 --- a/engine/cdrs.go +++ b/engine/cdrs.go @@ -324,7 +324,6 @@ func (self *CdrServer) rateCDR(storedCdr *StoredCdr) error { func (self *CdrServer) replicateCdr(cdr *StoredCdr) error { Logger.Debug(fmt.Sprintf("replicateCdr cdr: %+v, configuration: %+v", cdr, self.cgrCfg.CDRSCdrReplication)) for _, rplCfg := range self.cgrCfg.CDRSCdrReplication { - Logger.Debug(fmt.Sprintf("Replicating CDR with configuration: %+v", rplCfg)) passesFilters := true for _, cdfFltr := range rplCfg.CdrFilter { if fltrPass, _ := cdr.PassesFieldFilter(cdfFltr); !fltrPass { diff --git a/engine/responder.go b/engine/responder.go index 7d89c10ae..5e860cee6 100644 --- a/engine/responder.go +++ b/engine/responder.go @@ -45,21 +45,25 @@ type Responder struct { ExitChan chan bool CdrSrv *CdrServer Stats StatsInterface + cnt int64 } /* RPC method thet provides the external RPC interface for getting the rating information. */ func (rs *Responder) GetCost(arg *CallDescriptor, reply *CallCost) (err error) { + rs.cnt += 1 if arg.Subject == "" { arg.Subject = arg.Account } + Logger.Debug(fmt.Sprintf("CD before load user profile: %+v, count: %d", arg, rs.cnt)) if upData, err := LoadUserProfile(arg, "ExtraFields"); err != nil { return err } else { udRcv := upData.(*CallDescriptor) *arg = *udRcv } + Logger.Debug(fmt.Sprintf("CD after load user profile: %+v, count: %d", arg, rs.cnt)) if rs.Bal != nil { r, e := rs.getCallCost(arg, "Responder.GetCost") *reply, err = *r, e diff --git a/engine/users.go b/engine/users.go index 0cf821c74..ab334a9ad 100644 --- a/engine/users.go +++ b/engine/users.go @@ -186,7 +186,7 @@ func (um *UserMap) GetUsers(up UserProfile, results *UserProfiles) error { } } - var candidates UserProfiles + candidates := make(UserProfiles, 0) // It should not return nil in case of no users but [] for key, values := range table { ponder := 0 tableUP := &UserProfile{ diff --git a/general_tests/tutorial_fs_calls_test.go b/general_tests/tutorial_fs_calls_test.go index b55d1dbfe..fbdb3c590 100644 --- a/general_tests/tutorial_fs_calls_test.go +++ b/general_tests/tutorial_fs_calls_test.go @@ -326,7 +326,7 @@ func TestTutFsCallsCdrs(t *testing.T) { if reply[0].ReqType != utils.META_PREPAID { t.Errorf("Unexpected ReqType for CDR: %+v", reply[0]) } - if reply[0].Usage != "65" { // Usage as seconds + if reply[0].Usage != "65" && reply[0].Usage != "66" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) } if reply[0].Cost != 0 { // Cost was not calculated @@ -386,7 +386,7 @@ func TestTutFsCallsCdrs(t *testing.T) { if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) } - if reply[0].Usage != "63" { // Usage as seconds + if reply[0].Usage != "63" && reply[0].Usage != "64" { // Usage as seconds, sometimes takes a second longer to disconnect t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) } } @@ -405,7 +405,7 @@ func TestTutFsCallsCdrs(t *testing.T) { if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) } - if reply[0].Usage != "62" { // Usage as seconds + if reply[0].Usage != "62" && reply[0].Usage != "63" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) } } @@ -424,7 +424,7 @@ func TestTutFsCallsCdrs(t *testing.T) { if reply[0].Destination != "1002" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) } - if reply[0].Usage != "64" { // Usage as seconds + if reply[0].Usage != "64" && reply[0].Usage != "65" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) } if reply[0].Cost == -1.0 { // Cost was not calculated @@ -446,7 +446,7 @@ func TestTutFsCallsCdrs(t *testing.T) { if reply[0].Destination != "1002" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) } - if reply[0].Usage != "66" { // Usage as seconds + if reply[0].Usage != "66" && 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 diff --git a/general_tests/tutorial_kam_calls_test.go b/general_tests/tutorial_kam_calls_test.go index 93d966410..a4dba99b3 100644 --- a/general_tests/tutorial_kam_calls_test.go +++ b/general_tests/tutorial_kam_calls_test.go @@ -595,7 +595,6 @@ func TestTutKamCallsStopPjsuaListener(t *testing.T) { time.Sleep(time.Duration(1) * time.Second) // Allow pjsua to finish it's tasks, eg un-REGISTER } -/* func TestTutKamCallsStopCgrEngine(t *testing.T) { if !*testCalls { return @@ -611,4 +610,3 @@ func TestTutKamCallsStopKam(t *testing.T) { } engine.KillProcName("kamailio", 1000) } -*/ diff --git a/general_tests/tutorial_local_test.go b/general_tests/tutorial_local_test.go index adebc3cf0..adc3c1cd8 100644 --- a/general_tests/tutorial_local_test.go +++ b/general_tests/tutorial_local_test.go @@ -182,6 +182,18 @@ func TestTutLocalGetCachedItemAge(t *testing.T) { */ } +func TestTutLocalGetUsers(t *testing.T) { + if !*testLocal { + return + } + var users engine.UserProfiles + if err := tutLocalRpc.Call("UsersV1.GetUsers", engine.UserProfile{}, &users); err != nil { + t.Error("Got error on UsersV1.GetUsers: ", err.Error()) + } else if len(users) != 2 { + t.Error("Calling UsersV1.GetUsers got users:", len(users)) + } +} + // Check call costs func TestTutLocalGetCosts(t *testing.T) { if !*testLocal { @@ -206,6 +218,24 @@ func TestTutLocalGetCosts(t *testing.T) { } else if cc.Cost != 0.6 { t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost) } + // Make sure that the same cost is returned via users aliasing + cd = engine.CallDescriptor{ + Direction: "*out", + Category: "call", + Tenant: utils.USERS, + Subject: utils.USERS, + Account: utils.USERS, + Destination: "1002", + DurationIndex: 0, + TimeStart: tStart, + TimeEnd: tEnd, + ExtraFields: map[string]string{"Uuid": "388539dfd4f5cefee8f488b78c6c244b9e19138e"}, + } + if err := tutLocalRpc.Call("Responder.GetCost", cd, &cc); err != nil { + t.Error("Got error on Responder.GetCost: ", err.Error()) + } else if cc.Cost != 0.6 { + t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost) + } tStart, _ = utils.ParseDate("2014-08-04T13:00:00Z") tEnd, _ = utils.ParseDate("2014-08-04T13:01:25Z") cd = engine.CallDescriptor{ diff --git a/general_tests/tutorial_osips_calls_test.go b/general_tests/tutorial_osips_calls_test.go index f3195522e..31b8b0b60 100644 --- a/general_tests/tutorial_osips_calls_test.go +++ b/general_tests/tutorial_osips_calls_test.go @@ -71,7 +71,6 @@ func TestTutOsipsCallsResetStorDb(t *testing.T) { } } -/* // start Kam server func TestTutOsipsCallsStartOsips(t *testing.T) { if !*testCalls { @@ -82,7 +81,6 @@ func TestTutOsipsCallsStartOsips(t *testing.T) { t.Fatal(err) } } -*/ // Start CGR Engine func TestTutOsipsCallsStartEngine(t *testing.T) { @@ -358,7 +356,7 @@ func TestTutOsipsCallsCdrs(t *testing.T) { if reply[0].Destination != "1001" { t.Errorf("Unexpected Destination for CDR: %+v", reply[0]) } - if reply[0].Usage != "62" { // Usage as seconds + if reply[0].Usage != "62" && reply[0].Usage != "63" { // Usage as seconds t.Errorf("Unexpected Usage for CDR: %+v", reply[0]) } } @@ -448,11 +446,9 @@ func TestTutOsipsCallsStopCgrEngine(t *testing.T) { } } -/* func TestTutOsipsCallsStopOpensips(t *testing.T) { if !*testCalls { return } engine.KillProcName("opensips", 100) } -*/ diff --git a/sessionmanager/fssessionmanager.go b/sessionmanager/fssessionmanager.go index 2a082891a..913cc0ab7 100644 --- a/sessionmanager/fssessionmanager.go +++ b/sessionmanager/fssessionmanager.go @@ -220,13 +220,15 @@ func (sm *FSSessionManager) onChannelPark(ev engine.Event, connId string) { if err := sm.rater.GetDerivedMaxSessionTime(ev.AsStoredCdr(), &maxCallDuration); err != nil { engine.Logger.Err(fmt.Sprintf(" Could not get max session time for %s, error: %s", ev.GetUUID(), err.Error())) } - maxCallDur := time.Duration(maxCallDuration) - if maxCallDur <= sm.cfg.MinCallDuration { - //engine.Logger.Info(fmt.Sprintf("Not enough credit for trasferring the call %s for %s.", ev.GetUUID(), cd.GetKey(cd.Subject))) - sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), INSUFFICIENT_FUNDS) - return + if maxCallDuration != -1 { // For calls different than unlimited, set limits + maxCallDur := time.Duration(maxCallDuration) + if maxCallDur <= sm.cfg.MinCallDuration { + //engine.Logger.Info(fmt.Sprintf("Not enough credit for trasferring the call %s for %s.", ev.GetUUID(), cd.GetKey(cd.Subject))) + sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), INSUFFICIENT_FUNDS) + return + } + sm.setMaxCallDuration(ev.GetUUID(), connId, maxCallDur) } - sm.setMaxCallDuration(ev.GetUUID(), connId, maxCallDur) // ComputeLcr if ev.ComputeLcr() { cd, err := fsev.AsCallDescriptor() @@ -341,7 +343,7 @@ func (sm *FSSessionManager) Shutdown() (err error) { continue } engine.Logger.Info(fmt.Sprintf(" Shutting down all sessions on connection id: %s", connId)) - if _, err = fSock.SendApiCmd("hupall MANAGER_REQUEST cgr_reqtype prepaid"); err != nil { + if _, err = fSock.SendApiCmd("hupall MANAGER_REQUEST cgr_reqtype *prepaid"); err != nil { engine.Logger.Err(fmt.Sprintf(" Error on calls shutdown: %s, connection id: %s", err.Error(), connId)) } }