diff --git a/cmd/cgr-rater/cgr-rater.go b/cmd/cgr-rater/cgr-rater.go index a4bd9efc4..f812f7fc6 100644 --- a/cmd/cgr-rater/cgr-rater.go +++ b/cmd/cgr-rater/cgr-rater.go @@ -20,6 +20,7 @@ package main import ( "code.google.com/p/goconf/conf" + "database/sql" "flag" "fmt" "github.com/cgrates/cgrates/balancer" @@ -156,6 +157,28 @@ func listenToHttpRequests() { http.ListenAndServe(stats_listen, nil) } +func startSessionManager(responder *timespans.Responder) { + var connector sessionmanager.Connector + if sm_rater == INTERNAL { + connector = responder + } else { + var client *rpc.Client + var err error + if sm_json { + client, err = jsonrpc.Dial("tcp", sm_rater) + } else { + client, err = rpc.Dial("tcp", sm_rater) + } + if err != nil { + timespans.Logger.Crit(fmt.Sprintf("Could not connect to rater: %v", err)) + exitChan <- true + } + connector = &sessionmanager.RPCClientConnector{client} + } + sm := &sessionmanager.FSSessionManager{} + sm.Connect(&sessionmanager.SessionDelegate{connector}, sm_freeswitch_server, sm_freeswitch_pass) +} + func checkConfigSanity() { if sm_enabled && rater_enabled && rater_balancer != DISABLED { timespans.Logger.Crit("The session manager must not be enabled on a worker rater (change [rater]/balancer to disabled)!") @@ -213,30 +236,34 @@ func main() { } if sm_enabled { - go func() { - var connector sessionmanager.Connector - if sm_rater == INTERNAL { - connector = responder - } else { - var client *rpc.Client - if sm_json { - client, err = jsonrpc.Dial("tcp", sm_rater) - } else { - client, err = rpc.Dial("tcp", sm_rater) - } - if err != nil { - timespans.Logger.Crit(fmt.Sprintf("Could not connect to rater: %v", err)) - exitChan <- true - } - connector = &sessionmanager.RPCClientConnector{client} - } - sm := &sessionmanager.FSSessionManager{} - sm.Connect(&sessionmanager.SessionDelegate{connector}, sm_freeswitch_server, sm_freeswitch_pass) - }() + go startSessionManager(responder) } if mediator_enabled { - go startMediator() + db, err := sql.Open("postgres", fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=disable", mediator_host, mediator_port, mediator_db, mediator_user, mediator_password)) + //defer db.Close() + if err != nil { + timespans.Logger.Err(fmt.Sprintf("failed to open the database: %v", err)) + } + var connector sessionmanager.Connector + if sm_rater == INTERNAL { + connector = responder + } else { + var client *rpc.Client + var err error + if sm_json { + client, err = jsonrpc.Dial("tcp", sm_rater) + } else { + client, err = rpc.Dial("tcp", sm_rater) + } + if err != nil { + timespans.Logger.Crit(fmt.Sprintf("Could not connect to rater: %v", err)) + exitChan <- true + } + connector = &sessionmanager.RPCClientConnector{client} + } + m := &Mediator{connector, db} + _ = m } <-exitChan diff --git a/cmd/cgr-rater/mediator.go b/cmd/cgr-rater/mediator.go index 7600ca48d..bac27562e 100644 --- a/cmd/cgr-rater/mediator.go +++ b/cmd/cgr-rater/mediator.go @@ -25,68 +25,61 @@ import ( "flag" "fmt" _ "github.com/bmizerany/pq" + "github.com/cgrates/cgrates/sessionmanager" "github.com/cgrates/cgrates/timespans" "log" - "net/rpc/jsonrpc" "os" "time" ) -func readDbRecord(db *sql.DB, searchedUUID string) (cc *timespans.CallCost, timespansText string, err error) { - row := db.QueryRow(fmt.Sprintf("SELECT * FROM callcosts WHERE uuid='%s'", searchedUUID)) +type Mediator struct { + Connector sessionmanager.Connector + Db *sql.DB +} + +/*func readDbRecord(db *sql.DB, searchedUUID string) (cc *timespans.CallCost, timespansText string, err error) { + +}*/ + +func (m *Mediator) parseCSV() { + flag.Parse() + file, err := os.Open(mediator_cdr_file) + defer file.Close() + if err != nil { + log.Fatal(err) + } + csvReader := csv.NewReader(bufio.NewReader(file)) + + for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { + uuid := record[10] + _ = uuid + t, _ := time.Parse("2012-05-21 17:48:20", record[5]) + fmt.Println(t) + } +} + +func (m *Mediator) GetCostsFromDB(searchedUUID string) (cc *timespans.CallCost, timespansText string, err error) { + row := m.Db.QueryRow(fmt.Sprintf("SELECT * FROM callcosts WHERE uuid='%s'", searchedUUID)) var uuid string cc = ×pans.CallCost{} err = row.Scan(&uuid, &cc.Direction, &cc.Tenant, &cc.TOR, &cc.Subject, &cc.Destination, &cc.Cost, &cc.ConnectFee, ×pansText) return } -func startMediator() { - flag.Parse() - useDB := true - file, err := os.Open(mediator_cdr_file) - defer file.Close() - if err != nil { - log.Fatal(err) - } - db, err := sql.Open("postgres", fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=disable", mediator_host, mediator_port, mediator_db, mediator_user, mediator_password)) - defer db.Close() - if err != nil { - log.Printf("failed to open the database: %v", err) - useDB = false - } - csvReader := csv.NewReader(bufio.NewReader(file)) - client, err := jsonrpc.Dial("tcp", "localhost:2001") - useRPC := true - if err != nil { - log.Printf("Could not connect to rater server: %v!", err) - useRPC = false - } - for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { - uuid := record[10] - t, _ := time.Parse("2012-05-21 17:48:20", record[5]) - fmt.Println(t) - if useDB { - cc, timespansText, err := readDbRecord(db, uuid) - if err != nil && useRPC { - // try getting the price from the rater - - tenant := record[0] - subject := record[1] - dest := record[2] - t1, _ := time.Parse("2012-05-21 17:48:20", record[5]) - t2, _ := time.Parse("2012-05-21 17:48:20", record[6]) - cd := timespans.CallDescriptor{ - Direction: "OUT", - Tenant: tenant, - TOR: "0", - Subject: subject, - Destination: dest, - TimeStart: t1, - TimeEnd: t2} - client.Call("Responder.GetCost", cd, cc) - } - _ = timespansText - //log.Print(cc, timespansText) - } - } +func (m *Mediator) GetCostsFromRater(record []string) (cc *timespans.CallCost, err error) { + tenant := record[0] + subject := record[1] + dest := record[2] + t1, _ := time.Parse("2012-05-21 17:48:20", record[5]) + t2, _ := time.Parse("2012-05-21 17:48:20", record[6]) + cd := timespans.CallDescriptor{ + Direction: "OUT", + Tenant: tenant, + TOR: "0", + Subject: subject, + Destination: dest, + TimeStart: t1, + TimeEnd: t2} + err = m.Connector.GetCost(cd, cc) + return } diff --git a/sessionmanager/sessiondelegate.go b/sessionmanager/sessiondelegate.go index 01b5a3fb1..cec163877 100644 --- a/sessionmanager/sessiondelegate.go +++ b/sessionmanager/sessiondelegate.go @@ -30,6 +30,7 @@ const ( ) type Connector interface { + GetCost(timespans.CallDescriptor, *timespans.CallCost) error Debit(timespans.CallDescriptor, *timespans.CallCost) error DebitCents(timespans.CallDescriptor, *float64) error DebitSeconds(timespans.CallDescriptor, *float64) error @@ -40,6 +41,10 @@ type RPCClientConnector struct { Client *rpc.Client } +func (rcc *RPCClientConnector) GetCost(cd timespans.CallDescriptor, cc *timespans.CallCost) error { + return rcc.Client.Call("Responder.GetCost", cd, cc) +} + func (rcc *RPCClientConnector) Debit(cd timespans.CallDescriptor, cc *timespans.CallCost) error { return rcc.Client.Call("Responder.Debit", cd, cc) } diff --git a/timespans/action_timing.go b/timespans/action_timing.go index 0fbe59782..6e0502aab 100644 --- a/timespans/action_timing.go +++ b/timespans/action_timing.go @@ -112,16 +112,16 @@ MONTHS: if t.Equal(now) || t.After(now) { h, m, s := t.Clock() t = time.Date(now.Year(), now.Month(), t.Day(), h, m, s, 0, time.Local) - return + goto YEARS } - if x+1 < len(i.Months) { // today was found in the list, jump to the next grater day + if x+1 < len(i.Months) { // this month was found in the list so jump to next available month m = i.Months[x+1] // reset the monthday if i.MonthDays != nil { t = time.Date(t.Year(), t.Month(), i.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) } } - } else { // today was not found in the list, x is the first greater day + } else { // this month was not found in the list, x is the first greater month m = i.Months[x] // reset the monthday if i.MonthDays != nil { @@ -132,6 +132,45 @@ MONTHS: h, min, s := t.Clock() t = time.Date(now.Year(), m, t.Day(), h, min, s, 0, time.Local) } +YEARS: + if i.Years != nil && len(i.Years) > 0 { + i.Years.Sort() + now := time.Now() + x := sort.Search(len(i.Years), func(x int) bool { return i.Years[x] >= now.Year() }) + y = i.Years[0] + if x < len(i.Years) { + if i.Years[x] == now.Year() { + if t.Equal(now) || t.After(now) { + h, m, s := t.Clock() + t = time.Date(now.Year(), t.Month(), t.Day(), h, m, s, 0, time.Local) + return + } + if x+1 < len(i.Years) { // this year was found in the list so jump to next available year + y = i.Years[x+1] + // reset the month + if i.Months != nil { + t = time.Date(t.Year(), i.Months[0], t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location()) + } + // reset the monthday + if i.MonthDays != nil { + t = time.Date(t.Year(), t.Month(), i.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) + } + } + } else { // this year was not found in the list, x is the first greater year + y = i.Years[x] + // reset the month + if i.Months != nil { + t = time.Date(t.Year(), i.Months[0], t.Day(), t.Hour(), t.Minute(), t.Second(), 0, t.Location()) + } + // reset the monthday + if i.MonthDays != nil { + t = time.Date(t.Year(), t.Month(), i.MonthDays[0], t.Hour(), t.Minute(), t.Second(), 0, t.Location()) + } + } + } + h, min, s := t.Clock() + t = time.Date(y, t.Month(), t.Day(), h, min, s, 0, time.Local) + } return } diff --git a/timespans/actions_test.go b/timespans/actions_test.go index 309838c73..ad536271b 100644 --- a/timespans/actions_test.go +++ b/timespans/actions_test.go @@ -225,7 +225,7 @@ func TestActionTimingHourMonthdaysMonths(t *testing.T) { } } -func TestActionTimingFisrtOfTheMonth(t *testing.T) { +func TestActionTimingFirstOfTheMonth(t *testing.T) { now := time.Now() y, m, _ := now.Date() nextMonth := time.Date(y, m+1, 1, 0, 0, 0, 0, time.Local) @@ -241,6 +241,118 @@ func TestActionTimingFisrtOfTheMonth(t *testing.T) { } } +func TestActionTimingOnlyYears(t *testing.T) { + now := time.Now() + y, m, d := now.Date() + nextYear := time.Date(y+1, m, d, 0, 0, 0, 0, time.Local) + at := &ActionTiming{Timing: &Interval{Years: Years{now.Year(), nextYear.Year()}}} + st := at.GetNextStartTime() + expected := time.Date(nextYear.Year(), 1, 1, 0, 0, 0, 0, time.Local) + if !st.Equal(expected) { + t.Errorf("Expected %v was %v", expected, st) + } +} + +func TestActionTimingHourYears(t *testing.T) { + now := time.Now() + y, m, d := now.Date() + testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local) + nextYear := time.Date(y+1, m, d, 0, 0, 0, 0, time.Local) + year := now.Year() + if now.After(testTime) { + year = nextYear.Year() + } + at := &ActionTiming{Timing: &Interval{Years: Years{now.Year(), nextYear.Year()}, StartTime: "10:01:00"}} + st := at.GetNextStartTime() + expected := time.Date(year, m, d, 10, 1, 0, 0, time.Local) + if !st.Equal(expected) { + t.Errorf("Expected %v was %v", expected, st) + } +} + +func TestActionTimingHourMonthdaysYear(t *testing.T) { + now := time.Now() + y, m, d := now.Date() + testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local) + nextYear := time.Date(y+1, m, d, 0, 0, 0, 0, time.Local) + tomorrow := time.Date(y, m, d+1, 0, 0, 0, 0, time.Local) + day := now.Day() + if now.After(testTime) { + day = tomorrow.Day() + } + nextDay := time.Date(y, m, day, 10, 1, 0, 0, time.Local) + year := now.Year() + if nextDay.Before(now) { + if now.After(testTime) { + year = nextYear.Year() + } + } + at := &ActionTiming{Timing: &Interval{ + Years: Years{now.Year(), nextYear.Year()}, + MonthDays: MonthDays{now.Day(), tomorrow.Day()}, + StartTime: "10:01:00", + }} + st := at.GetNextStartTime() + expected := time.Date(year, m, day, 10, 1, 0, 0, time.Local) + if !st.Equal(expected) { + t.Errorf("Expected %v was %v", expected, st) + } +} + +func TestActionTimingHourMonthdaysMonthYear(t *testing.T) { + now := time.Now() + y, m, d := now.Date() + testTime := time.Date(y, m, d, 10, 1, 0, 0, time.Local) + nextYear := time.Date(y+1, m, d, 0, 0, 0, 0, time.Local) + nextMonth := time.Date(y, m+1, d, 0, 0, 0, 0, time.Local) + tomorrow := time.Date(y, m, d+1, 0, 0, 0, 0, time.Local) + day := now.Day() + if now.After(testTime) { + day = tomorrow.Day() + } + nextDay := time.Date(y, m, day, 10, 1, 0, 0, time.Local) + month := now.Month() + if nextDay.Before(now) { + if now.After(testTime) { + month = nextMonth.Month() + } + } + year := now.Year() + if nextDay.Before(now) { + if now.After(testTime) { + year = nextYear.Year() + } + } + at := &ActionTiming{Timing: &Interval{ + Years: Years{now.Year(), nextYear.Year()}, + Months: Months{now.Month(), nextMonth.Month()}, + MonthDays: MonthDays{now.Day(), tomorrow.Day()}, + StartTime: "10:01:00", + }} + st := at.GetNextStartTime() + expected := time.Date(year, month, day, 10, 1, 0, 0, time.Local) + if !st.Equal(expected) { + t.Errorf("Expected %v was %v", expected, st) + } +} + +func TestActionTimingFirstOfTheYear(t *testing.T) { + now := time.Now() + y, _, _ := now.Date() + nextYear := time.Date(y+1, 1, 1, 0, 0, 0, 0, time.Local) + at := &ActionTiming{Timing: &Interval{ + Years: Years{nextYear.Year()}, + Months: Months{time.January}, + MonthDays: MonthDays{1}, + StartTime: "00:00:00", + }} + st := at.GetNextStartTime() + expected := nextYear + if !st.Equal(expected) { + t.Errorf("Expected %v was %v", expected, st) + } +} + func TestActionTimingIsOneTimeRunNoInterval(t *testing.T) { at := &ActionTiming{Timing: &Interval{StartTime: ASAP}} if !at.CheckForASAP() {