diff --git a/apier/v1/smgenericbirpcv1.go b/apier/v1/smgenericbirpcv1.go index 7ddd97055..caa93cb67 100644 --- a/apier/v1/smgenericbirpcv1.go +++ b/apier/v1/smgenericbirpcv1.go @@ -72,18 +72,22 @@ func (self *SMGenericBiRpcV1) GetLcrSuppliers(clnt *rpc2.Client, ev sessionmanag // Called on session start, returns the maximum number of seconds the session can last func (self *SMGenericBiRpcV1) SessionStart(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - if err := self.sm.SessionStart(ev, clnt); err != nil { + if minMaxUsage, err := self.sm.SessionStart(ev, clnt); err != nil { return utils.NewErrServerError(err) + } else { + *maxUsage = minMaxUsage.Seconds() } - return self.GetMaxUsage(clnt, ev, maxUsage) + return nil } // Interim updates, returns remaining duration from the rater func (self *SMGenericBiRpcV1) SessionUpdate(clnt *rpc2.Client, ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - if err := self.sm.SessionUpdate(ev, clnt); err != nil { + if minMaxUsage, err := self.sm.SessionUpdate(ev, clnt); err != nil { return utils.NewErrServerError(err) + } else { + *maxUsage = minMaxUsage.Seconds() } - return self.GetMaxUsage(clnt, ev, maxUsage) + return nil } // Called on session end, should stop debit loop diff --git a/apier/v1/smgenericv1.go b/apier/v1/smgenericv1.go index 5eb1ff76f..c95a6bd85 100644 --- a/apier/v1/smgenericv1.go +++ b/apier/v1/smgenericv1.go @@ -42,18 +42,22 @@ func (self *SMGenericV1) GetLcrSuppliers(ev sessionmanager.SMGenericEvent, suppl // Called on session start, returns the maximum number of seconds the session can last func (self *SMGenericV1) SessionStart(ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - if err := self.sm.SessionStart(ev, nil); err != nil { + if minMaxUsage, err := self.sm.SessionStart(ev, nil); err != nil { return utils.NewErrServerError(err) + } else { + *maxUsage = minMaxUsage.Seconds() } - return self.GetMaxUsage(ev, maxUsage) + return nil } // Interim updates, returns remaining duration from the rater func (self *SMGenericV1) SessionUpdate(ev sessionmanager.SMGenericEvent, maxUsage *float64) error { - if err := self.sm.SessionUpdate(ev, nil); err != nil { + if minMaxUsage, err := self.sm.SessionUpdate(ev, nil); err != nil { return utils.NewErrServerError(err) + } else { + *maxUsage = minMaxUsage.Seconds() } - return self.GetMaxUsage(ev, maxUsage) + return nil } // Called on session end, should stop debit loop diff --git a/sessionmanager/smg_event.go b/sessionmanager/smg_event.go index 57337c561..e32553522 100644 --- a/sessionmanager/smg_event.go +++ b/sessionmanager/smg_event.go @@ -144,14 +144,14 @@ func (self SMGenericEvent) GetEndTime(fieldName, timezone string) (time.Time, er if err != nil { return nilTime, err } - dur, err := self.GetDuration(utils.META_DEFAULT) + dur, err := self.GetUsage(utils.META_DEFAULT) if err != nil { return nilTime, err } return aTime.Add(dur), nil } -func (self SMGenericEvent) GetDuration(fieldName string) (time.Duration, error) { +func (self SMGenericEvent) GetUsage(fieldName string) (time.Duration, error) { if fieldName == utils.META_DEFAULT { fieldName = utils.USAGE } @@ -159,6 +159,18 @@ func (self SMGenericEvent) GetDuration(fieldName string) (time.Duration, error) return utils.ParseDurationWithSecs(result) } +func (self SMGenericEvent) GetMaxUsage(fieldName string, cfgMaxUsage time.Duration) (time.Duration, error) { + if fieldName == utils.META_DEFAULT { + fieldName = utils.MAX_USAGE + } + maxUsageStr, hasIt := self[fieldName] + if !hasIt { + return cfgMaxUsage, nil + } + result, _ := utils.ConvertIfaceToString(maxUsageStr) + return utils.ParseDurationWithSecs(result) +} + func (self SMGenericEvent) GetPdd(fieldName string) (time.Duration, error) { if fieldName == utils.META_DEFAULT { fieldName = utils.PDD @@ -262,7 +274,7 @@ func (self SMGenericEvent) ParseEventValue(rsrFld *utils.RSRField, timezone stri at, _ := self.GetAnswerTime(utils.META_DEFAULT, timezone) return rsrFld.ParseValue(at.String()) case utils.USAGE: - dur, _ := self.GetDuration(utils.META_DEFAULT) + dur, _ := self.GetUsage(utils.META_DEFAULT) return rsrFld.ParseValue(strconv.FormatInt(dur.Nanoseconds(), 10)) case utils.PDD: pdd, _ := self.GetPdd(utils.META_DEFAULT) @@ -303,7 +315,7 @@ func (self SMGenericEvent) AsStoredCdr(cfg *config.CGRConfig, timezone string) * storCdr.Destination = self.GetDestination(utils.META_DEFAULT) storCdr.SetupTime, _ = self.GetSetupTime(utils.META_DEFAULT, timezone) storCdr.AnswerTime, _ = self.GetAnswerTime(utils.META_DEFAULT, timezone) - storCdr.Usage, _ = self.GetDuration(utils.META_DEFAULT) + storCdr.Usage, _ = self.GetUsage(utils.META_DEFAULT) storCdr.Pdd, _ = self.GetPdd(utils.META_DEFAULT) storCdr.Supplier = self.GetSupplier(utils.META_DEFAULT) storCdr.DisconnectCause = self.GetDisconnectCause(utils.META_DEFAULT) diff --git a/sessionmanager/smg_event_test.go b/sessionmanager/smg_event_test.go index 1792cd5e5..debdd27a9 100644 --- a/sessionmanager/smg_event_test.go +++ b/sessionmanager/smg_event_test.go @@ -102,7 +102,7 @@ func TestSMGenericEventParseFields(t *testing.T) { } else if !et.Equal(time.Date(2015, 11, 9, 14, 23, 25, 0, time.UTC)) { t.Error("Unexpected: ", et) } - if dur, err := smGev.GetDuration(utils.META_DEFAULT); err != nil { + if dur, err := smGev.GetUsage(utils.META_DEFAULT); err != nil { t.Error(err) } else if dur != time.Duration(83)*time.Second { t.Error("Unexpected: ", dur) diff --git a/sessionmanager/smgeneric.go b/sessionmanager/smgeneric.go index 39854738c..9d0490fca 100644 --- a/sessionmanager/smgeneric.go +++ b/sessionmanager/smgeneric.go @@ -43,8 +43,8 @@ type SMGeneric struct { timezone string sessions map[string][]*SMGSession //Group sessions per sessionId, multiple runs based on derived charging extconns *SMGExternalConnections // Reference towards external connections manager - sessionsMux *sync.Mutex - guard *engine.GuardianLock // Used to lock on uuid + sessionsMux *sync.Mutex // Locks sessions map + guard *engine.GuardianLock // Used to lock on uuid } func (self *SMGeneric) indexSession(uuid string, s *SMGSession) { @@ -104,34 +104,28 @@ func (self *SMGeneric) sessionStart(evStart SMGenericEvent, connId string) error } // End a session from outside -func (self *SMGeneric) sessionEnd(evStop SMGenericEvent) error { - evUuid := evStop.GetUUID() +func (self *SMGeneric) sessionEnd(sessionId string, endTime time.Time) error { _, err := self.guard.Guard(func() (interface{}, error) { // Lock it on UUID level - ss := self.getSession(evUuid) + ss := self.getSession(sessionId) if len(ss) == 0 { // Not handled by us return nil, nil } - if !self.unindexSession(evUuid) { // Unreference it early so we avoid concurrency + if !self.unindexSession(sessionId) { // Unreference it early so we avoid concurrency return nil, nil // Did not find the session so no need to close it anymore } for idx, s := range ss { if idx == 0 && s.stopDebit != nil { close(s.stopDebit) // Stop automatic debits } - eTime, err := evStop.GetEndTime(utils.META_DEFAULT, self.timezone) - if err != nil { - utils.Logger.Err(fmt.Sprintf(" Could not get endTime from session: %s, runId: %s, error: %s", evUuid, s.runId, err.Error())) - continue + if err := s.close(endTime); err != nil { + utils.Logger.Err(fmt.Sprintf(" Could not close session: %s, runId: %s, error: %s", sessionId, s.runId, err.Error())) } - if err = s.close(eTime); err != nil { - utils.Logger.Err(fmt.Sprintf(" Could not close session: %s, runId: %s, error: %s", evUuid, s.runId, err.Error())) - } - if err = s.saveOperations(); err != nil { - utils.Logger.Err(fmt.Sprintf(" Could not save session: %s, runId: %s, error: %s", evUuid, s.runId, err.Error())) + if err := s.saveOperations(); err != nil { + utils.Logger.Err(fmt.Sprintf(" Could not save session: %s, runId: %s, error: %s", sessionId, s.runId, err.Error())) } } return nil, nil - }, time.Duration(2)*time.Second, evUuid) + }, time.Duration(2)*time.Second, sessionId) return err } @@ -164,28 +158,51 @@ func (self *SMGeneric) GetLcrSuppliers(gev SMGenericEvent, clnt *rpc2.Client) ([ return lcr.SuppliersSlice() } -// Called on session start -func (self *SMGeneric) SessionStart(gev SMGenericEvent, clnt *rpc2.Client) error { - if err := self.sessionStart(gev, getClientConnId(clnt)); err != nil { - return err +// Execute debits for usage/maxUsage +func (self *SMGeneric) SessionUpdate(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { + var minMaxUsage time.Duration + evMaxUsage, err := gev.GetMaxUsage(utils.META_DEFAULT, self.cgrCfg.MaxCallDuration) + if err != nil { + return nilDuration, err } - return nil + evUuid := gev.GetUUID() + for _, s := range self.getSession(evUuid) { + if maxDur, err := s.debit(evMaxUsage); err != nil { + return nilDuration, err + } else { + if maxDur < minMaxUsage { + minMaxUsage = maxDur + } + } + } + return minMaxUsage, nil } -// Interim updates -func (self *SMGeneric) SessionUpdate(gev SMGenericEvent, clnt *rpc2.Client) error { - return nil +// Called on session start +func (self *SMGeneric) SessionStart(gev SMGenericEvent, clnt *rpc2.Client) (time.Duration, error) { + if err := self.sessionStart(gev, getClientConnId(clnt)); err != nil { + return nilDuration, err + } + return self.SessionUpdate(gev, clnt) } // Called on session end, should stop debit loop func (self *SMGeneric) SessionEnd(gev SMGenericEvent, clnt *rpc2.Client) error { - if err := self.sessionEnd(gev); err != nil { + endTime, err := gev.GetEndTime(utils.META_DEFAULT, self.timezone) + if err != nil { + return err + } + if err := self.sessionEnd(gev.GetUUID(), endTime); err != nil { return err } return nil } func (self *SMGeneric) ProcessCdr(gev SMGenericEvent) error { + var reply string + if err := self.cdrsrv.ProcessCdr(gev.AsStoredCdr(self.cgrCfg, self.timezone), &reply); err != nil { + return err + } return nil } @@ -193,6 +210,10 @@ func (self *SMGeneric) Connect() error { return nil } +// System shutdown func (self *SMGeneric) Shutdown() error { + for ssId := range self.getSessions() { // Force sessions shutdown + self.sessionEnd(ssId, time.Now()) + } return nil } diff --git a/utils/consts.go b/utils/consts.go index ccd80bd6f..e36add38c 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -127,6 +127,7 @@ const ( COST_DETAILS = "CostDetails" RATED = "rated" RATED_FLD = "Rated" + MAX_USAGE = "MaxUsage" DEFAULT_RUNID = "*default" META_DEFAULT = "*default" STATIC_VALUE_PREFIX = "^"