From e6b291d359877a31f7c3ddc492710ccad769d782 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 15 May 2012 14:45:09 +0300 Subject: [PATCH] working on debit loop and mediator data --- sessionmanager/session.go | 52 ++++++++++++------------------- sessionmanager/session_test.go | 15 +-------- sessionmanager/sessiondelegate.go | 31 ++++++++++++------ timespans/calldesc.go | 15 +++++++++ timespans/timespans.go | 1 + 5 files changed, 59 insertions(+), 55 deletions(-) diff --git a/sessionmanager/session.go b/sessionmanager/session.go index 324e0ab7c..5742c6f96 100644 --- a/sessionmanager/session.go +++ b/sessionmanager/session.go @@ -25,17 +25,14 @@ import ( "time" ) -const ( - DEBIT_PERIOD = 10 * time.Second -) - // Session type holding the call information fields, a session delegate for specific // actions and a channel to signal end of the debit loop. type Session struct { - uuid, cstmId, subject, destination string - startTime time.Time // destination: startTime - sessionDelegate SessionDelegate - stopDebit chan byte + uuid string + callDescriptor *timespans.CallDescriptor + sessionDelegate SessionDelegate + stopDebit chan byte + CallCosts []*timespans.CallCost } // Creates a new session and starts the debit loop @@ -45,12 +42,13 @@ func NewSession(ev *Event, ed SessionDelegate) (s *Session) { log.Print("Error parsing answer event start time, using time.Now!") startTime = time.Now() } + cd := ×pans.CallDescriptor{CstmId: ev.Fields[CSTMID], + Subject: ev.Fields[SUBJECT], + DestinationPrefix: ev.Fields[DESTINATION], + TimeStart: startTime} s = &Session{uuid: ev.Fields[UUID], - cstmId: ev.Fields[CSTMID], - subject: ev.Fields[SUBJECT], - destination: ev.Fields[DESTINATION], - startTime: startTime, - stopDebit: make(chan byte)} + callDescriptor: cd, + stopDebit: make(chan byte)} s.sessionDelegate = ed go s.startDebitLoop() return @@ -58,20 +56,25 @@ func NewSession(ev *Event, ed SessionDelegate) (s *Session) { // the debit loop method (to be stoped by sending somenting on stopDebit channel) func (s *Session) startDebitLoop() { + nextCd := *s.callDescriptor for { select { case <-s.stopDebit: return default: } - s.sessionDelegate.LoopAction() - time.Sleep(DEBIT_PERIOD) + if nextCd.TimeEnd == s.callDescriptor.TimeEnd { // first time use the session start time + nextCd.TimeStart = time.Now() + } + nextCd.TimeEnd = time.Now().Add(s.sessionDelegate.GetDebitPeriod()) + s.sessionDelegate.LoopAction(s, &nextCd) + time.Sleep(s.sessionDelegate.GetDebitPeriod()) } } // Returns the session duration till the specified time func (s *Session) getSessionDurationFrom(now time.Time) (d time.Duration) { - seconds := now.Sub(s.startTime).Seconds() + seconds := now.Sub(s.callDescriptor.TimeStart).Seconds() d, err := time.ParseDuration(fmt.Sprintf("%ds", int(seconds))) if err != nil { log.Printf("Cannot parse session duration %v", seconds) @@ -84,23 +87,8 @@ func (s *Session) GetSessionDuration() time.Duration { return s.getSessionDurationFrom(time.Now()) } -// Returns the session cost till the specified time -func (s *Session) getSessionCostFrom(now time.Time) (callCosts *timespans.CallCost, err error) { - cd := ×pans.CallDescriptor{TOR: 1, CstmId: s.cstmId, Subject: s.subject, DestinationPrefix: s.destination, TimeStart: s.startTime, TimeEnd: now} - cd.SetStorageGetter(s.sessionDelegate.GetStorageGetter()) - callCosts, err = cd.GetCost() - if err != nil { - log.Printf("Error getting call cost for session %v", s) - } - return -} - -// Returns the session duration till now -func (s *Session) GetSessionCost() (callCosts *timespans.CallCost, err error) { - return s.getSessionCostFrom(time.Now()) -} - // Stops the debit loop func (s *Session) Close() { s.stopDebit <- 1 + s.callDescriptor.TimeEnd = time.Now() } diff --git a/sessionmanager/session_test.go b/sessionmanager/session_test.go index e342fde6e..8645ef960 100644 --- a/sessionmanager/session_test.go +++ b/sessionmanager/session_test.go @@ -55,20 +55,7 @@ func TestSessionDurationSingle(t *testing.T) { s := NewSession(newEvent, new(DirectSessionDelegate)) defer s.Close() twoSeconds, _ := time.ParseDuration("2s") - if d := s.getSessionDurationFrom(s.startTime.Add(twoSeconds)); d.Seconds() < 2 || d.Seconds() > 3 { + if d := s.getSessionDurationFrom(s.callDescriptor.TimeStart.Add(twoSeconds)); d.Seconds() < 2 || d.Seconds() > 3 { t.Errorf("Wrong session duration %v", d) } } - -func TestSessionCostSingle(t *testing.T) { - s := NewSession(newEvent, new(DirectSessionDelegate)) - defer s.Close() - twoSeconds, _ := time.ParseDuration("60s") - if cc, err := s.getSessionCostFrom(s.startTime.Add(twoSeconds)); err != nil { - t.Errorf("Get cost returned error %v", err) - } else { - if cc.Cost < 1 || cc.Cost > 1.1 { - t.Errorf("Expected %v got %v", "between 1 and 1.1", cc.Cost) - } - } -} diff --git a/sessionmanager/sessiondelegate.go b/sessionmanager/sessiondelegate.go index 586369bbc..6428ca216 100644 --- a/sessionmanager/sessiondelegate.go +++ b/sessionmanager/sessiondelegate.go @@ -21,6 +21,11 @@ package sessionmanager import ( "github.com/rif/cgrates/timespans" "log" + "time" +) + +const ( + DEBIT_PERIOD = 10 * time.Second ) var ( @@ -37,9 +42,9 @@ type SessionDelegate interface { // Called on freeswitch's hangup event OnChannelHangupComplete(*Event, *Session) // The method to be called inside the debit loop - LoopAction() + LoopAction(*Session, *timespans.CallDescriptor) // Returns a storage getter for the sesssion to use - GetStorageGetter() timespans.StorageGetter + GetDebitPeriod() time.Duration } // Sample SessionDelegate calling the timespans methods directly @@ -57,12 +62,20 @@ func (dsd *DirectSessionDelegate) OnChannelHangupComplete(ev *Event, s *Session) log.Print("direct hangup") } -func (dsd *DirectSessionDelegate) LoopAction() { - log.Print("Direct debit") +func (dsd *DirectSessionDelegate) LoopAction(s *Session, cd *timespans.CallDescriptor) { + cc, err := cd.Debit() + if err != nil { + log.Printf("Could not complete debit opperation: %v", err) + } + s.CallCosts = append(s.CallCosts, cc) + cd.Amount = DEBIT_PERIOD.Seconds() + if remainingSeconds, err := cd.GetMaxSessionTime(); remainingSeconds < DEBIT_PERIOD.Seconds() || err != nil { + log.Print("Not enough money for another debit period!") + } } -func (dsd *DirectSessionDelegate) GetStorageGetter() timespans.StorageGetter { - return storageGetter +func (dsd *DirectSessionDelegate) GetDebitPeriod() time.Duration { + return DEBIT_PERIOD } // Sample SessionDelegate calling the timespans methods through the RPC interface @@ -80,10 +93,10 @@ func (rsd *RPCSessionDelegate) OnChannelHangupComplete(ev *Event, s *Session) { log.Print("rpc hangup") } -func (rsd *RPCSessionDelegate) LoopAction() { +func (rsd *RPCSessionDelegate) LoopAction(s *Session, cd *timespans.CallDescriptor) { log.Print("Rpc debit") } -func (rsd *RPCSessionDelegate) GetStorageGetter() timespans.StorageGetter { - return storageGetter +func (rsd *RPCSessionDelegate) GetDebitPeriod() time.Duration { + return DEBIT_PERIOD } diff --git a/timespans/calldesc.go b/timespans/calldesc.go index 41b11c8b4..a9041e845 100644 --- a/timespans/calldesc.go +++ b/timespans/calldesc.go @@ -295,6 +295,21 @@ func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) { return 0, nil } +// Interface method used to add/substract an amount of cents or bonus seconds (as returned by GetCost method) +// from user's money budget. +func (cd *CallDescriptor) Debit() (cc *CallCost, err error) { + cc, err = cd.GetCost() + if userBudget, err := cd.getUserBudget(); err == nil && userBudget != nil { + if cc.Cost != 0 || cc.ConnectFee != 0 { + userBudget.debitMoneyBudget(cd.storageGetter, cc.Cost+cc.ConnectFee) + } + for _, ts := range cc.Timespans { + userBudget.debitMinutesBudget(cd.storageGetter, ts.MinuteInfo.Quantity, cd.DestinationPrefix) + } + } + return +} + /* Interface method used to add/substract an amount of cents from user's money budget. The amount filed has to be filled in call descriptor. diff --git a/timespans/timespans.go b/timespans/timespans.go index 88862f710..af3011c61 100644 --- a/timespans/timespans.go +++ b/timespans/timespans.go @@ -34,6 +34,7 @@ type TimeSpan struct { MinuteInfo *MinuteInfo } +// Holds the bonus minute information related to a specified timespan type MinuteInfo struct { DestinationId string Quantity float64