diff --git a/cmd/cgr-loader/actions.go b/cmd/cgr-loader/actions.go
index e4ae4ff5b..24e5542b2 100644
--- a/cmd/cgr-loader/actions.go
+++ b/cmd/cgr-loader/actions.go
@@ -19,10 +19,8 @@ along with this program. If not, see
package main
import (
- "encoding/csv"
"github.com/cgrates/cgrates/timespans"
"log"
- "os"
"fmt"
"strconv"
)
@@ -34,16 +32,14 @@ var (
accountActions []*timespans.UserBalance
)
-func loadActions() {
- fp, err := os.Open(*actionsFn)
+func (csvr *CSVReader) loadActions(fn string) {
+ csvReader, fp, err := csvr.readerFunc(fn)
if err != nil {
- log.Printf("Could not open actions file: %v", err)
return
}
- defer fp.Close()
- csvReader := csv.NewReader(fp)
- csvReader.Comma = sep
- csvReader.TrailingComma = true
+ if fp != nil {
+ defer fp.Close()
+ }
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
tag := record[0]
if tag == "Tag" {
@@ -104,16 +100,14 @@ func loadActions() {
log.Print(actions)
}
-func loadActionTimings() {
- fp, err := os.Open(*actiontimingsFn)
+func (csvr *CSVReader) loadActionTimings(fn string) {
+ csvReader, fp, err := csvr.readerFunc(fn)
if err != nil {
- log.Printf("Could not open actions timings file: %v", err)
return
}
- defer fp.Close()
- csvReader := csv.NewReader(fp)
- csvReader.Comma = sep
- csvReader.TrailingComma = true
+ if fp != nil {
+ defer fp.Close()
+ }
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
tag := record[0]
if tag == "Tag" {
@@ -151,16 +145,14 @@ func loadActionTimings() {
log.Print(actionsTimings)
}
-func loadActionTriggers() {
- fp, err := os.Open(*actiontriggersFn)
+func (csvr *CSVReader) loadActionTriggers(fn string) {
+ csvReader, fp, err := csvr.readerFunc(fn)
if err != nil {
- log.Printf("Could not open destination balance actions file: %v", err)
return
}
- defer fp.Close()
- csvReader := csv.NewReader(fp)
- csvReader.Comma = sep
- csvReader.TrailingComma = true
+ if fp != nil {
+ defer fp.Close()
+ }
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
tag := record[0]
if tag == "Tag" {
@@ -190,16 +182,14 @@ func loadActionTriggers() {
log.Print(actionsTriggers)
}
-func loadAccountActions() {
- fp, err := os.Open(*accountactionsFn)
+func (csvr *CSVReader) loadAccountActions(fn string) {
+ csvReader, fp, err := csvr.readerFunc(fn)
if err != nil {
- log.Printf("Could not open account actions file: %v", err)
return
}
- defer fp.Close()
- csvReader := csv.NewReader(fp)
- csvReader.Comma = sep
- csvReader.TrailingComma = true
+ if fp != nil {
+ defer fp.Close()
+ }
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
if record[0] == "Tenant" {
continue
diff --git a/cmd/cgr-loader/cgr-loader.go b/cmd/cgr-loader/cgr-loader.go
index c9ce8a010..d9d43330b 100644
--- a/cmd/cgr-loader/cgr-loader.go
+++ b/cmd/cgr-loader/cgr-loader.go
@@ -22,12 +22,15 @@ import (
"flag"
"github.com/cgrates/cgrates/timespans"
"log"
+ "encoding/csv"
+ "strings"
+ "os"
)
var (
separator = flag.String("separator", ",", "Default field separator")
- redisserver = flag.String("redisserver", "127.0.0.1:6379", "redis server address (tcp:127.0.0.1:6379)")
- redisdb = flag.Int("rdb", 10, "redis database number (10)")
+ redissrv = flag.String("redissrv", "127.0.0.1:6379", "redis server address (tcp:127.0.0.1:6379)")
+ redisdb = flag.Int("redisdb", 10, "redis database number (10)")
redispass = flag.String("pass", "", "redis database password")
flush = flag.Bool("flush", false, "Flush the database before importing")
monthsFn = flag.String("month", "Months.csv", "Months file")
@@ -46,7 +49,7 @@ var (
)
func writeToDatabase() {
- storage, err := timespans.NewRedisStorage(*redisserver, *redisdb)
+ storage, err := timespans.NewRedisStorage(*redissrv, *redisdb)
if err != nil {
log.Fatalf("Could not open database connection: %v", err)
}
@@ -82,17 +85,40 @@ func writeToDatabase() {
}
}
+func openFileCSVReader(fn string) (csvReader *csv.Reader, fp *os.File, err error) {
+ fp, err = os.Open(fn)
+ if err != nil {
+ return
+ }
+ csvReader = csv.NewReader(fp)
+ csvReader.Comma = sep
+ csvReader.TrailingComma = true
+ return
+}
+
+func openStringCSVReader(data string) (csvReader *csv.Reader, fp *os.File, err error) {
+ csvReader = csv.NewReader(strings.NewReader(data))
+ csvReader.Comma = ','
+ csvReader.TrailingComma = true
+ return
+}
+
+type CSVReader struct {
+ readerFunc func(string) (*csv.Reader, *os.File, error)
+}
+
func main() {
flag.Parse()
sep = []rune(*separator)[0]
- loadDestinations()
- loadRates()
- loadTimings()
- loadRateTimings()
- loadRatingProfiles()
- loadActions()
- loadActionTimings()
- loadActionTriggers()
- loadAccountActions()
+ csvr := &CSVReader{openFileCSVReader}
+ csvr.loadDestinations(*destinationsFn)
+ csvr.loadRates(*ratesFn)
+ csvr.loadTimings(*timingsFn)
+ csvr.loadRateTimings(*ratetimingsFn)
+ csvr.loadRatingProfiles(*ratingprofilesFn)
+ csvr.loadActions(*actionsFn)
+ csvr.loadActionTimings(*actiontimingsFn)
+ csvr.loadActionTriggers(*actiontriggersFn)
+ csvr.loadAccountActions(*accountactionsFn)
writeToDatabase()
}
diff --git a/cmd/cgr-loader/loader_test.go b/cmd/cgr-loader/loader_test.go
new file mode 100644
index 000000000..476bc34ee
--- /dev/null
+++ b/cmd/cgr-loader/loader_test.go
@@ -0,0 +1,140 @@
+/*
+Rating system designed to be used in VoIP Carriers World
+Copyright (C) 2012 Radu Ioan Fericean
+
+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 main
+
+import (
+ "testing"
+)
+
+var (
+ dest = `
+Tag,Prefix
+NAT,0256
+NAT,0257
+NAT,0723
+RET,0723
+RET,0724
+`
+ rts = `
+P1,NAT,0,1,1
+P2,NAT,0,0.5,1
+`
+ ts = `
+WORKDAYS_00,*all,*all,1;2;3;4;5,00:00:00
+WORKDAYS_18,*all,*all,1;2;3;4;5,18:00:00
+WEEKENDS,*all,*all,6;7,00:00:00
+ONE_TIME_RUN,*none,*none,*none,*now
+`
+ rtts = `
+EVENING,P1,WORKDAYS_00,10
+EVENING,P2,WORKDAYS_18,10
+EVENING,P2,WEEKENDS,10
+`
+ rp = `
+vdf,0,OUT,rif,,EVENING,2012-01-01T00:00:00Z
+vdf,0,OUT,rif,,EVENING,2012-02-28T00:00:00Z
+vdf,0,OUT,minu,,EVENING,2012-01-01T00:00:00Z
+vdf,0,OUT,minu,,EVENING,2012-02-28T00:00:00Z
+`
+ a = `
+MINI,TOPUP,MINUTES,100,NAT,ABSOLUTE,0,10,10
+`
+ atms = `
+MORE_MINUTES,MINI,ONE_TIME_RUN,10
+`
+ atrs = `
+STANDARD_TRIGGER,MINUTES,10,GERMANY_O2,SOME_1,10
+STANDARD_TRIGGER,MINUTES,200,GERMANY,SOME_2,10
+`
+ accs = `
+vdf,minitsboy,OUT,MORE_MINUTES,STANDARD_TRIGGER
+`
+)
+
+func TestDestinations(t *testing.T) {
+ csvr := &CSVReader{openStringCSVReader}
+ csvr.loadDestinations(dest)
+ if len(destinations) != 2 {
+ t.Error("Failed to load destinations: ", destinations)
+ }
+}
+
+func TestRates(t *testing.T) {
+ csvr := &CSVReader{openStringCSVReader}
+ csvr.loadRates(rts)
+ if len(rates) != 2 {
+ t.Error("Failed to load rates: ", rates)
+ }
+}
+
+func TestTimimgs(t *testing.T) {
+ csvr := &CSVReader{openStringCSVReader}
+ csvr.loadTimings(ts)
+ if len(timings) != 4 {
+ t.Error("Failed to load timings: ", timings)
+ }
+}
+
+func TestRateTimings(t *testing.T) {
+ csvr := &CSVReader{openStringCSVReader}
+ csvr.loadRateTimings(rtts)
+ if len(activationPeriods) != 1 {
+ t.Error("Failed to load rate timings: ", activationPeriods)
+ }
+}
+
+func TestRatingProfiles(t *testing.T) {
+ csvr := &CSVReader{openStringCSVReader}
+ csvr.loadRatingProfiles(rp)
+ if len(ratingProfiles) != 4 {
+ t.Error("Failed to load rating profiles: ", ratingProfiles)
+ }
+}
+
+func TestActions(t *testing.T) {
+ csvr := &CSVReader{openStringCSVReader}
+ csvr.loadActions(a)
+ if len(actions) != 1 {
+ t.Error("Failed to load actions: ", actions)
+ }
+}
+
+func TestActionTimings(t *testing.T) {
+ csvr := &CSVReader{openStringCSVReader}
+ csvr.loadActionTimings(atms)
+ if len(actionsTimings) != 1 {
+ t.Error("Failed to load action timings: ", actionsTimings)
+ }
+}
+
+func TestActionTriggers(t *testing.T) {
+ csvr := &CSVReader{openStringCSVReader}
+ csvr.loadActionTriggers(atrs)
+ if len(actionsTriggers) != 1 {
+ t.Error("Failed to load action triggers: ", actionsTriggers)
+ }
+}
+
+func TestAccountActions(t *testing.T) {
+ csvr := &CSVReader{openStringCSVReader}
+ csvr.loadAccountActions(accs)
+ if len(accountActions) != 1 {
+ t.Error("Failed to load account actions: ", accountActions)
+ }
+}
diff --git a/cmd/cgr-loader/rates.go b/cmd/cgr-loader/rates.go
index a24fe4aae..e80395fdf 100644
--- a/cmd/cgr-loader/rates.go
+++ b/cmd/cgr-loader/rates.go
@@ -19,11 +19,9 @@ along with this program. If not, see
package main
import (
- "encoding/csv"
"github.com/cgrates/cgrates/timespans"
"log"
"fmt"
- "os"
"time"
)
@@ -36,17 +34,16 @@ var (
ratingProfiles = make(map[string]CallDescriptors)
)
-func loadDestinations() {
- fp, err := os.Open(*destinationsFn)
+func (csvr *CSVReader) loadDestinations(fn string) {
+ csvReader, fp, err := csvr.readerFunc(fn)
if err != nil {
- log.Printf("Could not open destinations file: %v", err)
return
}
- defer fp.Close()
- csvReader := csv.NewReader(fp)
- csvReader.Comma = sep
- csvReader.TrailingComma = true
+ if fp != nil {
+ defer fp.Close()
+ }
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
+
tag := record[0]
if tag == "Tag" {
// skip header line
@@ -63,20 +60,18 @@ func loadDestinations() {
dest = ×pans.Destination{Id: tag}
destinations = append(destinations, dest)
}
- dest.Prefixes = append(dest.Prefixes, record[1:]...)
+ dest.Prefixes = append(dest.Prefixes, record[1])
}
}
-func loadRates() {
- fp, err := os.Open(*ratesFn)
+func (csvr *CSVReader) loadRates(fn string) {
+ csvReader, fp, err := csvr.readerFunc(fn)
if err != nil {
- log.Printf("Could not open rates timing file: %v", err)
return
}
- defer fp.Close()
- csvReader := csv.NewReader(fp)
- csvReader.Comma = sep
- csvReader.TrailingComma = true
+ if fp != nil {
+ defer fp.Close()
+ }
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
tag := record[0]
if tag == "Tag" {
@@ -91,16 +86,14 @@ func loadRates() {
}
}
-func loadTimings() {
- fp, err := os.Open(*timingsFn)
+func (csvr *CSVReader) loadTimings(fn string) {
+ csvReader, fp, err := csvr.readerFunc(fn)
if err != nil {
- log.Printf("Could not open timings file: %v", err)
return
}
- defer fp.Close()
- csvReader := csv.NewReader(fp)
- csvReader.Comma = sep
- csvReader.TrailingComma = true
+ if fp != nil {
+ defer fp.Close()
+ }
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
tag := record[0]
if tag == "Tag" {
@@ -113,16 +106,14 @@ func loadTimings() {
}
}
-func loadRateTimings() {
- fp, err := os.Open(*ratetimingsFn)
+func (csvr *CSVReader) loadRateTimings(fn string) {
+ csvReader, fp, err := csvr.readerFunc(fn)
if err != nil {
- log.Printf("Could not open rates timings file: %v", err)
return
}
- defer fp.Close()
- csvReader := csv.NewReader(fp)
- csvReader.Comma = sep
- csvReader.TrailingComma = true
+ if fp != nil {
+ defer fp.Close()
+ }
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
tag := record[0]
if tag == "Tag" {
@@ -153,16 +144,14 @@ func loadRateTimings() {
}
}
-func loadRatingProfiles() {
- fp, err := os.Open(*ratingprofilesFn)
+func (csvr *CSVReader) loadRatingProfiles(fn string) {
+ csvReader, fp, err := csvr.readerFunc(fn)
if err != nil {
- log.Printf("Could not open destinations rates file: %v", err)
return
}
- defer fp.Close()
- csvReader := csv.NewReader(fp)
- csvReader.Comma = sep
- csvReader.TrailingComma = true
+ if fp != nil {
+ defer fp.Close()
+ }
for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() {
tag := record[0]
if tag == "Tenant" {
@@ -232,7 +221,7 @@ func loadRatingProfiles() {
log.Printf("Could not open destinations rates file: %v", err)
return
}
- defer fp.Close()
+ if fp != nil {defer fp.Close()}
csvReader := csv.NewReader(fp)
csvReader.Comma = sep
csvReader.TrailingComma = true
diff --git a/docs/apicalls.rst b/docs/apicalls.rst
index 537ebe74d..091630420 100644
--- a/docs/apicalls.rst
+++ b/docs/apicalls.rst
@@ -1,5 +1,47 @@
Api Calls
========
+The general API usage of the CGRateS involves creating a CallDescriptor structure sending it to the balancer via JSON/GOB RPC and getting a response from the balancer in form of a CallCost structure or a numeric value for requested information.
+
+CallDescriptor structure
+------------------------
+ - TOR int
+ - CstmId, Subject, DestinationPrefix string
+ - TimeStart, TimeEnd time.Time
+ - Amount float64
+TOR
+ Type Of Record, used to differentiate between various type of records
+CstmId
+ Customer Identification used for multi tenant databases
+Subject
+ Subject for this query
+DestinationPrefix
+ Destination prefix to be matched
+TimeStart, TimeEnd
+ The start end end of the call in question
+Amount
+ The amount requested in various API calls (e.g. DebitSMS amount)
+
+CallCost structure
+------------------
+ - TOR int
+ - CstmId, Subject, DestinationPrefix string
+ - Cost, ConnectFee float64
+ - Timespans []*TimeSpan
+TOR
+ Type Of Record, used to differentiate between various type of records (for query identification and confirmation)
+CstmId
+ Customer Identification used for multi tenant databases (for query identification and confirmation)
+Subject
+ Subject for this query (for query identification and confirmation)
+DestinationPrefix
+ Destination prefix to be matched (for query identification and confirmation)
+Cost
+ The requested cost
+ConnectFee
+ The requested connection cost
+Timespans
+ The timespans in witch the initial TimeStart-TimeEnd was split in for cost determination with all pricing and cost information attached.
+
As stated before the balancer (or the rater directly) can be accesed via json rpc.
The smallest python snippet to acces the CGRateS balancer is this:
diff --git a/docs/importing.rst b/docs/importing.rst
index cf487914a..d82cd84fc 100644
--- a/docs/importing.rst
+++ b/docs/importing.rst
@@ -1,3 +1,4 @@
+.. _`data-importing`:
Data importing
=============
diff --git a/docs/tutorial.rst b/docs/tutorial.rst
index b36497bac..35b24a787 100644
--- a/docs/tutorial.rst
+++ b/docs/tutorial.rst
@@ -1,58 +1,18 @@
Tutorial
========
-The general usage of the CGRateS involves creating a CallDescriptor structure sending it to the balancer via JSON RPC and getting a response from the balancer inf form of a CallCost structure or a numeric value for requested information.
The general steps to get up and running with CGRateS are:
-#. Create JSON files containing rates, budgets, tariff plans and destinations, see :ref:`data-importing`.
+#. Create CSV files containing the initial data for CGRateS, see :ref:`data-importing`.
#. Load the data in the databases using the loader tool.
-#. Start the balancer, see :ref:`running`.
+#. Start the balancer or rater and connect it to the call switch, see :ref:`running`.
#. Start one ore more raters.
-#. Make API calls to the balancer/rater.
-
-CallDescriptor structure
-------------------------
- - TOR int
- - CstmId, Subject, DestinationPrefix string
- - TimeStart, TimeEnd time.Time
- - Amount float64
-TOR
- Type Of Record, used to differentiate between various type of records
-CstmId
- Customer Identification used for multi tenant databases
-Subject
- Subject for this query
-DestinationPrefix
- Destination prefix to be matched
-TimeStart, TimeEnd
- The start end end of the call in question
-Amount
- The amount requested in various API calls (e.g. DebitSMS amount)
-
-CallCost structure
-------------------
- - TOR int
- - CstmId, Subject, DestinationPrefix string
- - Cost, ConnectFee float64
- - Timespans []*TimeSpan
-TOR
- Type Of Record, used to differentiate between various type of records (for query identification and confirmation)
-CstmId
- Customer Identification used for multi tenant databases (for query identification and confirmation)
-Subject
- Subject for this query (for query identification and confirmation)
-DestinationPrefix
- Destination prefix to be matched (for query identification and confirmation)
-Cost
- The requested cost
-ConnectFee
- The requested connection cost
-Timespans
- The timespans in witch the initial TimeStart-TimeEnd was split in for cost determination with all pricing and cost information attached.
+#. Make API calls to the balancer/rater or just let the session manager do the work.
Instalation
-----------
**Using packages**
+
**Using source**
After the go environment is installed_ and setup_ just issue the following commands:
@@ -62,8 +22,6 @@ After the go environment is installed_ and setup_ just issue the following comma
This will install the sources and compile all available tools
-After that navigate
-
.. _installed: http://golang.org/doc/install
.. _setup: http://golang.org/doc/code.html
@@ -79,9 +37,13 @@ cgr-balancer
rif@grace:~$ cgr-balancer --help
Usage of cgr-balancer:
- -httpapiaddr="127.0.0.1:8000": HTTP API server address (localhost:2002)
- -jsonrpcaddr="127.0.0.1:2001": JSON RPC server address (localhost:2001)
- -rateraddr="127.0.0.1:2000": Rater server address (localhost:2000)
+ -freeswitchpass="ClueCon": freeswitch address host:port
+ -freeswitchsrv="localhost:8021": freeswitch address host:port
+ -httpapiaddr="127.0.0.1:8000": Http API server address (localhost:2002)
+ -json=false: use JSON for RPC encoding
+ -jsonrpcaddr="127.0.0.1:2001": Json RPC server address (localhost:2001)
+ -rateraddr="127.0.0.1:2000": Rater server address (localhost:2000)
+
cgr-rater
The cgr-rater can be provided with the balancer server address and can be configured to listen to a specific interface and port.
@@ -90,8 +52,14 @@ cgr-rater
rif@grace:~$ cgr-rater --help
Usage of cgr-rater:
-balancer="127.0.0.1:2000": balancer address host:port
- -json=false: use json for rpc encoding
+ -freeswitch=false: connect to freeswitch server
+ -freeswitchpass="ClueCon": freeswitch address host:port
+ -freeswitchsrv="localhost:8021": freeswitch address host:port
+ -json=false: use JSON for RPC encoding
-listen="127.0.0.1:1234": listening address host:port
+ -redisdb=10: redis database number
+ -redissrv="127.0.0.1:6379": redis address host:port
+ -standalone=false: start standalone server (no balancer)
cgr-console
The cgr-console is a command line tool used to access the balancer (or the rater directly) to call all the API methods offered by CGRateS.
@@ -108,20 +76,6 @@ cgr-console
-tor=0: Type of record
-ts="2012-02-09T00:00:00Z": Time start
- rif@grace:~$ cgr-cgrates
- List of commands:
- getcost
- getmaxsessiontime
- debitbalance
- debitsms
- debitseconds
- addvolumediscountseconds
- resetvolumediscountseconds
- addrecievedcallseconds
- resetuserbudget
- status
-
-
cgr-loader
The loader is the most configurable tool because it has options for each of the three supported databases (kyoto, redis and mongodb).
Apart from that multi-database options it is quite easy to be used.
@@ -133,17 +87,50 @@ cgr-loader
rif@grace:~$ cgr-loader --help
Usage of cgr-loader:
- -apfile="ap.json": Activation Periods containing intervals file
- -destfile="dest.json": Destinations file
- -kyotofile="storage.kch": kyoto storage file (storage.kch)
- -mdb="test": mongo database name (test)
- -mongoserver="127.0.0.1:27017": mongo server address (127.0.0.1:27017)
+ -accountactions="AccountActions.csv": Account actions file
+ -actions="Actions.csv": Actions file
+ -actiontimings="ActionTimings.csv": Actions timings file
+ -actiontriggers="ActionTriggers.csv": Actions triggers file
+ -destinations="Destinations.csv": Destinations file
+ -flush=false: Flush the database before importing
+ -month="Months.csv": Months file
+ -monthdays="MonthDays.csv": Month days file
-pass="": redis database password
+ -rates="Rates.csv": Rates file
+ -ratetimings="RateTimings.csv": Rates timings file
+ -ratingprofiles="RatingProfiles.csv": Rating profiles file
-rdb=10: redis database number (10)
- -redisserver="tcp:127.0.0.1:6379": redis server address (tcp:127.0.0.1:6379)
- -storage="all": kyoto|redis|mongo
- -tpfile="tp.json": Tariff plans file
- -ubfile="ub.json": User budgets file
+ -redisserver="127.0.0.1:6379": redis server address (tcp:127.0.0.1:6379)
+ -separator=",": Default field separator
+ -timings="Timings.csv": Timings file
+ -weekdays="WeekDays.csv": Week days file
+rif@grace:~$ cgr-balancer --help
+Usage of cgr-balancer:
+ -freeswitchpass="ClueCon": freeswitch address host:port
+ -freeswitchsrv="localhost:8021": freeswitch address host:port
+ -httpapiaddr="127.0.0.1:8000": Http API server address (localhost:2002)
+ -json=false: use JSON for RPC encoding
+ -jsonrpcaddr="127.0.0.1:2001": Json RPC server address (localhost:2001)
+ -rateraddr="127.0.0.1:2000": Rater server address (localhost:2000)
+rif@grace:~$ cgr-sessionmanager --help
+Usage of cgr-sessionmanager:
+ -balancer="127.0.0.1:2000": balancer address host:port
+ -freeswitchpass="ClueCon": freeswitch address host:port
+ -freeswitchsrv="localhost:8021": freeswitch address host:port
+ -json=false: use JSON for RPC encoding
+ -redisdb=10: redis database number
+ -redissrv="127.0.0.1:6379": redis address host:port
+ -standalone=false: run standalone (run as a rater)
+
+rif@grace:~$ cgr-mediator --help
+Usage of cgr-mediator:
+ -dbname="cgrates": The name of the database to connect to.
+ -freeswitchcdr="Master.csv": Freeswitch Master CSV CDR file.
+ -host="localhost": The host to connect to. Values that start with / are for unix domain sockets.
+ -password="": The user's password.
+ -port="5432": The port to bind to.
+ -resultfile="out.csv": Generated file containing CDR and price info.
+ -user="": The user to sign in as.
\ No newline at end of file
diff --git a/timespans/destinations.go b/timespans/destinations.go
index 0e1c0b01f..31d840fd2 100644
--- a/timespans/destinations.go
+++ b/timespans/destinations.go
@@ -64,6 +64,15 @@ func (d *Destination) containsPrefix(prefix string) (bool, int) {
return false, 0
}
+func (d *Destination) String() (result string) {
+ result = d.Id + ": "
+ for _, p := range d.Prefixes {
+ result += p + ", "
+ }
+ result = strings.TrimRight(result, ", ")
+ return result
+}
+
func (d *Destination) store() (result string) {
for _, p := range d.Prefixes {
result += p + ","