mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-12 10:36:24 +05:00
cond lang refactor for better design
This commit is contained in:
@@ -77,3 +77,101 @@ func (self *ApierV2) GetAccount(attr *utils.AttrGetAccount, reply *engine.Accoun
|
||||
*reply = *account
|
||||
return nil
|
||||
}
|
||||
|
||||
type AttrSetAccount struct {
|
||||
Tenant string
|
||||
Account string
|
||||
ActionPlanId string
|
||||
ActionTriggersId string
|
||||
AllowNegative *bool
|
||||
Disabled *bool
|
||||
ReloadScheduler bool
|
||||
}
|
||||
|
||||
func (self *ApierV2) SetAccount(attr AttrSetAccount, reply *string) error {
|
||||
if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 {
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
var schedulerReloadNeeded = false
|
||||
accID := utils.AccountKey(attr.Tenant, attr.Account)
|
||||
var ub *engine.Account
|
||||
_, err := engine.Guardian.Guard(func() (interface{}, error) {
|
||||
if bal, _ := self.AccountDb.GetAccount(accID); bal != nil {
|
||||
ub = bal
|
||||
} else { // Not found in db, create it here
|
||||
ub = &engine.Account{
|
||||
Id: accID,
|
||||
}
|
||||
}
|
||||
if len(attr.ActionPlanId) != 0 {
|
||||
_, err := engine.Guardian.Guard(func() (interface{}, error) {
|
||||
var ap *engine.ActionPlan
|
||||
var err error
|
||||
ap, err = self.RatingDb.GetActionPlan(attr.ActionPlanId, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, exists := ap.AccountIDs[accID]; !exists {
|
||||
if ap.AccountIDs == nil {
|
||||
ap.AccountIDs = make(map[string]struct{})
|
||||
}
|
||||
ap.AccountIDs[accID] = struct{}{}
|
||||
schedulerReloadNeeded = true
|
||||
// create tasks
|
||||
for _, at := range ap.ActionTimings {
|
||||
if at.IsASAP() {
|
||||
t := &engine.Task{
|
||||
Uuid: utils.GenUUID(),
|
||||
AccountID: accID,
|
||||
ActionsID: at.ActionsID,
|
||||
}
|
||||
if err = self.RatingDb.PushTask(t); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := self.RatingDb.SetActionPlan(attr.ActionPlanId, ap); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// update cache
|
||||
self.RatingDb.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PLAN_PREFIX: []string{utils.ACTION_PLAN_PREFIX + attr.ActionPlanId}})
|
||||
}
|
||||
return 0, nil
|
||||
}, 0, utils.ACTION_PLAN_PREFIX)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(attr.ActionTriggersId) != 0 {
|
||||
atrs, err := self.RatingDb.GetActionTriggers(attr.ActionTriggersId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ub.ActionTriggers = atrs
|
||||
ub.InitCounters()
|
||||
}
|
||||
if attr.AllowNegative != nil {
|
||||
ub.AllowNegative = *attr.AllowNegative
|
||||
}
|
||||
if attr.Disabled != nil {
|
||||
ub.Disabled = *attr.Disabled
|
||||
}
|
||||
// All prepared, save account
|
||||
if err := self.AccountDb.SetAccount(ub); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, nil
|
||||
}, 0, accID)
|
||||
if err != nil {
|
||||
return utils.NewErrServerError(err)
|
||||
}
|
||||
if attr.ReloadScheduler && schedulerReloadNeeded {
|
||||
// reload scheduler
|
||||
if self.Sched != nil {
|
||||
self.Sched.Reload(true)
|
||||
}
|
||||
}
|
||||
*reply = utils.OK // This will mark saving of the account, error still can show up in actionTimingsId
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -45,21 +45,108 @@ const (
|
||||
CondHAS = "*has"
|
||||
)
|
||||
|
||||
var operatorMap = map[string]func(field, value interface{}) (bool, error){
|
||||
CondEQ: func(field, value interface{}) (bool, error) {
|
||||
return value == field, nil
|
||||
},
|
||||
CondGT: func(field, value interface{}) (bool, error) {
|
||||
var of, vf float64
|
||||
var ok bool
|
||||
if of, ok = field.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(field)
|
||||
}
|
||||
if vf, ok = value.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(value)
|
||||
}
|
||||
return of > vf, nil
|
||||
},
|
||||
CondGTE: func(field, value interface{}) (bool, error) {
|
||||
var of, vf float64
|
||||
var ok bool
|
||||
if of, ok = field.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(field)
|
||||
}
|
||||
if vf, ok = value.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(value)
|
||||
}
|
||||
return of >= vf, nil
|
||||
},
|
||||
CondLT: func(field, value interface{}) (bool, error) {
|
||||
var of, vf float64
|
||||
var ok bool
|
||||
if of, ok = field.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(field)
|
||||
}
|
||||
if vf, ok = value.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(value)
|
||||
}
|
||||
return of < vf, nil
|
||||
},
|
||||
CondLTE: func(field, value interface{}) (bool, error) {
|
||||
var of, vf float64
|
||||
var ok bool
|
||||
if of, ok = field.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(field)
|
||||
}
|
||||
if vf, ok = value.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(value)
|
||||
}
|
||||
return of <= vf, nil
|
||||
},
|
||||
CondEXP: func(field, value interface{}) (bool, error) {
|
||||
var expDate time.Time
|
||||
var ok bool
|
||||
if expDate, ok = field.(time.Time); !ok {
|
||||
return false, NewErrInvalidArgument(field)
|
||||
}
|
||||
var expired bool
|
||||
if expired, ok = value.(bool); !ok {
|
||||
return false, NewErrInvalidArgument(value)
|
||||
}
|
||||
if expired { // check for expiration
|
||||
return !expDate.IsZero() && expDate.Before(time.Now()), nil
|
||||
} else { // check not expired
|
||||
return expDate.IsZero() || expDate.After(time.Now()), nil
|
||||
}
|
||||
},
|
||||
CondHAS: func(field, value interface{}) (bool, error) {
|
||||
var strMap StringMap
|
||||
var ok bool
|
||||
if strMap, ok = field.(StringMap); !ok {
|
||||
return false, NewErrInvalidArgument(field)
|
||||
}
|
||||
var strSlice []interface{}
|
||||
if strSlice, ok = value.([]interface{}); !ok {
|
||||
return false, NewErrInvalidArgument(value)
|
||||
}
|
||||
for _, str := range strSlice {
|
||||
if !strMap[str.(string)] {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
}
|
||||
|
||||
func NewErrInvalidArgument(arg interface{}) error {
|
||||
return fmt.Errorf("INVALID_ARGUMENT: %v", arg)
|
||||
}
|
||||
|
||||
type condElement interface {
|
||||
addChild(condElement) error
|
||||
type compositeElement interface {
|
||||
element
|
||||
addChild(element) error
|
||||
}
|
||||
|
||||
type element interface {
|
||||
checkStruct(interface{}) (bool, error)
|
||||
}
|
||||
|
||||
type operatorSlice struct {
|
||||
operator string
|
||||
slice []condElement
|
||||
slice []element
|
||||
}
|
||||
|
||||
func (os *operatorSlice) addChild(ce condElement) error {
|
||||
func (os *operatorSlice) addChild(ce element) error {
|
||||
os.slice = append(os.slice, ce)
|
||||
return nil
|
||||
}
|
||||
@@ -91,10 +178,10 @@ func (os *operatorSlice) checkStruct(o interface{}) (bool, error) {
|
||||
|
||||
type keyStruct struct {
|
||||
key string
|
||||
elem condElement
|
||||
elem element
|
||||
}
|
||||
|
||||
func (ks *keyStruct) addChild(ce condElement) error {
|
||||
func (ks *keyStruct) addChild(ce element) error {
|
||||
ks.elem = ce
|
||||
return nil
|
||||
}
|
||||
@@ -115,69 +202,11 @@ type operatorValue struct {
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (ov *operatorValue) addChild(condElement) error { return ErrNotImplemented }
|
||||
func (ov *operatorValue) checkStruct(o interface{}) (bool, error) {
|
||||
// no conversion
|
||||
if ov.operator == CondEQ {
|
||||
return ov.value == o, nil
|
||||
if f, ok := operatorMap[ov.operator]; ok {
|
||||
return f(o, ov.value)
|
||||
}
|
||||
// StringMap conversion
|
||||
if ov.operator == CondHAS {
|
||||
var strMap StringMap
|
||||
var ok bool
|
||||
if strMap, ok = o.(StringMap); !ok {
|
||||
return false, NewErrInvalidArgument(o)
|
||||
}
|
||||
var strSlice []interface{}
|
||||
if strSlice, ok = ov.value.([]interface{}); !ok {
|
||||
return false, NewErrInvalidArgument(ov.value)
|
||||
}
|
||||
for _, str := range strSlice {
|
||||
if !strMap[str.(string)] {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
// date conversion
|
||||
if ov.operator == CondEXP {
|
||||
var expDate time.Time
|
||||
var ok bool
|
||||
if expDate, ok = o.(time.Time); !ok {
|
||||
return false, NewErrInvalidArgument(o)
|
||||
}
|
||||
var expired bool
|
||||
if expired, ok = ov.value.(bool); !ok {
|
||||
return false, NewErrInvalidArgument(ov.value)
|
||||
}
|
||||
if expired { // check for expiration
|
||||
return !expDate.IsZero() && expDate.Before(time.Now()), nil
|
||||
} else { // check not expired
|
||||
return expDate.IsZero() || expDate.After(time.Now()), nil
|
||||
}
|
||||
}
|
||||
|
||||
// float conversion
|
||||
var of, vf float64
|
||||
var ok bool
|
||||
if of, ok = o.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(o)
|
||||
}
|
||||
if vf, ok = ov.value.(float64); !ok {
|
||||
return false, NewErrInvalidArgument(ov.value)
|
||||
}
|
||||
switch ov.operator {
|
||||
case CondGT:
|
||||
return of > vf, nil
|
||||
case CondGTE:
|
||||
return of >= vf, nil
|
||||
case CondLT:
|
||||
return of < vf, nil
|
||||
case CondLTE:
|
||||
return of <= vf, nil
|
||||
|
||||
}
|
||||
return true, nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
type keyValue struct {
|
||||
@@ -185,19 +214,20 @@ type keyValue struct {
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (kv *keyValue) addChild(condElement) error { return ErrNotImplemented }
|
||||
func (kv *keyValue) checkStruct(o interface{}) (bool, error) {
|
||||
obj := reflect.ValueOf(o)
|
||||
if obj.Kind() == reflect.Ptr {
|
||||
obj = obj.Elem()
|
||||
}
|
||||
value := obj.FieldByName(kv.key)
|
||||
if !value.IsValid() {
|
||||
return false, NewErrInvalidArgument(kv.key)
|
||||
}
|
||||
return value.Interface() == kv.value, nil
|
||||
}
|
||||
|
||||
type trueElement struct{}
|
||||
|
||||
func (te *trueElement) addChild(condElement) error { return ErrNotImplemented }
|
||||
func (te *trueElement) checkStruct(o interface{}) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
@@ -211,12 +241,12 @@ func notEmpty(x interface{}) bool {
|
||||
}
|
||||
|
||||
type CondLoader struct {
|
||||
rootElement condElement
|
||||
rootElement element
|
||||
}
|
||||
|
||||
func (cp *CondLoader) load(a map[string]interface{}, parentElement condElement) (condElement, error) {
|
||||
func (cp *CondLoader) load(a map[string]interface{}, parentElement compositeElement) (element, error) {
|
||||
for key, value := range a {
|
||||
var currentElement condElement
|
||||
var currentElement element
|
||||
switch t := value.(type) {
|
||||
case []interface{}:
|
||||
if key == CondHAS {
|
||||
@@ -224,13 +254,13 @@ func (cp *CondLoader) load(a map[string]interface{}, parentElement condElement)
|
||||
} else {
|
||||
currentElement = &operatorSlice{operator: key}
|
||||
for _, e := range t {
|
||||
cp.load(e.(map[string]interface{}), currentElement)
|
||||
cp.load(e.(map[string]interface{}), currentElement.(compositeElement))
|
||||
}
|
||||
}
|
||||
case map[string]interface{}:
|
||||
currentElement = &keyStruct{key: key}
|
||||
//log.Print("map: ", t)
|
||||
cp.load(t, currentElement)
|
||||
cp.load(t, currentElement.(compositeElement))
|
||||
case interface{}:
|
||||
if isOperator(key) {
|
||||
currentElement = &operatorValue{operator: key, value: t}
|
||||
@@ -241,13 +271,13 @@ func (cp *CondLoader) load(a map[string]interface{}, parentElement condElement)
|
||||
default:
|
||||
return nil, ErrParserError
|
||||
}
|
||||
if parentElement != nil {
|
||||
if parentElement != nil { // normal recurrent action
|
||||
parentElement.addChild(currentElement)
|
||||
} else {
|
||||
if len(a) > 1 {
|
||||
if len(a) > 1 { // we have more keys in the map
|
||||
parentElement = &operatorSlice{operator: CondAND}
|
||||
parentElement.addChild(currentElement)
|
||||
} else {
|
||||
} else { // it was only one key value
|
||||
return currentElement, nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user