mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
working on debit loop and mediator data
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user