mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Adding CGREvent
This commit is contained in:
@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
@@ -70,6 +69,15 @@ type SupplierEvent struct {
|
||||
Event map[string]interface{}
|
||||
}
|
||||
|
||||
func (se *SupplierEvent) CheckMandatoryFields(fldNames []string) error {
|
||||
for _, fldName := range fldNames {
|
||||
if _, has := se.Event[fldName]; !has {
|
||||
return utils.NewErrMandatoryIeMissing(fldName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AnswerTime returns the AnswerTime of SupplierEvent
|
||||
func (le *SupplierEvent) FieldAsString(fldName string) (val string, err error) {
|
||||
iface, has := le.Event[fldName]
|
||||
@@ -78,41 +86,47 @@ func (le *SupplierEvent) FieldAsString(fldName string) (val string, err error) {
|
||||
}
|
||||
val, canCast := utils.CastFieldIfToString(iface)
|
||||
if !canCast {
|
||||
return "", errors.New("cannot cast to string")
|
||||
return "", fmt.Errorf("cannot cast %s to string", fldName)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// AnswerTime returns the AnswerTime of SupplierEvent
|
||||
func (le *SupplierEvent) AnswerTime(timezone string) (at time.Time, err error) {
|
||||
atIf, has := le.Event[utils.ANSWER_TIME]
|
||||
// FieldAsTime returns the a field as Time instance
|
||||
func (le *SupplierEvent) FieldAsTime(fldName string, timezone string) (t time.Time, err error) {
|
||||
iface, has := le.Event[fldName]
|
||||
if !has {
|
||||
return at, utils.ErrNotFound
|
||||
err = utils.ErrNotFound
|
||||
return
|
||||
}
|
||||
if at, canCast := atIf.(time.Time); canCast {
|
||||
return at, nil
|
||||
var canCast bool
|
||||
if t, canCast = iface.(time.Time); canCast {
|
||||
return
|
||||
}
|
||||
atStr, canCast := atIf.(string)
|
||||
s, canCast := iface.(string)
|
||||
if !canCast {
|
||||
return at, errors.New("cannot cast to string")
|
||||
err = fmt.Errorf("cannot cast %s to string", fldName)
|
||||
return
|
||||
}
|
||||
return utils.ParseTimeDetectLayout(atStr, timezone)
|
||||
return utils.ParseTimeDetectLayout(s, timezone)
|
||||
}
|
||||
|
||||
// AnswerTime returns the AnswerTime of SupplierEvent
|
||||
func (le *SupplierEvent) Usage() (usage time.Duration, err error) {
|
||||
iface, has := le.Event[utils.USAGE]
|
||||
// FieldAsTime returns the a field as Time instance
|
||||
func (le *SupplierEvent) FieldAsDuration(fldName string) (d time.Duration, err error) {
|
||||
iface, has := le.Event[fldName]
|
||||
if !has {
|
||||
return 0, utils.ErrNotFound
|
||||
err = utils.ErrNotFound
|
||||
return
|
||||
}
|
||||
if usage, canCast := iface.(time.Duration); canCast {
|
||||
return usage, nil
|
||||
var canCast bool
|
||||
if d, canCast = iface.(time.Duration); canCast {
|
||||
return
|
||||
}
|
||||
usageStr, canCast := iface.(string)
|
||||
s, canCast := iface.(string)
|
||||
if !canCast {
|
||||
return 0, errors.New("cannot cast to string")
|
||||
err = fmt.Errorf("cannot cast %s to string", fldName)
|
||||
return
|
||||
}
|
||||
return utils.ParseDurationWithNanosecs(usageStr)
|
||||
return utils.ParseDurationWithNanosecs(s)
|
||||
}
|
||||
|
||||
// SuppliersSorter is the interface which needs to be implemented by supplier sorters
|
||||
@@ -158,7 +172,7 @@ func (ws *WeightSorter) SortSuppliers(prflID string,
|
||||
for i, s := range suppls {
|
||||
sortedSuppls.SortedSuppliers[i] = &SortedSupplier{
|
||||
SupplierID: s.ID,
|
||||
SortingData: map[string]interface{}{"Weight": s.Weight}}
|
||||
SortingData: map[string]interface{}{Weight: s.Weight}}
|
||||
}
|
||||
sortedSuppls.SortWeight()
|
||||
return
|
||||
|
||||
@@ -34,14 +34,20 @@ type LeastCostSorter struct {
|
||||
}
|
||||
|
||||
func (lcs *LeastCostSorter) SortSuppliers(prflID string,
|
||||
suppls []*Supplier, suplEv *SupplierEvent) (sortedSuppls *SortedSuppliers, err error) {
|
||||
suppls []*Supplier, ev *SupplierEvent) (sortedSuppls *SortedSuppliers, err error) {
|
||||
sortedSuppls = &SortedSuppliers{ProfileID: prflID,
|
||||
Sorting: lcs.sorting,
|
||||
SortedSuppliers: make([]*SortedSupplier, len(suppls))}
|
||||
for i, s := range suppls {
|
||||
cost, err := lcs.spS.costForEvent(ev, s.AccountIDs, s.RatingPlanIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sortedSuppls.SortedSuppliers[i] = &SortedSupplier{
|
||||
SupplierID: s.ID,
|
||||
SortingData: map[string]interface{}{"Weight": s.Weight}}
|
||||
SupplierID: s.ID,
|
||||
SortingData: map[string]interface{}{
|
||||
Weight: s.Weight,
|
||||
Cost: cost}}
|
||||
}
|
||||
sortedSuppls.SortCost()
|
||||
return
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
//"github.com/cgrates/cgrates/cache"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/guardian"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
@@ -130,7 +131,7 @@ func (spS *SupplierService) matchingSupplierProfilesForEvent(ev *SupplierEvent)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
aTime, err := ev.AnswerTime(spS.timezone)
|
||||
aTime, err := ev.FieldAsTime(utils.ANSWER_TIME, spS.timezone)
|
||||
if err != nil {
|
||||
if err == utils.ErrNotFound {
|
||||
aTime = time.Now()
|
||||
@@ -142,7 +143,8 @@ func (spS *SupplierService) matchingSupplierProfilesForEvent(ev *SupplierEvent)
|
||||
!lcrPrfl.ActivationInterval.IsActiveAtTime(aTime) { // not active
|
||||
continue
|
||||
}
|
||||
if pass, err := spS.filterS.PassFiltersForEvent(ev.Tenant, ev.Event, lcrPrfl.FilterIDs); err != nil {
|
||||
if pass, err := spS.filterS.PassFiltersForEvent(ev.Tenant,
|
||||
ev.Event, lcrPrfl.FilterIDs); err != nil {
|
||||
return nil, err
|
||||
} else if !pass {
|
||||
continue
|
||||
@@ -166,8 +168,50 @@ func (spS *SupplierService) matchingSupplierProfilesForEvent(ev *SupplierEvent)
|
||||
return
|
||||
}
|
||||
|
||||
// costForEvent will compute cost out of ratingPlanIDs for event
|
||||
func (spS *SupplierService) costForEvent(ev *SupplierEvent, rpIDs []string) (ec *EventCost, err error) {
|
||||
// costForEvent will compute cost out of accounts and rating plans for event
|
||||
func (spS *SupplierService) costForEvent(ev *SupplierEvent,
|
||||
acntIDs, rpIDs []string) (ec *EventCost, err error) {
|
||||
/*if err = ev.CheckMandatoryFields([]string{utils.ACCOUNT,
|
||||
utils.DESTINATION, utils.ANSWER_TIME, utils.USAGE}); err != nil {
|
||||
return
|
||||
}
|
||||
var acnt, subj, dst string
|
||||
if acnt, err = ev.FieldAsString(utils.ACCOUNT); err != nil {
|
||||
return
|
||||
}
|
||||
if subj, err = ev.FieldAsString(utils.ACCOUNT); err != nil {
|
||||
if err != utils.ErrNotFound {
|
||||
return
|
||||
}
|
||||
subj = acnt
|
||||
}
|
||||
if dst, err = ev.FieldAsString(utils.DESTINATION); err != nil {
|
||||
return
|
||||
}
|
||||
var aTime time.Time
|
||||
if aTime, err = ev.FieldAsTime(utils.ANSWER_TIME, spS.timezone); err != nil {
|
||||
return
|
||||
}
|
||||
var usage time.Duration
|
||||
if usage, err = ev.FieldAsDuration(utils.USAGE); err != nil {
|
||||
return
|
||||
}
|
||||
for i, rp := range rpIDs {
|
||||
rPrfl := &RatingProfile{
|
||||
Id: utils.ConcatenatedKey(utils.OUT,
|
||||
ev.Tenant, utils.MetaSuppliers, subj),
|
||||
RatingPlanActivations: RatingPlanActivations{
|
||||
&RatingPlanActivation{
|
||||
ActivationTime: aTime,
|
||||
RatingPlanId: rp,
|
||||
},
|
||||
},
|
||||
}
|
||||
// force cache set so it can be picked by calldescriptor for cost calculation
|
||||
cache.Set(utils.RATING_PROFILE_PREFIX+rPrfl.Id, rPrfl,
|
||||
true, utils.NonTransactional)
|
||||
}
|
||||
*/
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
91
utils/cgrevent.go
Normal file
91
utils/cgrevent.go
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOev. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CGREvent is a generic event processed by CGR services
|
||||
type CGREvent struct {
|
||||
Tenant string
|
||||
ID string
|
||||
Event map[string]interface{}
|
||||
}
|
||||
|
||||
func (ev *CGREvent) CheckMandatoryFields(fldNames []string) error {
|
||||
for _, fldName := range fldNames {
|
||||
if _, has := ev.Event[fldName]; !has {
|
||||
return NewErrMandatoryIeMissing(fldName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AnswerTime returns the AnswerTime of CGREvent
|
||||
func (ev *CGREvent) FieldAsString(fldName string) (val string, err error) {
|
||||
iface, has := ev.Event[fldName]
|
||||
if !has {
|
||||
return "", ErrNotFound
|
||||
}
|
||||
val, canCast := CastFieldIfToString(iface)
|
||||
if !canCast {
|
||||
return "", fmt.Errorf("cannot cast %s to string", fldName)
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// FieldAsTime returns the a field as Time instance
|
||||
func (ev *CGREvent) FieldAsTime(fldName string, timezone string) (t time.Time, err error) {
|
||||
iface, has := ev.Event[fldName]
|
||||
if !has {
|
||||
err = ErrNotFound
|
||||
return
|
||||
}
|
||||
var canCast bool
|
||||
if t, canCast = iface.(time.Time); canCast {
|
||||
return
|
||||
}
|
||||
s, canCast := iface.(string)
|
||||
if !canCast {
|
||||
err = fmt.Errorf("cannot cast %s to string", fldName)
|
||||
return
|
||||
}
|
||||
return ParseTimeDetectLayout(s, timezone)
|
||||
}
|
||||
|
||||
// FieldAsTime returns the a field as Time instance
|
||||
func (ev *CGREvent) FieldAsDuration(fldName string) (d time.Duration, err error) {
|
||||
iface, has := ev.Event[fldName]
|
||||
if !has {
|
||||
err = ErrNotFound
|
||||
return
|
||||
}
|
||||
var canCast bool
|
||||
if d, canCast = iface.(time.Duration); canCast {
|
||||
return
|
||||
}
|
||||
s, canCast := iface.(string)
|
||||
if !canCast {
|
||||
err = fmt.Errorf("cannot cast %s to string", fldName)
|
||||
return
|
||||
}
|
||||
return ParseDurationWithNanosecs(s)
|
||||
}
|
||||
Reference in New Issue
Block a user