SMG - SessionTTLUsage and SessionTTLLastUsed support

This commit is contained in:
DanB
2016-04-14 19:17:47 +02:00
parent d40a9193e6
commit 4107ac76d0
5 changed files with 109 additions and 40 deletions

View File

@@ -210,7 +210,9 @@ const CGRATES_CFG_JSON = `
"debit_interval": "0s", // 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
"session_ttl": "0s", // time after a session with no updates is terminated
"session_ttl": "0s", // time after a session with no updates is terminated, not defined by default
//"session_ttl_last_used": "", // tweak LastUsed for sessions timing-out, not defined by default
//"session_ttl_usage": "", // tweak Usage for sessions timing-out, not defined by default
},

View File

@@ -167,14 +167,16 @@ type CdrcJsonCfg struct {
// SM-Generic config section
type SmGenericJsonCfg struct {
Enabled *bool
Listen_bijson *string
Rater *string
Cdrs *string
Debit_interval *string
Min_call_duration *string
Max_call_duration *string
Session_ttl *string
Enabled *bool
Listen_bijson *string
Rater *string
Cdrs *string
Debit_interval *string
Min_call_duration *string
Max_call_duration *string
Session_ttl *string
Session_ttl_last_used *string
Session_ttl_usage *string
}
// SM-FreeSWITCH config section

View File

@@ -72,14 +72,16 @@ func (self *FsConnConfig) loadFromJsonCfg(jsnCfg *FsConnJsonCfg) error {
}
type SmGenericConfig struct {
Enabled bool
ListenBijson string
HaRater []*HaPoolConfig
HaCdrs []*HaPoolConfig
DebitInterval time.Duration
MinCallDuration time.Duration
MaxCallDuration time.Duration
SessionTTL time.Duration
Enabled bool
ListenBijson string
HaRater []*HaPoolConfig
HaCdrs []*HaPoolConfig
DebitInterval time.Duration
MinCallDuration time.Duration
MaxCallDuration time.Duration
SessionTTL time.Duration
SessionTTLLastUsed *time.Duration
SessionTTLUsage *time.Duration
}
func (self *SmGenericConfig) loadFromJsonCfg(jsnCfg *SmGenericJsonCfg) error {
@@ -119,6 +121,20 @@ func (self *SmGenericConfig) loadFromJsonCfg(jsnCfg *SmGenericJsonCfg) error {
return err
}
}
if jsnCfg.Session_ttl_last_used != nil {
if sessionTTLLastUsed, err := utils.ParseDurationWithSecs(*jsnCfg.Session_ttl_last_used); err != nil {
return err
} else {
self.SessionTTLLastUsed = &sessionTTLLastUsed
}
}
if jsnCfg.Session_ttl_usage != nil {
if sessionTTLUsage, err := utils.ParseDurationWithSecs(*jsnCfg.Session_ttl_usage); err != nil {
return err
} else {
self.SessionTTLUsage = &sessionTTLUsage
}
}
return nil
}

View File

@@ -51,34 +51,75 @@ type SMGeneric struct {
guard *engine.GuardianLock // Used to lock on uuid
}
type smgSessionTerminator struct {
timer *time.Timer
endChan chan bool
timer *time.Timer
endChan chan bool
ttl time.Duration
ttlLastUsed *time.Duration
ttlUsage *time.Duration
}
// Updates the timer for the session to a new ttl and terminate info
func (self *SMGeneric) resetTerminatorTimer(uuid string, ttl time.Duration, ttlLastUsed, ttlUsage *time.Duration) {
self.sessionsMux.RLock()
defer self.sessionsMux.RUnlock()
if st, found := self.sessionTerminators[uuid]; found {
if ttl != 0 {
st.ttl = ttl
}
if ttlLastUsed != nil {
st.ttlLastUsed = ttlLastUsed
}
if ttlUsage != nil {
st.ttlUsage = ttlUsage
}
st.timer.Reset(st.ttl)
}
}
// Called when a session timeouts
func (self *SMGeneric) ttlTerminate(s *SMGSession, tmtr *smgSessionTerminator) {
totalSessionUsage := s.TotalUsage() + tmtr.ttl
if tmtr.ttlUsage != nil {
totalSessionUsage = *tmtr.ttlUsage
}
if totalSessionUsage > s.TotalUsage() {
evUpdate := s.eventStart
diffSessionUsage := totalSessionUsage - s.TotalUsage()
evUpdate[utils.USAGE] = diffSessionUsage.Seconds() // Debit additionally
if tmtr.ttlLastUsed != nil {
evUpdate[utils.LastUsed] = tmtr.ttlLastUsed.Seconds()
}
self.SessionUpdate(evUpdate, nil)
}
self.sessionEnd(s.eventStart.GetUUID(), totalSessionUsage)
cdr := s.eventStart.AsStoredCdr(self.cgrCfg, self.timezone)
cdr.Usage = totalSessionUsage
var reply string
self.cdrsrv.ProcessCdr(cdr, &reply)
}
func (self *SMGeneric) indexSession(uuid string, s *SMGSession) {
self.sessionsMux.Lock()
self.sessions[uuid] = append(self.sessions[uuid], s)
if self.cgrCfg.SmGenericConfig.SessionTTL > 0 {
if self.cgrCfg.SmGenericConfig.SessionTTL != 0 {
if _, found := self.sessionTerminators[uuid]; !found {
timer := time.NewTimer(self.cgrCfg.SmGenericConfig.SessionTTL)
endChan := make(chan bool, 1)
terminator := &smgSessionTerminator{
timer: timer,
endChan: endChan,
ttl: self.cgrCfg.SmGenericConfig.SessionTTL,
}
self.sessionTerminators[uuid] = terminator
go func() {
select {
case <-timer.C:
totalUsage := s.TotalUsage() + self.cgrCfg.SmGenericConfig.SessionTTL
self.sessionEnd(uuid, totalUsage)
cdr := s.eventStart.AsStoredCdr(self.cgrCfg, self.timezone)
cdr.Usage = totalUsage
var reply string
self.cdrsrv.ProcessCdr(cdr, &reply)
self.ttlTerminate(s, terminator)
case <-endChan:
timer.Stop()
}
}()
self.sessionTerminators[uuid] = &smgSessionTerminator{
timer: timer,
endChan: endChan,
}
}
}
self.sessionsMux.Unlock()
@@ -125,15 +166,6 @@ func (self *SMGeneric) getSession(uuid string) []*SMGSession {
return self.sessions[uuid]
}
// Updates the timer for the session to a new ttl
func (self *SMGeneric) resetTerminatorTimer(uuid string) {
self.sessionsMux.RLock()
defer self.sessionsMux.RUnlock()
if st, found := self.sessionTerminators[uuid]; found {
st.timer.Reset(self.cgrCfg.SmGenericConfig.SessionTTL)
}
}
// Handle a new session, pass the connectionId so we can communicate on disconnect request
func (self *SMGeneric) sessionStart(evStart SMGenericEvent, connId string) error {
sessionId := evStart.GetUUID()
@@ -262,7 +294,21 @@ func (self *SMGeneric) SessionStart(gev SMGenericEvent, clnt *rpc2.Client) (time
// Execute debits for usage/maxUsage
func (self *SMGeneric) SessionUpdate(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) {
self.resetTerminatorTimer(gev.GetUUID())
ttl := time.Duration(0)
if ttlStr, err := gev.GetFieldAsString(utils.SessionTTL); err == nil {
ttl, _ = utils.ParseDurationWithSecs(ttlStr)
}
var ttlLastUsed *time.Duration
if ttlLastUsedStr, err := gev.GetFieldAsString(utils.SessionTTLLastUsed); err == nil {
ttlLastUsedParsed, _ := utils.ParseDurationWithSecs(ttlLastUsedStr)
ttlLastUsed = &ttlLastUsedParsed
}
var ttlUsage *time.Duration
if ttlUsageStr, err := gev.GetFieldAsString(utils.SessionTTLUsage); err == nil {
ttlUsageParsed, _ := utils.ParseDurationWithSecs(ttlUsageStr)
ttlUsage = &ttlUsageParsed
}
self.resetTerminatorTimer(gev.GetUUID(), ttl, ttlLastUsed, ttlUsage)
if initialID, err := gev.GetFieldAsString(utils.InitialOriginID); err == nil {
err := self.sessionRelocate(gev.GetUUID(), initialID)
if err == utils.ErrNotFound { // Session was already relocated, create a new session with this update

View File

@@ -278,6 +278,9 @@ const (
UpdatedAt = "UpdatedAt"
HandlerArgSep = "|"
FlagForceDuration = "fd"
SessionTTL = "SessionTTL"
SessionTTLLastUsed = "SessionTTLLastUsed"
SessionTTLUsage = "SessionTTLUsage"
)
var (