func startSmFreeSWITCH(internalRaterChan chan *engine.Responder, cdrDb engine.CdrStorage, exitChan chan bool) { engine.Logger.Info("Starting CGRateS SM-FreeSWITCH service.") var raterConn, cdrsConn engine.ConnectorPool var client *rpcclient.RpcClient var err error delay := utils.Fib() for _, raterCfg := range cfg.SmFsConfig.HaRater { if raterCfg.Server == utils.INTERNAL { resp := <-internalRaterChan raterConn = append(raterConn, resp) internalRaterChan <- resp } for i := 0; i < cfg.Reconnects; i++ { client, err = rpcclient.NewRpcClient("tcp", raterCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err == nil { //Connected so no need to reiterate break } time.Sleep(delay()) } if err != nil { engine.Logger.Crit(fmt.Sprintf("<SM-FreeSWITCH> Could not connect to rater via RPC: %v", err)) exitChan <- true return } raterConn = append(raterConn, &engine.RPCClientConnector{Client: client, Timeout: raterCfg.Timeout}) } if reflect.DeepEqual(cfg.SmFsConfig.HaCdrs, cfg.SmFsConfig.HaRater) { cdrsConn = raterConn } else if len(cfg.SmFsConfig.HaCdrs) != 0 { delay = utils.Fib() for _, cdrsCfg := range cfg.SmFsConfig.HaCdrs { if cdrsCfg.Server == utils.INTERNAL { resp := <-internalRaterChan raterConn = append(raterConn, resp) internalRaterChan <- resp } for i := 0; i < cfg.Reconnects; i++ { client, err = rpcclient.NewRpcClient("tcp", cdrsCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err == nil { //Connected so no need to reiterate break } time.Sleep(delay()) } if err != nil { engine.Logger.Crit(fmt.Sprintf("<SM-FreeSWITCH> Could not connect to CDRS via RPC: %v", err)) exitChan <- true return } cdrsConn = append(cdrsConn, &engine.RPCClientConnector{Client: client, Timeout: cdrsCfg.Timeout}) } } sm := sessionmanager.NewFSSessionManager(cfg.SmFsConfig, raterConn, cdrsConn, cfg.DefaultTimezone) sms = append(sms, sm) smRpc.SMs = append(smRpc.SMs, sm) if err = sm.Connect(); err != nil { engine.Logger.Err(fmt.Sprintf("<SessionManager> error: %s!", err)) } exitChan <- true }
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 }
// rateCDR will populate cost field // Returns more than one rated CDR in case of SMCost retrieved based on prefix func (self *CdrServer) rateCDR(cdr *CDR) ([]*CDR, error) { var qryCC *CallCost var err error if cdr.RequestType == utils.META_NONE { return nil, nil } var cdrsRated []*CDR _, hasLastUsed := cdr.ExtraFields[utils.LastUsed] if utils.IsSliceMember([]string{utils.META_PREPAID, utils.PREPAID}, cdr.RequestType) && (cdr.Usage != 0 || hasLastUsed) { // 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() var smCosts []*SMCost for i := 0; i < 4; i++ { smCosts, err = self.cdrDb.GetSMCosts(cdr.CGRID, cdr.RunID, cdr.OriginHost, cdr.ExtraFields[utils.OriginIDPrefix]) if err == nil && len(smCosts) != 0 { break } if i != 3 { time.Sleep(delay()) } } if len(smCosts) != 0 { // Cost retrieved from SMCost table for _, smCost := range smCosts { cdrClone := cdr.Clone() cdrClone.OriginID = smCost.OriginID if cdr.Usage == 0 { cdrClone.Usage = time.Duration(smCost.Usage * utils.NANO_MULTIPLIER) // Usage is float as seconds, convert back to duration } cdrClone.Cost = smCost.CostDetails.Cost cdrClone.CostDetails = smCost.CostDetails cdrsRated = append(cdrsRated, cdrClone) } return cdrsRated, nil } if len(smCosts) == 0 { //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", cdr.CGRID, utils.SESSION_MANAGER_SOURCE, cdr.RunID)) qryCC, err = self.getCostFromRater(cdr) } } else { qryCC, err = self.getCostFromRater(cdr) } if err != nil { return nil, err } else if qryCC != nil { cdr.Cost = qryCC.Cost cdr.CostDetails = qryCC } return []*CDR{cdr}, nil }
func (ps *PubSub) Publish(evt CgrEvent, reply *string) error { ps.mux.Lock() defer ps.mux.Unlock() evt["Timestamp"] = time.Now().Format(time.RFC3339Nano) for key, subData := range ps.subscribers { if !subData.ExpTime.IsZero() && subData.ExpTime.Before(time.Now()) { delete(ps.subscribers, key) ps.removeSubscriber(key) continue // subscription exevtred, do not send event } if subData.Filters == nil || !evt.PassFilters(subData.Filters) { continue // the event does not match the filters } split := utils.InfieldSplit(key) if len(split) != 2 { utils.Logger.Warning("<PubSub> Wrong transport;address pair: " + key) continue } transport := split[0] address := split[1] ttlVerify := ps.ttlVerify jsn, err := json.Marshal(evt) if err != nil { return err } switch transport { case utils.META_HTTP_POST: go func() { delay := utils.Fib() for i := 0; i < 5; i++ { // Loop so we can increase the success rate on best effort if _, err := ps.pubFunc(address, ttlVerify, jsn); err == nil { break // Success, no need to reinterate } else if i == 4 { // Last iteration, syslog the warning utils.Logger.Warning(fmt.Sprintf("<PubSub> Failed calling url: [%s], error: [%s], event type: %s", address, err.Error(), evt["EventName"])) break } time.Sleep(delay()) } }() } } *reply = utils.OK return nil }