func (self *ApierV1) RemoveRatingProfile(attr AttrRemoveRatingProfile, reply *string) error { log.Printf("ATTR: %+v", attr) if attr.Direction == "" { attr.Direction = utils.OUT } if (attr.Subject != "" && utils.IsSliceMember([]string{attr.Direction, attr.Tenant, attr.Category}, "")) || (attr.Category != "" && utils.IsSliceMember([]string{attr.Direction, attr.Tenant}, "")) || attr.Tenant != "" && attr.Direction == "" { return utils.ErrMandatoryIeMissing } _, err := engine.Guardian.Guard(func() (interface{}, error) { log.Print("RPID: ", attr.GetId()) err := self.RatingDb.RemoveRatingProfile(attr.GetId()) if err != nil { return 0, err } return 0, nil }, 0, "RemoveRatingProfile") if err != nil { *reply = err.Error() return utils.NewErrServerError(err) } *reply = utils.OK return nil }
// sessionRelocate is used when an update will relocate an initial session (eg multiple data streams) func (smg *SMGeneric) sessionRelocate(initialID, cgrID, newOriginID string) error { _, err := engine.Guardian.Guard(func() (interface{}, error) { // Lock it on initialID level if utils.IsSliceMember([]string{initialID, cgrID, newOriginID}, "") { // Not allowed empty params here return nil, utils.ErrMandatoryIeMissing } ssNew := smg.getSessions(cgrID, false) if len(ssNew) != 0 { // Already relocated return nil, nil } if pSSNew := smg.getSessions(cgrID, true); len(pSSNew) != 0 { // passive sessions recorded, will be recovered so no need of relocation return nil, nil } ss := smg.getSessions(initialID, false) if len(ss) == 0 { // No need of relocation if ss = smg.passiveToActive(initialID); len(ss) == 0 { return nil, utils.ErrNotFound } } for i, s := range ss[initialID] { s.CGRID = cgrID // Overwrite initial CGRID with new one s.EventStart[utils.ACCID] = newOriginID // Overwrite OriginID for session indexing smg.recordASession(s) if i == 0 { smg.unrecordASession(initialID) } } return nil, nil }, smg.cgrCfg.LockingTimeout, initialID) return err }
func NewRequestFilter(rfType, fieldName string, vals []string) (*RequestFilter, error) { if !utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaRSRFields, MetaCDRStats, MetaDestinations}, rfType) { return nil, fmt.Errorf("Unsupported filter Type: %s", rfType) } if fieldName == "" && utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaDestinations}, rfType) { return nil, fmt.Errorf("FieldName is mandatory for Type: %s", rfType) } if len(vals) == 0 && utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaRSRFields, MetaDestinations, MetaDestinations}, rfType) { return nil, fmt.Errorf("Values is mandatory for Type: %s", rfType) } rf := &RequestFilter{Type: rfType, FieldName: fieldName, Values: vals} if err := rf.CompileValues(); err != nil { return nil, err } return rf, nil }
// Retrive the cost from engine func (self *Mediator) getCostFromRater(storedCdr *utils.StoredCdr) (*CallCost, error) { cc := &CallCost{} var err error if storedCdr.Usage == time.Duration(0) { // failed call, returning empty callcost, no error return cc, nil } cd := CallDescriptor{ TOR: storedCdr.TOR, Direction: storedCdr.Direction, Tenant: storedCdr.Tenant, Category: storedCdr.Category, Subject: storedCdr.Subject, Account: storedCdr.Account, Destination: storedCdr.Destination, TimeStart: storedCdr.AnswerTime, TimeEnd: storedCdr.AnswerTime.Add(storedCdr.Usage), DurationIndex: storedCdr.Usage, } if utils.IsSliceMember([]string{utils.PSEUDOPREPAID, utils.POSTPAID}, storedCdr.ReqType) { err = self.connector.Debit(cd, cc) } else { err = self.connector.GetCost(cd, cc) } if err != nil { self.logDb.LogError(storedCdr.CgrId, MEDIATOR_SOURCE, storedCdr.MediationRunId, err.Error()) } else { // If the mediator calculated a price it will write it to logdb self.logDb.LogCallCost(storedCdr.CgrId, MEDIATOR_SOURCE, storedCdr.MediationRunId, cc) } return cc, err }
// Returns error if not able to properly store the CDR, mediation is async since we can always recover offline func (self *CdrServer) deriveRateStoreStatsReplicate(storedCdr *StoredCdr) error { cdrRuns, err := self.deriveCdrs(storedCdr) if err != nil { return err } for _, cdr := range cdrRuns { if cdr.MediationRunId != utils.META_DEFAULT { // Process Aliases and Users for derived CDRs if err := LoadAlias(&AttrMatchingAlias{ Destination: cdr.Destination, Direction: cdr.Direction, Tenant: cdr.Tenant, Category: cdr.Category, Account: cdr.Account, Subject: cdr.Subject, Context: utils.ALIAS_CONTEXT_RATING, }, cdr, utils.EXTRA_FIELDS); err != nil && err != utils.ErrNotFound { return err } if err := LoadUserProfile(cdr, utils.EXTRA_FIELDS); err != nil { return err } } // Rate CDR if self.rater != nil && !cdr.Rated { if err := self.rateCDR(cdr); err != nil { cdr.Cost = -1.0 // If there was an error, mark the CDR cdr.ExtraInfo = err.Error() } } if cdr.MediationRunId == utils.META_SURETAX { // Request should be processed by SureTax if err := SureTaxProcessCdr(cdr); err != nil { cdr.Cost = -1.0 cdr.ExtraInfo = err.Error() // Something failed, write the error in the ExtraInfo } } if self.cgrCfg.CDRSStoreCdrs { // Store CDRs // Store RatedCDR if err := self.cdrDb.SetRatedCdr(cdr); err != nil { utils.Logger.Err(fmt.Sprintf("<CDRS> Storing rated CDR %+v, got error: %s", cdr, err.Error())) } // Store CostDetails if cdr.Rated || utils.IsSliceMember([]string{utils.RATED, utils.META_RATED}, cdr.ReqType) { // Account related CDRs are saved automatically, so save the others here if requested if err := self.cdrDb.LogCallCost(cdr.CgrId, utils.CDRS_SOURCE, cdr.MediationRunId, cdr.CostDetails); err != nil { utils.Logger.Err(fmt.Sprintf("<CDRS> Storing costs for CDR %+v, costDetails: %+v, got error: %s", cdr, cdr.CostDetails, err.Error())) } } } // Attach CDR to stats if self.stats != nil { // Send CDR to stats if err := self.stats.AppendCDR(cdr, nil); err != nil { utils.Logger.Err(fmt.Sprintf("<CDRS> Could not append cdr to stats: %s", err.Error())) } } if len(self.cgrCfg.CDRSCdrReplication) != 0 { self.replicateCdr(cdr) } } return nil }
func (self *CdrServer) rateCDR(storedCdr *StoredCdr) error { var qryCC *CallCost var err error if storedCdr.ReqType == utils.META_NONE { return nil } if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, storedCdr.ReqType) && storedCdr.Usage != 0 { // ToDo: Get rid of PREPAID as soon as we don't want to support it backwards // Should be previously calculated and stored in DB delay := utils.Fib() for i := 0; i < 4; i++ { qryCC, err = self.cdrDb.GetCallCostLog(storedCdr.CgrId, utils.SESSION_MANAGER_SOURCE, storedCdr.MediationRunId) if err == nil { break } time.Sleep(delay()) } if err != nil && err == gorm.RecordNotFound { //calculate CDR as for pseudoprepaid utils.Logger.Warning(fmt.Sprintf("<Cdrs> WARNING: Could not find CallCostLog for cgrid: %s, source: %s, runid: %s, will recalculate", storedCdr.CgrId, utils.SESSION_MANAGER_SOURCE, storedCdr.MediationRunId)) qryCC, err = self.getCostFromRater(storedCdr) } } else { qryCC, err = self.getCostFromRater(storedCdr) } if err != nil { return err } else if qryCC != nil { storedCdr.Cost = qryCC.Cost storedCdr.CostDetails = qryCC } return nil }
func (account *Account) GetUniqueSharedGroupMembers(destination, direction, category, unitType string) ([]string, error) { creditBalances := account.getBalancesForPrefix(destination, category, account.BalanceMap[CREDIT+direction], "") unitBalances := account.getBalancesForPrefix(destination, category, account.BalanceMap[unitType+direction], "") // gather all shared group ids var sharedGroupIds []string for _, cb := range creditBalances { if cb.SharedGroup != "" { sharedGroupIds = append(sharedGroupIds, cb.SharedGroup) } } for _, mb := range unitBalances { if mb.SharedGroup != "" { sharedGroupIds = append(sharedGroupIds, mb.SharedGroup) } } var memberIds []string for _, sgID := range sharedGroupIds { sharedGroup, err := accountingStorage.GetSharedGroup(sgID, false) if err != nil { Logger.Warning(fmt.Sprintf("Could not get shared group: %v", sgID)) return nil, err } for _, memberId := range sharedGroup.GetMembersExceptUser(account.Id) { if !utils.IsSliceMember(memberIds, memberId) { memberIds = append(memberIds, memberId) } } } return memberIds, nil }
func NewRPCPool(dispatchStrategy string, connAttempts, reconnects int, connectTimeout, replyTimeout time.Duration, rpcConnCfgs []*config.HaPoolConfig, internalConnChan chan rpcclient.RpcClientConnection, ttl time.Duration) (*rpcclient.RpcClientPool, error) { var rpcClient *rpcclient.RpcClient var err error rpcPool := rpcclient.NewRpcClientPool(dispatchStrategy, replyTimeout) atLestOneConnected := false // If one connected we don't longer return errors for _, rpcConnCfg := range rpcConnCfgs { if rpcConnCfg.Address == utils.MetaInternal { var internalConn rpcclient.RpcClientConnection select { case internalConn = <-internalConnChan: internalConnChan <- internalConn case <-time.After(ttl): return nil, errors.New("TTL triggered") } rpcClient, err = rpcclient.NewRpcClient("", "", connAttempts, reconnects, connectTimeout, replyTimeout, rpcclient.INTERNAL_RPC, internalConn, false) } else if utils.IsSliceMember([]string{utils.MetaJSONrpc, utils.MetaGOBrpc, ""}, rpcConnCfg.Transport) { codec := utils.GOB if rpcConnCfg.Transport != "" { codec = rpcConnCfg.Transport[1:] // Transport contains always * before codec understood by rpcclient } rpcClient, err = rpcclient.NewRpcClient("tcp", rpcConnCfg.Address, connAttempts, reconnects, connectTimeout, replyTimeout, codec, nil, false) } else { return nil, fmt.Errorf("Unsupported transport: <%s>", rpcConnCfg.Transport) } if err == nil { atLestOneConnected = true } rpcPool.AddClient(rpcClient) } if atLestOneConnected { err = nil } return rpcPool, err }
func NewTPExporter(storDb LoadStorage, tpID, expPath, fileFormat, sep string, compress bool) (*TPExporter, error) { if len(tpID) == 0 { return nil, errors.New("Missing TPid") } if !utils.IsSliceMember(TPExportFormats, fileFormat) { return nil, errors.New("Unsupported file format") } tpExp := &TPExporter{ storDb: storDb, tpID: tpID, exportPath: expPath, fileFormat: fileFormat, compress: compress, cacheBuff: new(bytes.Buffer), } runeSep, _ := utf8.DecodeRuneInString(sep) if runeSep == utf8.RuneError { return nil, fmt.Errorf("Invalid field separator: %s", sep) } else { tpExp.sep = runeSep } if compress { if len(tpExp.exportPath) == 0 { tpExp.zipWritter = zip.NewWriter(tpExp.cacheBuff) } else { if fileOut, err := os.Create(path.Join(tpExp.exportPath, "tpexport.zip")); err != nil { return nil, err } else { tpExp.zipWritter = zip.NewWriter(fileOut) } } } return tpExp, nil }
// Takes the record out of csv and turns it into storedCdr which can be processed by CDRS func (self *CsvRecordsProcessor) recordToStoredCdr(record []string, cdrcId string) (*engine.CDR, error) { storedCdr := &engine.CDR{OriginHost: "0.0.0.0", Source: self.cdrcCfgs[cdrcId].CdrSourceId, ExtraFields: make(map[string]string), Cost: -1} var err error var lazyHttpFields []*config.CfgCdrField for _, cdrFldCfg := range self.cdrcCfgs[cdrcId].ContentFields { if utils.IsSliceMember([]string{utils.KAM_FLATSTORE, utils.OSIPS_FLATSTORE}, self.dfltCdrcCfg.CdrFormat) { // Hardcode some values in case of flatstore switch cdrFldCfg.FieldId { case utils.ACCID: cdrFldCfg.Value = utils.ParseRSRFieldsMustCompile("3;1;2", utils.INFIELD_SEP) // in case of flatstore, accounting id is made up out of callid, from_tag and to_tag case utils.USAGE: cdrFldCfg.Value = utils.ParseRSRFieldsMustCompile(strconv.Itoa(len(record)-1), utils.INFIELD_SEP) // in case of flatstore, last element will be the duration computed by us } } var fieldVal string if cdrFldCfg.Type == utils.META_COMPOSED { for _, cfgFieldRSR := range cdrFldCfg.Value { if cfgFieldRSR.IsStatic() { fieldVal += cfgFieldRSR.ParseValue("") } else { // Dynamic value extracted using index if cfgFieldIdx, _ := strconv.Atoi(cfgFieldRSR.Id); len(record) <= cfgFieldIdx { return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s", record, cdrFldCfg.Tag) } else { fieldVal += cfgFieldRSR.ParseValue(record[cfgFieldIdx]) } } } } else if cdrFldCfg.Type == utils.META_HTTP_POST { lazyHttpFields = append(lazyHttpFields, cdrFldCfg) // Will process later so we can send an estimation of storedCdr to http server } else { return nil, fmt.Errorf("Unsupported field type: %s", cdrFldCfg.Type) } if err := storedCdr.ParseFieldValue(cdrFldCfg.FieldId, fieldVal, self.timezone); err != nil { return nil, err } } storedCdr.CGRID = utils.Sha1(storedCdr.OriginID, storedCdr.SetupTime.UTC().String()) if storedCdr.ToR == utils.DATA && self.cdrcCfgs[cdrcId].DataUsageMultiplyFactor != 0 { storedCdr.Usage = time.Duration(float64(storedCdr.Usage.Nanoseconds()) * self.cdrcCfgs[cdrcId].DataUsageMultiplyFactor) } for _, httpFieldCfg := range lazyHttpFields { // Lazy process the http fields var outValByte []byte var fieldVal, httpAddr string for _, rsrFld := range httpFieldCfg.Value { httpAddr += rsrFld.ParseValue("") } if outValByte, err = utils.HttpJsonPost(httpAddr, self.httpSkipTlsCheck, storedCdr); err != nil && httpFieldCfg.Mandatory { return nil, err } else { fieldVal = string(outValByte) if len(fieldVal) == 0 && httpFieldCfg.Mandatory { return nil, fmt.Errorf("MandatoryIeMissing: Empty result for http_post field: %s", httpFieldCfg.Tag) } if err := storedCdr.ParseFieldValue(httpFieldCfg.FieldId, fieldVal, self.timezone); err != nil { return nil, err } } } return storedCdr, nil }
// Retrive the cost from engine func (self *CdrServer) getCostFromRater(cdr *CDR) (*CallCost, error) { cc := new(CallCost) var err error timeStart := cdr.AnswerTime if timeStart.IsZero() { // Fix for FreeSWITCH unanswered calls timeStart = cdr.SetupTime } cd := &CallDescriptor{ TOR: cdr.ToR, Direction: cdr.Direction, Tenant: cdr.Tenant, Category: cdr.Category, Subject: cdr.Subject, Account: cdr.Account, Destination: cdr.Destination, TimeStart: timeStart, TimeEnd: timeStart.Add(cdr.Usage), DurationIndex: cdr.Usage, PerformRounding: true, } if utils.IsSliceMember([]string{utils.META_PSEUDOPREPAID, utils.META_POSTPAID, utils.META_PREPAID, utils.PSEUDOPREPAID, utils.POSTPAID, utils.PREPAID}, cdr.RequestType) { // Prepaid - Cost can be recalculated in case of missing records from SM err = self.rals.Call("Responder.Debit", cd, cc) } else { err = self.rals.Call("Responder.GetCost", cd, cc) } if err != nil { return cc, err } return cc, nil }
// Retrive the cost from engine func (self *CdrServer) getCostFromRater(storedCdr *StoredCdr) (*CallCost, error) { cc := new(CallCost) var err error timeStart := storedCdr.AnswerTime if timeStart.IsZero() { // Fix for FreeSWITCH unanswered calls timeStart = storedCdr.SetupTime } cd := &CallDescriptor{ TOR: storedCdr.TOR, Direction: storedCdr.Direction, Tenant: storedCdr.Tenant, Category: storedCdr.Category, Subject: storedCdr.Subject, Account: storedCdr.Account, Destination: storedCdr.Destination, TimeStart: timeStart, TimeEnd: timeStart.Add(storedCdr.Usage), DurationIndex: storedCdr.Usage, } if utils.IsSliceMember([]string{utils.META_PSEUDOPREPAID, utils.META_POSTPAID, utils.META_PREPAID, utils.PSEUDOPREPAID, utils.POSTPAID, utils.PREPAID}, storedCdr.ReqType) { // Prepaid - Cost can be recalculated in case of missing records from SM if err = self.rater.Debit(cd, cc); err == nil { // Debit has occured, we are forced to write the log, even if CDR store is disabled self.cdrDb.LogCallCost(storedCdr.CgrId, utils.CDRS_SOURCE, storedCdr.MediationRunId, cc) } } else { err = self.rater.GetCost(cd, cc) } if err != nil { return cc, err } return cc, nil }
func (account *Account) GetUniqueSharedGroupMembers(cd *CallDescriptor) ([]string, error) { var balances []*Balance balances = append(balances, account.getBalancesForPrefix(cd.Destination, cd.Category, account.BalanceMap[utils.MONETARY+cd.Direction], "")...) balances = append(balances, account.getBalancesForPrefix(cd.Destination, cd.Category, account.BalanceMap[cd.TOR+cd.Direction], "")...) // gather all shared group ids var sharedGroupIds []string for _, b := range balances { if b.SharedGroup != "" { sharedGroupIds = append(sharedGroupIds, b.SharedGroup) } } var memberIds []string for _, sgID := range sharedGroupIds { sharedGroup, err := ratingStorage.GetSharedGroup(sgID, false) if err != nil { Logger.Warning(fmt.Sprintf("Could not get shared group: %v", sgID)) return nil, err } for _, memberId := range sharedGroup.MemberIds { if !utils.IsSliceMember(memberIds, memberId) { memberIds = append(memberIds, memberId) } } } return memberIds, nil }
// Retrive the cost from engine func (self *CdrServer) getCostFromRater(storedCdr *StoredCdr) (*CallCost, error) { //if storedCdr.Usage == time.Duration(0) { // failed call, nil cost // return nil, nil // No costs present, better than empty call cost since could lead us to 0 costs //} cc := new(CallCost) var err error cd := &CallDescriptor{ TOR: storedCdr.TOR, Direction: storedCdr.Direction, Tenant: storedCdr.Tenant, Category: storedCdr.Category, Subject: storedCdr.Subject, Account: storedCdr.Account, Destination: storedCdr.Destination, TimeStart: storedCdr.AnswerTime, TimeEnd: storedCdr.AnswerTime.Add(storedCdr.Usage), DurationIndex: storedCdr.Usage, } if utils.IsSliceMember([]string{utils.META_PSEUDOPREPAID, utils.META_POSTPAID, utils.META_PREPAID, utils.PSEUDOPREPAID, utils.POSTPAID, utils.PREPAID}, storedCdr.ReqType) { // Prepaid - Cost can be recalculated in case of missing records from SM if err = self.rater.Debit(cd, cc); err == nil { // Debit has occured, we are forced to write the log, even if CDR store is disabled self.cdrDb.LogCallCost(storedCdr.CgrId, utils.CDRS_SOURCE, storedCdr.MediationRunId, cc) } } else { err = self.rater.GetCost(cd, cc) } if err != nil { return nil, err } return cc, nil }
// Takes the record out of csv and turns it into http form which can be posted func (self *Cdrc) recordToStoredCdr(record []string) (*utils.StoredCdr, error) { storedCdr := &utils.StoredCdr{CdrHost: "0.0.0.0", CdrSource: self.cdrSourceId, ExtraFields: make(map[string]string), Cost: -1} var err error for cfgFieldName, cfgFieldRSRs := range self.cdrFields { var fieldVal string if utils.IsSliceMember([]string{CSV, FS_CSV}, self.cdrType) { for _, cfgFieldRSR := range cfgFieldRSRs { if strings.HasPrefix(cfgFieldRSR.Id, utils.STATIC_VALUE_PREFIX) { fieldVal += cfgFieldRSR.ParseValue("PLACEHOLDER") } else { // Dynamic value extracted using index if cfgFieldIdx, _ := strconv.Atoi(cfgFieldRSR.Id); len(record) <= cfgFieldIdx { return nil, fmt.Errorf("Ignoring record: %v - cannot extract field %s", record, cfgFieldName) } else { fieldVal += cfgFieldRSR.ParseValue(record[cfgFieldIdx]) } } } } else { // Modify here when we add more supported cdr formats fieldVal = "UNKNOWN" } switch cfgFieldName { case utils.TOR: storedCdr.TOR = fieldVal case utils.ACCID: storedCdr.AccId = fieldVal case utils.REQTYPE: storedCdr.ReqType = fieldVal case utils.DIRECTION: storedCdr.Direction = fieldVal case utils.TENANT: storedCdr.Tenant = fieldVal case utils.CATEGORY: storedCdr.Category = fieldVal case utils.ACCOUNT: storedCdr.Account = fieldVal case utils.SUBJECT: storedCdr.Subject = fieldVal case utils.DESTINATION: storedCdr.Destination = fieldVal case utils.SETUP_TIME: if storedCdr.SetupTime, err = utils.ParseTimeDetectLayout(fieldVal); err != nil { return nil, fmt.Errorf("Cannot parse answer time field with value: %s, err: %s", fieldVal, err.Error()) } case utils.ANSWER_TIME: if storedCdr.AnswerTime, err = utils.ParseTimeDetectLayout(fieldVal); err != nil { return nil, fmt.Errorf("Cannot parse answer time field with value: %s, err: %s", fieldVal, err.Error()) } case utils.USAGE: if storedCdr.Usage, err = utils.ParseDurationWithNanosecs(fieldVal); err != nil { return nil, fmt.Errorf("Cannot parse duration field with value: %s, err: %s", fieldVal, err.Error()) } default: // Extra fields will not match predefined so they all show up here storedCdr.ExtraFields[cfgFieldName] = fieldVal } } storedCdr.CgrId = utils.Sha1(storedCdr.AccId, storedCdr.SetupTime.String()) return storedCdr, nil }
func (storedCdr *StoredCdr) GetTenant(fieldName string) string { if utils.IsSliceMember([]string{utils.TENANT, utils.META_DEFAULT}, fieldName) { return storedCdr.Tenant } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } return storedCdr.FieldAsString(&utils.RSRField{Id: fieldName}) }
// Formats usage on export func (cdr *CDR) FormatUsage(layout string) string { if utils.IsSliceMember([]string{utils.DATA, utils.SMS, utils.MMS, utils.GENERIC}, cdr.ToR) { return strconv.FormatFloat(utils.Round(cdr.Usage.Seconds(), 0, utils.ROUNDING_MIDDLE), 'f', -1, 64) } switch layout { default: return strconv.FormatFloat(float64(cdr.Usage.Nanoseconds())/1000000000, 'f', -1, 64) } }
func (cgrCdr CgrCdr) getExtraFields() map[string]string { extraFields := make(map[string]string) for k, v := range cgrCdr { if !utils.IsSliceMember(utils.PrimaryCdrFields, k) { extraFields[k] = v } } return extraFields }
func (cdr *CDR) GetCallDestNr(fieldName string) string { if utils.IsSliceMember([]string{utils.DESTINATION, utils.META_DEFAULT, ""}, fieldName) { return cdr.Destination } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) }
func (cdr *CDR) GetReqType(fieldName string) string { if utils.IsSliceMember([]string{utils.REQTYPE, utils.META_DEFAULT, ""}, fieldName) { return cdr.RequestType } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) }
func (kev KamEvent) GetExtraFields() map[string]string { extraFields := make(map[string]string) for field, val := range kev { if !utils.IsSliceMember(primaryFields, field) { extraFields[field] = val } } return extraFields }
func (cdr *CDR) GetCategory(fieldName string) string { if utils.IsSliceMember([]string{utils.CATEGORY, utils.META_DEFAULT, ""}, fieldName) { return cdr.Category } if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value return fieldName[len(utils.STATIC_VALUE_PREFIX):] } return cdr.FieldAsString(&utils.RSRField{Id: fieldName}) }
// 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() }
func NewRequestFilter(rfType, fieldName string, vals []string, cdrStats rpcclient.RpcClientConnection) (*RequestFilter, error) { if !utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaRSRFields, MetaCDRStats, MetaDestinations}, rfType) { return nil, fmt.Errorf("Unsupported filter Type: %s", rfType) } if fieldName == "" && utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaDestinations}, rfType) { return nil, fmt.Errorf("FieldName is mandatory for Type: %s", rfType) } if len(vals) == 0 && utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaRSRFields, MetaDestinations, MetaDestinations}, rfType) { return nil, fmt.Errorf("Values is mandatory for Type: %s", rfType) } rf := &RequestFilter{Type: rfType, FieldName: fieldName, Values: vals, cdrStats: cdrStats, cdrStatSThresholds: make([]*RFStatSThreshold, len(vals))} if rfType == MetaCDRStats { if cdrStats == nil { return nil, errors.New("Missing cdrStats information") } for i, val := range vals { valSplt := strings.Split(val, utils.InInFieldSep) if len(valSplt) != 3 { return nil, fmt.Errorf("Value %s needs to contain at least 3 items", val) } st := &RFStatSThreshold{QueueID: valSplt[0], ThresholdType: strings.ToUpper(valSplt[1])} if len(st.ThresholdType) < len(MetaMinCapPrefix)+1 { return nil, fmt.Errorf("Value %s contains a unsupported ThresholdType format", val) } else if !strings.HasPrefix(st.ThresholdType, MetaMinCapPrefix) && !strings.HasPrefix(st.ThresholdType, MetaMaxCapPrefix) { return nil, fmt.Errorf("Value %s contains unsupported ThresholdType prefix", val) } if tv, err := strconv.ParseFloat(valSplt[2], 64); err != nil { return nil, err } else { st.ThresholdValue = tv } rf.cdrStatSThresholds[i] = st } } if rfType == MetaRSRFields { var err error if rf.rsrFields, err = utils.ParseRSRFieldsFromSlice(vals); err != nil { return nil, err } } return rf, nil }
func (kev KamEvent) GetPdd(fieldName string) (time.Duration, error) { var pddStr string if utils.IsSliceMember([]string{utils.PDD, utils.META_DEFAULT}, fieldName) { pddStr = kev[CGR_PDD] } else if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value pddStr = fieldName[len(utils.STATIC_VALUE_PREFIX):] } else { pddStr = kev[fieldName] } return utils.ParseDurationWithSecs(pddStr) }
func (osipsev *OsipsEvent) GetExtraFields() map[string]string { primaryFields := []string{"to_tag", "setuptime", "created", "method", "callid", "sip_reason", "time", "sip_code", "duration", "from_tag", "cgr_tenant", "cgr_category", "cgr_reqtype", "cgr_account", "cgr_subject", "cgr_destination"} extraFields := make(map[string]string) for field, val := range osipsev.osipsEvent.AttrValues { if !utils.IsSliceMember(primaryFields, field) { extraFields[field] = val } } return extraFields }
func (osipsev *OsipsEvent) GetExtraFields() map[string]string { primaryFields := []string{TO_TAG, SETUP_DURATION, OSIPS_SETUP_TIME, "method", "callid", "sip_reason", OSIPS_EVENT_TIME, "sip_code", "duration", "from_tag", "dialog_id", CGR_TENANT, CGR_CATEGORY, CGR_REQTYPE, CGR_ACCOUNT, CGR_SUBJECT, CGR_DESTINATION, utils.CGR_SUPPLIER, CGR_PDD, CGR_ANSWERTIME} extraFields := make(map[string]string) for field, val := range osipsev.osipsEvent.AttrValues { if !utils.IsSliceMember(primaryFields, field) { extraFields[field] = val } } return extraFields }
func (smaEv *SMAsteriskEvent) ExtraParameters() (extraParams map[string]string) { extraParams = make(map[string]string) primaryFields := []string{eventType, channelID, timestamp, utils.CGR_ACCOUNT, utils.CGR_DESTINATION, utils.CGR_REQTYPE, utils.CGR_TENANT, utils.CGR_CATEGORY, utils.CGR_SUBJECT, utils.CGR_PDD, utils.CGR_SUPPLIER, utils.CGR_DISCONNECT_CAUSE} for cachedKey, cachedVal := range smaEv.cachedFields { if !utils.IsSliceMember(primaryFields, cachedKey) { extraParams[cachedKey] = cachedVal } } return }
func (self SMGenericEvent) GetExtraFields() map[string]string { extraFields := make(map[string]string) for key, val := range self { primaryFields := append(utils.PrimaryCdrFields, utils.EVENT_NAME) if utils.IsSliceMember(primaryFields, key) { continue } result, _ := utils.ConvertIfaceToString(val) extraFields[key] = result } return extraFields }
func (cdr *CDR) GetPdd(fieldName string) (time.Duration, error) { if utils.IsSliceMember([]string{utils.PDD, utils.META_DEFAULT, ""}, fieldName) { return cdr.PDD, nil } var PDDVal string if strings.HasPrefix(fieldName, utils.STATIC_VALUE_PREFIX) { // Static value PDDVal = fieldName[len(utils.STATIC_VALUE_PREFIX):] } else { PDDVal = cdr.FieldAsString(&utils.RSRField{Id: fieldName}) } return utils.ParseDurationWithSecs(PDDVal) }