func (dbr *DbReader) LoadActions() (err error) { storActs, err := dbr.storDb.GetTpActions(dbr.tpid, "") if err != nil { return err } // map[string][]*Action for tag, tpacts := range storActs { acts := make([]*Action, len(tpacts)) for idx, tpact := range tpacts { acts[idx] = &Action{ Id: utils.GenUUID(), ActionType: tpact.Identifier, BalanceType: tpact.BalanceType, Direction: tpact.Direction, Weight: tpact.Weight, ExtraParameters: tpact.ExtraParameters, ExpirationString: tpact.ExpiryTime, Balance: &Balance{ Uuid: utils.GenUUID(), Value: tpact.Units, Weight: tpact.BalanceWeight, RatingSubject: tpact.RatingSubject, Category: tpact.Category, DestinationId: tpact.DestinationId, }, } } dbr.actions[tag] = acts } return nil }
func (csvr *CSVReader) LoadActions() (err error) { csvReader, fp, err := csvr.readerFunc(csvr.actionsFn, csvr.sep, utils.ACTIONS_NRCOLS) if err != nil { log.Print("Could not load action file: ", err) // allow writing of the other values return nil } if fp != nil { defer fp.Close() } for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { tag := record[0] var units float64 if len(record[4]) == 0 { // Not defined units = 0.0 } else { units, err = strconv.ParseFloat(record[4], 64) if err != nil { return fmt.Errorf("Could not parse action units: %v", err) } } var balanceWeight float64 if len(record[9]) == 0 { // Not defined balanceWeight = 0.0 } else { balanceWeight, err = strconv.ParseFloat(record[9], 64) if err != nil { return fmt.Errorf("Could not parse action balance weight: %v", err) } } weight, err := strconv.ParseFloat(record[12], 64) if err != nil { return fmt.Errorf("Could not parse action weight: %v", err) } a := &Action{ Id: utils.GenUUID(), ActionType: record[1], BalanceType: record[2], Direction: record[3], Weight: weight, ExpirationString: record[5], ExtraParameters: record[11], Balance: &Balance{ Uuid: utils.GenUUID(), Value: units, Weight: balanceWeight, DestinationId: record[6], RatingSubject: record[7], Category: record[8], SharedGroup: record[10], }, } if _, err := utils.ParseDate(a.ExpirationString); err != nil { return fmt.Errorf("Could not parse expiration time: %v", err) } csvr.actions[tag] = append(csvr.actions[tag], a) } return }
func testOnStorITCacheActions(t *testing.T) { acts := Actions{ &Action{ Id: "MINI", ActionType: TOPUP_RESET, ExpirationString: UNLIMITED, Weight: 10, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.MONETARY), Uuid: utils.StringPointer(utils.GenUUID()), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Value: &utils.ValueFormula{Static: 10, Params: make(map[string]interface{})}, Weight: utils.Float64Pointer(10), Disabled: utils.BoolPointer(false), Timings: make([]*RITiming, 0), Blocker: utils.BoolPointer(false), }, }, &Action{ Id: "MINI", ActionType: TOPUP, ExpirationString: UNLIMITED, Weight: 10, Balance: &BalanceFilter{ Type: utils.StringPointer(utils.VOICE), Uuid: utils.StringPointer(utils.GenUUID()), Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)), Value: &utils.ValueFormula{Static: 100, Params: make(map[string]interface{})}, Weight: utils.Float64Pointer(10), RatingSubject: utils.StringPointer("test"), DestinationIDs: utils.StringMapPointer(utils.NewStringMap("NAT")), Disabled: utils.BoolPointer(false), Timings: make([]*RITiming, 0), Blocker: utils.BoolPointer(false), }, }, } if err := onStor.SetActions(acts[0].Id, acts, utils.NonTransactional); err != nil { t.Error(err) } if _, hasIt := cache.Get(utils.ACTION_PREFIX + acts[0].Id); hasIt { t.Error("Already in cache") } if err := onStor.CacheDataFromDB(utils.ACTION_PREFIX, []string{acts[0].Id}, false); err != nil { t.Error(err) } if itm, hasIt := cache.Get(utils.ACTION_PREFIX + acts[0].Id); !hasIt { t.Error("Did not cache") } else if rcv := itm.(Actions); !reflect.DeepEqual(acts, rcv) { t.Errorf("Expecting: %+v, received: %+v", acts, rcv) } }
func testOnStorITCacheActionPlan(t *testing.T) { ap := &ActionPlan{ Id: "MORE_MINUTES", AccountIDs: utils.StringMap{"vdf:minitsboy": true}, ActionTimings: []*ActionTiming{ &ActionTiming{ Uuid: utils.GenUUID(), Timing: &RateInterval{ Timing: &RITiming{ Years: utils.Years{2012}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{}, StartTime: utils.ASAP, }, }, Weight: 10, ActionsID: "MINI", }, &ActionTiming{ Uuid: utils.GenUUID(), Timing: &RateInterval{ Timing: &RITiming{ Years: utils.Years{2012}, Months: utils.Months{}, MonthDays: utils.MonthDays{}, WeekDays: utils.WeekDays{}, StartTime: utils.ASAP, }, }, Weight: 10, ActionsID: "SHARED", }, }, } if err := onStor.SetActionPlan(ap.Id, ap, true, utils.NonTransactional); err != nil { t.Error(err) } if _, hasIt := cache.Get(utils.ACTION_PLAN_PREFIX + ap.Id); hasIt { t.Error("Already in cache") } if err := onStor.CacheDataFromDB(utils.ACTION_PLAN_PREFIX, []string{ap.Id}, false); err != nil { t.Error(err) } if itm, hasIt := cache.Get(utils.ACTION_PLAN_PREFIX + ap.Id); !hasIt { t.Error("Did not cache") } else if rcv := itm.(*ActionPlan); !reflect.DeepEqual(ap, rcv) { t.Errorf("Expecting: %+v, received: %+v", ap, rcv) } }
func (self *ApierV1) SetActions(attrs utils.AttrSetActions, reply *string) error { if missing := utils.MissingStructFields(&attrs, []string{"ActionsId", "Actions"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } for _, action := range attrs.Actions { requiredFields := []string{"Identifier", "Weight"} if action.BalanceType != "" { // Add some inter-dependent parameters - if balanceType then we are not talking about simply calling actions requiredFields = append(requiredFields, "Direction", "Units") } if missing := utils.MissingStructFields(action, requiredFields); len(missing) != 0 { return fmt.Errorf("%s:Action:%s:%v", utils.ErrMandatoryIeMissing.Error(), action.Identifier, missing) } } if !attrs.Overwrite { if exists, err := self.RatingDb.HasData(utils.ACTION_PREFIX, attrs.ActionsId); err != nil { return utils.NewErrServerError(err) } else if exists { return utils.ErrExists } } storeActions := make(engine.Actions, len(attrs.Actions)) for idx, apiAct := range attrs.Actions { a := &engine.Action{ Id: utils.GenUUID(), ActionType: apiAct.Identifier, BalanceType: apiAct.BalanceType, Weight: apiAct.Weight, ExpirationString: apiAct.ExpiryTime, ExtraParameters: apiAct.ExtraParameters, Filter: apiAct.Filter, Balance: &engine.Balance{ Uuid: utils.GenUUID(), Id: apiAct.BalanceId, Value: apiAct.Units, Weight: apiAct.BalanceWeight, Directions: utils.ParseStringMap(apiAct.Directions), DestinationIds: utils.ParseStringMap(apiAct.DestinationIds), RatingSubject: apiAct.RatingSubject, SharedGroups: utils.ParseStringMap(apiAct.SharedGroups), }, } storeActions[idx] = a } if err := self.RatingDb.SetActions(attrs.ActionsId, storeActions); err != nil { return utils.NewErrServerError(err) } self.RatingDb.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PREFIX: []string{utils.ACTION_PREFIX + attrs.ActionsId}}) *reply = OK return nil }
func (tpr *TpReader) LoadActionTriggers() (err error) { tps, err := tpr.lr.GetTpActionTriggers(tpr.tpid, "") if err != nil { return err } storAts, err := TpActionTriggers(tps).GetActionTriggers() if err != nil { return err } for key, atrsLst := range storAts { atrs := make([]*ActionTrigger, len(atrsLst)) for idx, atr := range atrsLst { balanceExpirationDate, _ := utils.ParseTimeDetectLayout(atr.BalanceExpirationDate, tpr.timezone) id := atr.Id if id == "" { id = utils.GenUUID() } minSleep, err := utils.ParseDurationWithSecs(atr.MinSleep) if err != nil { return err } atrs[idx] = &ActionTrigger{ Id: id, ThresholdType: atr.ThresholdType, ThresholdValue: atr.ThresholdValue, Recurrent: atr.Recurrent, MinSleep: minSleep, BalanceId: atr.BalanceId, BalanceType: atr.BalanceType, BalanceDirection: atr.BalanceDirection, BalanceDestinationIds: atr.BalanceDestinationIds, BalanceWeight: atr.BalanceWeight, BalanceExpirationDate: balanceExpirationDate, BalanceTimingTags: atr.BalanceTimingTags, BalanceRatingSubject: atr.BalanceRatingSubject, BalanceCategory: atr.BalanceCategory, BalanceSharedGroup: atr.BalanceSharedGroup, Weight: atr.Weight, ActionsId: atr.ActionsId, MinQueuedItems: atr.MinQueuedItems, } if atrs[idx].Id == "" { atrs[idx].Id = utils.GenUUID() } } tpr.actionsTriggers[key] = atrs } return nil }
func (self *ApierV1) SetActions(attrs AttrSetActions, reply *string) error { if missing := utils.MissingStructFields(&attrs, []string{"ActionsId", "Actions"}); len(missing) != 0 { return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) } for _, action := range attrs.Actions { requiredFields := []string{"Identifier", "Weight"} if action.BalanceType != "" { // Add some inter-dependent parameters - if balanceType then we are not talking about simply calling actions requiredFields = append(requiredFields, "Direction", "Units") } if missing := utils.MissingStructFields(action, requiredFields); len(missing) != 0 { return fmt.Errorf("%s:Action:%s:%v", utils.ERR_MANDATORY_IE_MISSING, action.Identifier, missing) } } if !attrs.Overwrite { if exists, err := self.AccountDb.HasData(engine.ACTION_PREFIX, attrs.ActionsId); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } else if exists { return errors.New(utils.ERR_EXISTS) } } storeActions := make(engine.Actions, len(attrs.Actions)) for idx, apiAct := range attrs.Actions { a := &engine.Action{ Id: utils.GenUUID(), ActionType: apiAct.Identifier, BalanceType: apiAct.BalanceType, Direction: apiAct.Direction, Weight: apiAct.Weight, ExpirationString: apiAct.ExpiryTime, ExtraParameters: apiAct.ExtraParameters, Balance: &engine.Balance{ Uuid: utils.GenUUID(), Value: apiAct.Units, Weight: apiAct.BalanceWeight, DestinationId: apiAct.DestinationId, RatingSubject: apiAct.RatingSubject, SharedGroup: apiAct.SharedGroup, }, } storeActions[idx] = a } if err := self.AccountDb.SetActions(attrs.ActionsId, storeActions); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } didNotChange := []string{} self.AccountDb.CacheAccounting(nil, didNotChange, didNotChange, didNotChange) *reply = OK return nil }
func (ms *MapStorage) cacheAccounting(loadID string, alsKeys []string) error { CacheBeginTransaction() if alsKeys == nil { CacheRemPrefixKey(utils.ALIASES_PREFIX) // Forced until we can fine tune it } for k, _ := range ms.dict { if strings.HasPrefix(k, utils.ALIASES_PREFIX) { // check if it already exists // to remove reverse cache keys if avs, err := CacheGet(k); err == nil && avs != nil { al := &Alias{Values: avs.(AliasValues)} al.SetId(k[len(utils.ALIASES_PREFIX):]) al.RemoveReverseCache() } CacheRemKey(k) if _, err := ms.GetAlias(k[len(utils.ALIASES_PREFIX):], true); err != nil { CacheRollbackTransaction() return err } } } CacheCommitTransaction() loadHistList, err := ms.GetLoadHistory(1, true) if err != nil || len(loadHistList) == 0 { utils.Logger.Info(fmt.Sprintf("could not get load history: %v (%v)", loadHistList, err)) } var loadHist *utils.LoadInstance if len(loadHistList) == 0 { loadHist = &utils.LoadInstance{ RatingLoadID: utils.GenUUID(), AccountingLoadID: utils.GenUUID(), LoadID: loadID, LoadTime: time.Now(), } } else { loadHist = loadHistList[0] loadHist.AccountingLoadID = utils.GenUUID() loadHist.LoadID = loadID loadHist.LoadTime = time.Now() } if err := ms.AddLoadHistory(loadHist, 10); err != nil { utils.Logger.Info(fmt.Sprintf("error saving load history: %v (%v)", loadHist, err)) return err } ms.GetLoadHistory(1, true) // to load last instance in cache return utils.SaveCacheFileInfo(ms.cacheDumpDir, &utils.CacheFileInfo{Encoding: utils.MSGPACK, LoadInfo: loadHist}) }
// Index the client connection so we can use it to communicate back func (self *SMGExternalConnections) OnClientConnect(clnt *rpc2.Client) { self.connMux.Lock() defer self.connMux.Unlock() connId := utils.GenUUID() clnt.State.Set(CGR_CONNUUID, connId) // Set unique id for the connection so we can identify it later in requests self.conns[connId] = clnt }
func BeginTransaction() string { transID := utils.GenUUID() transBufMux.Lock() transactionBuffer[transID] = make([]*transactionItem, 0) transBufMux.Unlock() return transID }
func (dbr *DbReader) LoadActionTriggers() (err error) { atrsMap, err := dbr.storDb.GetTpActionTriggers(dbr.tpid, "") if err != nil { return err } for key, atrsLst := range atrsMap { atrs := make([]*ActionTrigger, len(atrsLst)) for idx, apiAtr := range atrsLst { balance_expiration_date, _ := utils.ParseTimeDetectLayout(apiAtr.BalanceExpirationDate) atrs[idx] = &ActionTrigger{ Id: utils.GenUUID(), BalanceType: apiAtr.BalanceType, Direction: apiAtr.Direction, ThresholdType: apiAtr.ThresholdType, ThresholdValue: apiAtr.ThresholdValue, Recurrent: apiAtr.Recurrent, MinSleep: apiAtr.MinSleep, DestinationId: apiAtr.DestinationId, BalanceWeight: apiAtr.BalanceWeight, BalanceExpirationDate: balance_expiration_date, BalanceRatingSubject: apiAtr.BalanceRatingSubject, BalanceCategory: apiAtr.BalanceCategory, BalanceSharedGroup: apiAtr.BalanceSharedGroup, Weight: apiAtr.Weight, ActionsId: apiAtr.ActionsId, MinQueuedItems: apiAtr.MinQueuedItems, } } dbr.actionsTriggers[key] = atrs } return err }
func NewDefaultCGRConfig() (*CGRConfig, error) { cfg := new(CGRConfig) cfg.InstanceID = utils.GenUUID() cfg.DataFolderPath = "/usr/share/cgrates/" cfg.SmGenericConfig = new(SmGenericConfig) cfg.SmFsConfig = new(SmFsConfig) cfg.SmKamConfig = new(SmKamConfig) cfg.SmOsipsConfig = new(SmOsipsConfig) cfg.diameterAgentCfg = new(DiameterAgentCfg) cfg.ConfigReloads = make(map[string]chan struct{}) cfg.ConfigReloads[utils.CDRC] = make(chan struct{}, 1) cfg.ConfigReloads[utils.CDRC] <- struct{}{} // Unlock the channel cfg.ConfigReloads[utils.CDRE] = make(chan struct{}, 1) cfg.ConfigReloads[utils.CDRE] <- struct{}{} // Unlock the channel cfg.ConfigReloads[utils.SURETAX] = make(chan struct{}, 1) cfg.ConfigReloads[utils.SURETAX] <- struct{}{} // Unlock the channel cfg.ConfigReloads[utils.DIAMETER_AGENT] = make(chan struct{}, 1) cfg.ConfigReloads[utils.DIAMETER_AGENT] <- struct{}{} // Unlock the channel cgrJsonCfg, err := NewCgrJsonCfgFromReader(strings.NewReader(CGRATES_CFG_JSON)) if err != nil { return nil, err } cfg.MaxCallDuration = time.Duration(3) * time.Hour // Hardcoded for now if err := cfg.loadFromJsonCfg(cgrJsonCfg); err != nil { return nil, err } cfg.dfltCdreProfile = cfg.CdreProfiles[utils.META_DEFAULT].Clone() // So default will stay unique, will have nil pointer in case of no defaults loaded which is an extra check cfg.dfltCdrcProfile = cfg.CdrcProfiles["/var/spool/cgrates/cdrc/in"][0].Clone() dfltFsConnConfig = cfg.SmFsConfig.EventSocketConns[0] // We leave it crashing here on purpose if no Connection defaults defined dfltKamConnConfig = cfg.SmKamConfig.EvapiConns[0] if err := cfg.checkConfigSanity(); err != nil { return nil, err } return cfg, nil }
func (rplCfg CdrReplicationCfg) GetFallbackFileName() string { serverName := url.QueryEscape(rplCfg.Server) result := fmt.Sprintf("cdr_%s_%s_%s.form", rplCfg.Transport, serverName, utils.GenUUID()) return result }
// Debits some amount of user's specified balance adding the balance if it does not exists. // Returns the remaining credit in user's balance. func (ub *Account) debitBalanceAction(a *Action, reset bool) error { if a == nil { return errors.New("nil action") } bClone := a.Balance.Clone() if ub.BalanceMap == nil { ub.BalanceMap = make(map[string]BalanceChain, 1) } found := false if a.Direction == "" { a.Direction = utils.OUT } id := a.BalanceType + a.Direction ub.CleanExpiredBalances() for _, b := range ub.BalanceMap[id] { if b.IsExpired() { continue // just to be safe (cleaned expired balances above) } b.account = ub if b.MatchFilter(a.Balance) { if reset { b.SetValue(0) } b.SubstractValue(bClone.GetValue()) found = true } } // if it is not found then we add it to the list if !found { if bClone.GetValue() != 0 { bClone.SetValue(-bClone.GetValue()) } bClone.dirty = true // Mark the balance as dirty since we have modified and it should be checked by action triggers if bClone.Uuid == "" { bClone.Uuid = utils.GenUUID() } ub.BalanceMap[id] = append(ub.BalanceMap[id], bClone) } if a.Balance.SharedGroup != "" { // add shared group member sg, err := ratingStorage.GetSharedGroup(a.Balance.SharedGroup, false) if err != nil || sg == nil { //than problem utils.Logger.Warning(fmt.Sprintf("Could not get shared group: %v", a.Balance.SharedGroup)) } else { if !utils.IsSliceMember(sg.MemberIds, ub.Id) { // add member and save sg.MemberIds = append(sg.MemberIds, ub.Id) ratingStorage.SetSharedGroup(sg) } } } ub.executeActionTriggers(nil) return nil //ub.BalanceMap[id].GetTotalValue() }
// clone with new id(uuid) func (atrs ActionTriggers) Clone() ActionTriggers { // set ids to action triggers var newATriggers ActionTriggers for _, atr := range atrs { newAtr := atr.Clone() newAtr.Id = utils.GenUUID() newATriggers = append(newATriggers, newAtr) } return newATriggers }
func (self *ApierV1) SetActionPlan(attrs AttrSetActionPlan, reply *string) (err error) { if missing := utils.MissingStructFields(&attrs, []string{"Id", "ActionPlan"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } for _, at := range attrs.ActionPlan { requiredFields := []string{"ActionsId", "Time", "Weight"} if missing := utils.MissingStructFields(at, requiredFields); len(missing) != 0 { return fmt.Errorf("%s:Action:%s:%v", utils.ErrMandatoryIeMissing.Error(), at.ActionsId, missing) } } if !attrs.Overwrite { if exists, err := self.RatingDb.HasData(utils.ACTION_PLAN_PREFIX, attrs.Id); err != nil { return utils.NewErrServerError(err) } else if exists { return utils.ErrExists } } ap := &engine.ActionPlan{ Id: attrs.Id, } for _, apiAtm := range attrs.ActionPlan { if exists, err := self.RatingDb.HasData(utils.ACTION_PREFIX, apiAtm.ActionsId); err != nil { return utils.NewErrServerError(err) } else if !exists { return fmt.Errorf("%s:%s", utils.ErrBrokenReference.Error(), apiAtm.ActionsId) } timing := new(engine.RITiming) timing.Years.Parse(apiAtm.Years, ";") timing.Months.Parse(apiAtm.Months, ";") timing.MonthDays.Parse(apiAtm.MonthDays, ";") timing.WeekDays.Parse(apiAtm.WeekDays, ";") timing.StartTime = apiAtm.Time ap.ActionTimings = append(ap.ActionTimings, &engine.ActionTiming{ Uuid: utils.GenUUID(), Weight: apiAtm.Weight, Timing: &engine.RateInterval{Timing: timing}, ActionsID: apiAtm.ActionsId, }) } if err := self.RatingDb.SetActionPlan(ap.Id, ap, true, utils.NonTransactional); err != nil { return utils.NewErrServerError(err) } if err = self.RatingDb.CacheDataFromDB(utils.ACTION_PLAN_PREFIX, []string{ap.Id}, true); err != nil { return utils.NewErrServerError(err) } if attrs.ReloadScheduler { sched := self.ServManager.GetScheduler() if sched == nil { return errors.New(utils.SchedulerNotRunningCaps) } sched.Reload() } *reply = OK return nil }
func (tpr *TpReader) LoadActionPlans() (err error) { tps, err := tpr.lr.GetTpActionPlans(tpr.tpid, "") if err != nil { return err } storAps, err := TpActionPlans(tps).GetActionPlans() if err != nil { return err } for atId, ats := range storAps { for _, at := range ats { _, exists := tpr.actions[at.ActionsId] if !exists && tpr.ratingStorage != nil { if exists, err = tpr.ratingStorage.HasData(utils.ACTION_PREFIX, at.ActionsId); err != nil { return fmt.Errorf("[ActionPlans] Error querying actions: %v - %s", at.ActionsId, err.Error()) } } if !exists { return fmt.Errorf("[ActionPlans] Could not load the action for tag: %v", at.ActionsId) } t, exists := tpr.timings[at.TimingId] if !exists { return fmt.Errorf("[ActionPlans] Could not load the timing for tag: %v", at.TimingId) } var actPln *ActionPlan if actPln, exists = tpr.actionPlans[atId]; !exists { actPln = &ActionPlan{ Id: atId, } } actPln.ActionTimings = append(actPln.ActionTimings, &ActionTiming{ Uuid: utils.GenUUID(), Weight: at.Weight, Timing: &RateInterval{ Timing: &RITiming{ Years: t.Years, Months: t.Months, MonthDays: t.MonthDays, WeekDays: t.WeekDays, StartTime: t.StartTime, }, }, ActionsID: at.ActionsId, }) tpr.actionPlans[atId] = actPln } } return nil }
func (self *ApierV1) SetActionPlan(attrs AttrSetActionPlan, reply *string) error { if missing := utils.MissingStructFields(&attrs, []string{"Id", "ActionPlan"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } for _, at := range attrs.ActionPlan { requiredFields := []string{"ActionsId", "Time", "Weight"} if missing := utils.MissingStructFields(at, requiredFields); len(missing) != 0 { return fmt.Errorf("%s:Action:%s:%v", utils.ErrMandatoryIeMissing.Error(), at.ActionsId, missing) } } if !attrs.Overwrite { if exists, err := self.RatingDb.HasData(utils.ACTION_PLAN_PREFIX, attrs.Id); err != nil { return utils.NewErrServerError(err) } else if exists { return utils.ErrExists } } storeAtms := make(engine.ActionPlans, len(attrs.ActionPlan)) for idx, apiAtm := range attrs.ActionPlan { if exists, err := self.RatingDb.HasData(utils.ACTION_PREFIX, apiAtm.ActionsId); err != nil { return utils.NewErrServerError(err) } else if !exists { return fmt.Errorf("%s:%s", utils.ErrBrokenReference.Error(), apiAtm.ActionsId) } timing := new(engine.RITiming) timing.Years.Parse(apiAtm.Years, ";") timing.Months.Parse(apiAtm.Months, ";") timing.MonthDays.Parse(apiAtm.MonthDays, ";") timing.WeekDays.Parse(apiAtm.WeekDays, ";") timing.StartTime = apiAtm.Time at := &engine.ActionPlan{ Uuid: utils.GenUUID(), Id: attrs.Id, Weight: apiAtm.Weight, Timing: &engine.RateInterval{Timing: timing}, ActionsId: apiAtm.ActionsId, } storeAtms[idx] = at } if err := self.RatingDb.SetActionPlans(attrs.Id, storeAtms); err != nil { return utils.NewErrServerError(err) } self.RatingDb.CacheRatingPrefixValues(map[string][]string{utils.ACTION_PLAN_PREFIX: []string{utils.ACTION_PLAN_PREFIX + attrs.Id}}) if attrs.ReloadScheduler { if self.Sched == nil { return errors.New("SCHEDULER_NOT_ENABLED") } self.Sched.LoadActionPlans(self.RatingDb) self.Sched.Restart() } *reply = OK return nil }
func (self *ApierV1) SetActionPlan(attrs AttrSetActionPlan, reply *string) error { if missing := utils.MissingStructFields(&attrs, []string{"Id", "ActionPlan"}); len(missing) != 0 { return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) } for _, at := range attrs.ActionPlan { requiredFields := []string{"ActionsId", "Time", "Weight"} if missing := utils.MissingStructFields(at, requiredFields); len(missing) != 0 { return fmt.Errorf("%s:Action:%s:%v", utils.ERR_MANDATORY_IE_MISSING, at.ActionsId, missing) } } if !attrs.Overwrite { if exists, err := self.AccountDb.HasData(engine.ACTION_TIMING_PREFIX, attrs.Id); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } else if exists { return errors.New(utils.ERR_EXISTS) } } storeAtms := make(engine.ActionPlan, len(attrs.ActionPlan)) for idx, apiAtm := range attrs.ActionPlan { if exists, err := self.AccountDb.HasData(engine.ACTION_PREFIX, apiAtm.ActionsId); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } else if !exists { return fmt.Errorf("%s:%s", utils.ERR_BROKEN_REFERENCE, err.Error()) } timing := new(engine.RITiming) timing.Years.Parse(apiAtm.Years, ";") timing.Months.Parse(apiAtm.Months, ";") timing.MonthDays.Parse(apiAtm.MonthDays, ";") timing.WeekDays.Parse(apiAtm.WeekDays, ";") timing.StartTime = apiAtm.Time at := &engine.ActionTiming{ Uuid: utils.GenUUID(), Id: attrs.Id, Weight: apiAtm.Weight, Timing: &engine.RateInterval{Timing: timing}, ActionsId: apiAtm.ActionsId, } storeAtms[idx] = at } if err := self.AccountDb.SetActionTimings(attrs.Id, storeAtms); err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } if attrs.ReloadScheduler { if self.Sched == nil { return errors.New("SCHEDULER_NOT_ENABLED") } self.Sched.LoadActionTimings(self.AccountDb) self.Sched.Restart() } *reply = OK return nil }
func BenchmarkUUID(b *testing.B) { m := make(map[string]int, 1000) for i := 0; i < b.N; i++ { uuid := utils.GenUUID() if len(uuid) == 0 { b.Fatalf("GenUUID error %s", uuid) } b.StopTimer() c := m[uuid] if c > 0 { b.Fatalf("duplicate uuid[%s] count %d", uuid, c) } m[uuid] = c + 1 b.StartTimer() } }
func (ub *Account) GetDefaultMoneyBalance() *Balance { for _, balance := range ub.BalanceMap[utils.MONETARY] { if balance.IsDefault() { return balance } } // create default balance defaultBalance := &Balance{ Uuid: utils.GenUUID(), ID: utils.META_DEFAULT, } // minimum weight if ub.BalanceMap == nil { ub.BalanceMap = make(map[string]Balances) } ub.BalanceMap[utils.MONETARY] = append(ub.BalanceMap[utils.MONETARY], defaultBalance) return defaultBalance }
func (ub *Account) GetDefaultMoneyBalance(direction string) *Balance { for _, balance := range ub.BalanceMap[utils.MONETARY+direction] { if balance.IsDefault() { return balance } } // create default balance defaultBalance := &Balance{ Uuid: "DEFAULT" + utils.GenUUID(), Weight: 0, } // minimum weight if ub.BalanceMap == nil { ub.BalanceMap = make(map[string]BalanceChain) } ub.BalanceMap[utils.MONETARY+direction] = append(ub.BalanceMap[utils.MONETARY+direction], defaultBalance) return defaultBalance }
// Debits some amount of user's specified balance adding the balance if it does not exists. // Returns the remaining credit in user's balance. func (ub *Account) debitBalanceAction(a *Action) error { if a == nil { return errors.New("nil minute action!") } if a.Balance.Uuid == "" { a.Balance.Uuid = utils.GenUUID() } if ub.BalanceMap == nil { ub.BalanceMap = make(map[string]BalanceChain, 1) } found := false id := a.BalanceType + a.Direction ub.CleanExpiredBalances() for _, b := range ub.BalanceMap[id] { if b.IsExpired() { continue // just to be safe (cleaned expired balances above) } if b.Equal(a.Balance) { b.SubstractAmount(a.Balance.Value) found = true break } } // if it is not found then we add it to the list if !found { a.Balance.Value = -a.Balance.Value a.Balance.dirty = true // Mark the balance as dirty since we have modified and it should be checked by action triggers ub.BalanceMap[id] = append(ub.BalanceMap[id], a.Balance) if a.Balance.SharedGroup != "" { // add shared group member sg, err := accountingStorage.GetSharedGroup(a.Balance.SharedGroup, false) if err != nil || sg == nil { //than problem Logger.Warning(fmt.Sprintf("Could not get shared group: %v", a.Balance.SharedGroup)) } else { // add member and save sg.MemberIds = append(sg.MemberIds, ub.Id) accountingStorage.SetSharedGroup(sg) } } } ub.executeActionTriggers(nil) return nil //ub.BalanceMap[id].GetTotalValue() }
func (csvr *CSVReader) LoadActionTimings() (err error) { csvReader, fp, err := csvr.readerFunc(csvr.actiontimingsFn, csvr.sep, utils.ACTION_PLANS_NRCOLS) if err != nil { log.Print("Could not load action plans file: ", err) // allow writing of the other values return nil } if fp != nil { defer fp.Close() } for record, err := csvReader.Read(); err == nil; record, err = csvReader.Read() { tag := record[0] _, exists := csvr.actions[record[1]] if !exists { return fmt.Errorf("ActionPlan: Could not load the action for tag: %v", record[1]) } t, exists := csvr.timings[record[2]] if !exists { return fmt.Errorf("ActionPlan: Could not load the timing for tag: %v", record[2]) } weight, err := strconv.ParseFloat(record[3], 64) if err != nil { return fmt.Errorf("ActionTiming: Could not parse action timing weight: %v", err) } at := &ActionTiming{ Uuid: utils.GenUUID(), Id: record[0], Weight: weight, Timing: &RateInterval{ Timing: &RITiming{ Years: t.Years, Months: t.Months, MonthDays: t.MonthDays, WeekDays: t.WeekDays, StartTime: t.StartTime, }, }, ActionsId: record[1], } csvr.actionsTimings[tag] = append(csvr.actionsTimings[tag], at) } return }
func (self *ApierV1) AddTriggeredAction(attr AttrAddActionTrigger, reply *string) error { if attr.Direction == "" { attr.Direction = engine.OUTBOUND } balExpiryTime, err := utils.ParseTimeDetectLayout(attr.BalanceExpiryTime) if err != nil { return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) } at := &engine.ActionTrigger{ Id: utils.GenUUID(), BalanceType: attr.BalanceType, Direction: attr.Direction, ThresholdType: attr.ThresholdType, ThresholdValue: attr.ThresholdValue, DestinationId: attr.DestinationId, BalanceWeight: attr.BalanceWeight, BalanceExpirationDate: balExpiryTime, Weight: attr.Weight, ActionsId: attr.ActionsId, Executed: false, } tag := utils.AccountKey(attr.Tenant, attr.Account, attr.Direction) _, err = engine.AccLock.Guard(tag, func() (float64, error) { userBalance, err := self.AccountDb.GetAccount(tag) if err != nil { return 0, err } userBalance.ActionTriggers = append(userBalance.ActionTriggers, at) if err = self.AccountDb.SetAccount(userBalance); err != nil { return 0, err } return 0, nil }) if err != nil { *reply = err.Error() return err } *reply = OK return nil }
// Connects to the freeswitch mod_event_socket server and starts // listening for events. func (sm *FSSessionManager) Connect() error { eventFilters := map[string]string{"Call-Direction": "inbound"} errChan := make(chan error) for _, connCfg := range sm.cfg.Connections { connId := utils.GenUUID() fSock, err := fsock.NewFSock(connCfg.Server, connCfg.Password, connCfg.Reconnects, sm.createHandlers(), eventFilters, utils.Logger.(*syslog.Writer), connId) if err != nil { return err } else if !fSock.Connected() { return errors.New("Could not connect to FreeSWITCH") } else { sm.conns[connId] = fSock } go func() { // Start reading in own goroutine, return on error if err := sm.conns[connId].ReadEvents(); err != nil { errChan <- err } }() if fsSenderPool, err := fsock.NewFSockPool(5, connCfg.Server, connCfg.Password, 1, make(map[string][]func(string, string)), make(map[string]string), utils.Logger.(*syslog.Writer), connId); err != nil { return fmt.Errorf("Cannot connect FreeSWITCH senders pool, error: %s", err.Error()) } else if fsSenderPool == nil { return errors.New("Cannot connect FreeSWITCH senders pool.") } else { sm.senderPools[connId] = fsSenderPool } if sm.cfg.ChannelSyncInterval != 0 { // Schedule running of the callsync go func() { for { // Schedule sync channels to run repetately time.Sleep(sm.cfg.ChannelSyncInterval) sm.SyncSessions() } }() } } err := <-errChan // Will keep the Connect locked until the first error in one of the connections return err }
func (self *KamailioSessionManager) Connect() error { var err error eventHandlers := map[*regexp.Regexp][]func([]byte, string){ regexp.MustCompile("CGR_AUTH_REQUEST"): []func([]byte, string){self.onCgrAuth}, regexp.MustCompile("CGR_LCR_REQUEST"): []func([]byte, string){self.onCgrLcrReq}, regexp.MustCompile("CGR_CALL_START"): []func([]byte, string){self.onCallStart}, regexp.MustCompile("CGR_CALL_END"): []func([]byte, string){self.onCallEnd}, } errChan := make(chan error) for _, connCfg := range self.cfg.Connections { connId := utils.GenUUID() if self.conns[connId], err = kamevapi.NewKamEvapi(connCfg.EvapiAddr, connId, connCfg.Reconnects, eventHandlers, utils.Logger.(*syslog.Writer)); err != nil { return err } go func() { // Start reading in own goroutine, return on error if err := self.conns[connId].ReadEvents(); err != nil { errChan <- err } }() } err = <-errChan // Will keep the Connect locked until the first error in one of the connections return err }
func (dbr *DbReader) LoadActionTimings() (err error) { atsMap, err := dbr.storDb.GetTPActionTimings(dbr.tpid, "") if err != nil { return err } for atId, ats := range atsMap { for _, at := range ats { _, exists := dbr.actions[at.ActionsId] if !exists { return fmt.Errorf("ActionTiming: Could not load the action for tag: %v", at.ActionsId) } t, exists := dbr.timings[at.TimingId] if !exists { return fmt.Errorf("ActionTiming: Could not load the timing for tag: %v", at.TimingId) } actTmg := &ActionTiming{ Uuid: utils.GenUUID(), Id: atId, Weight: at.Weight, Timing: &RateInterval{ Timing: &RITiming{ Years: t.Years, Months: t.Months, MonthDays: t.MonthDays, WeekDays: t.WeekDays, StartTime: t.StartTime, }, }, ActionsId: at.ActionsId, } dbr.actionsTimings[atId] = append(dbr.actionsTimings[atId], actTmg) } } return err }
func (self *ApierV2) SetAccount(attr AttrSetAccount, reply *string) error { if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } accID := utils.AccountKey(attr.Tenant, attr.Account) dirtyActionPlans := make(map[string]*engine.ActionPlan) 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 attr.ActionPlanIDs != nil { _, err := engine.Guardian.Guard(func() (interface{}, error) { actionPlansMap, err := self.RatingDb.GetAllActionPlans() if err != nil { if err == utils.ErrNotFound { // if no action plans just continue return 0, nil } return 0, err } if attr.ActionPlansOverwrite { // clean previous action plans for actionPlanID, ap := range actionPlansMap { if _, exists := ap.AccountIDs[accID]; exists { delete(ap.AccountIDs, accID) dirtyActionPlans[actionPlanID] = ap } } } for _, actionPlanID := range *attr.ActionPlanIDs { ap, ok := actionPlansMap[actionPlanID] if !ok { return 0, utils.ErrNotFound } if _, exists := ap.AccountIDs[accID]; !exists { if ap.AccountIDs == nil { ap.AccountIDs = make(utils.StringMap) } ap.AccountIDs[accID] = true dirtyActionPlans[actionPlanID] = ap // 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 } } } } } apIDs := make([]string, len(dirtyActionPlans)) i := 0 for actionPlanID, ap := range dirtyActionPlans { if err := self.RatingDb.SetActionPlan(actionPlanID, ap, true, utils.NonTransactional); err != nil { return 0, err } apIDs[i] = actionPlanID i++ } if err := self.RatingDb.CacheDataFromDB(utils.ACTION_PLAN_PREFIX, apIDs, true); err != nil { return 0, err } return 0, nil }, 0, utils.ACTION_PLAN_PREFIX) if err != nil { return 0, err } } if attr.ActionTriggerIDs != nil { if attr.ActionTriggerOverwrite { ub.ActionTriggers = make(engine.ActionTriggers, 0) } for _, actionTriggerID := range *attr.ActionTriggerIDs { atrs, err := self.RatingDb.GetActionTriggers(actionTriggerID, false, utils.NonTransactional) if err != nil { return 0, err } for _, at := range atrs { var found bool for _, existingAt := range ub.ActionTriggers { if existingAt.Equals(at) { found = true break } } if !found { ub.ActionTriggers = append(ub.ActionTriggers, at) } } } } 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 && len(dirtyActionPlans) > 0 { sched := self.ServManager.GetScheduler() if sched == nil { return errors.New(utils.SchedulerNotRunningCaps) } sched.Reload() } *reply = utils.OK // This will mark saving of the account, error still can show up in actionTimingsId return nil }
func (self *ApierV1) SetActionTrigger(attr AttrSetActionTrigger, reply *string) error { if missing := utils.MissingStructFields(&attr, []string{"GroupID"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } atrs, _ := self.RatingDb.GetActionTriggers(attr.GroupID, false, utils.NonTransactional) var newAtr *engine.ActionTrigger if attr.UniqueID != "" { //search for exiting one for _, atr := range atrs { if atr.UniqueID == attr.UniqueID { newAtr = atr break } } } if newAtr == nil { newAtr = &engine.ActionTrigger{} atrs = append(atrs, newAtr) } newAtr.ID = attr.GroupID if attr.UniqueID != "" { newAtr.UniqueID = attr.UniqueID } else { newAtr.UniqueID = utils.GenUUID() } if attr.ThresholdType != nil { newAtr.ThresholdType = *attr.ThresholdType } if attr.ThresholdValue != nil { newAtr.ThresholdValue = *attr.ThresholdValue } if attr.Recurrent != nil { newAtr.Recurrent = *attr.Recurrent } if attr.MinSleep != nil { minSleep, err := utils.ParseDurationWithSecs(*attr.MinSleep) if err != nil { *reply = err.Error() return err } newAtr.MinSleep = minSleep } if attr.ExpirationDate != nil { expTime, err := utils.ParseTimeDetectLayout(*attr.ExpirationDate, self.Config.DefaultTimezone) if err != nil { *reply = err.Error() return err } newAtr.ExpirationDate = expTime } if attr.ActivationDate != nil { actTime, err := utils.ParseTimeDetectLayout(*attr.ActivationDate, self.Config.DefaultTimezone) if err != nil { *reply = err.Error() return err } newAtr.ActivationDate = actTime } newAtr.Balance = &engine.BalanceFilter{} if attr.BalanceID != nil { newAtr.Balance.ID = attr.BalanceID } if attr.BalanceType != nil { newAtr.Balance.Type = attr.BalanceType } if attr.BalanceDirections != nil { newAtr.Balance.Directions = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDirections...)) } if attr.BalanceDestinationIds != nil { newAtr.Balance.DestinationIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceDestinationIds...)) } if attr.BalanceWeight != nil { newAtr.Balance.Weight = attr.BalanceWeight } if attr.BalanceExpirationDate != nil { balanceExpTime, err := utils.ParseDate(*attr.BalanceExpirationDate) if err != nil { *reply = err.Error() return err } newAtr.Balance.ExpirationDate = &balanceExpTime } if attr.BalanceTimingTags != nil { newAtr.Balance.TimingIDs = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceTimingTags...)) } if attr.BalanceRatingSubject != nil { newAtr.Balance.RatingSubject = attr.BalanceRatingSubject } if attr.BalanceCategories != nil { newAtr.Balance.Categories = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceCategories...)) } if attr.BalanceSharedGroups != nil { newAtr.Balance.SharedGroups = utils.StringMapPointer(utils.NewStringMap(*attr.BalanceSharedGroups...)) } if attr.BalanceBlocker != nil { newAtr.Balance.Blocker = attr.BalanceBlocker } if attr.BalanceDisabled != nil { newAtr.Balance.Disabled = attr.BalanceDisabled } if attr.MinQueuedItems != nil { newAtr.MinQueuedItems = *attr.MinQueuedItems } if attr.ActionsID != nil { newAtr.ActionsID = *attr.ActionsID } if err := self.RatingDb.SetActionTriggers(attr.GroupID, atrs, utils.NonTransactional); err != nil { *reply = err.Error() return err } //no cache for action triggers *reply = utils.OK return nil }