cond lang refactor for better design

This commit is contained in:
Radu Ioan Fericean
2016-01-21 11:27:09 +02:00
parent da8ab844d4
commit 511f5002d4
2 changed files with 205 additions and 77 deletions

View File

@@ -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
}

View File

@@ -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
}
}