From 3fa0293bfaf1535df3a7d6e8bdf7647ddd654444 Mon Sep 17 00:00:00 2001 From: TeoV Date: Fri, 21 Jun 2019 15:34:06 +0300 Subject: [PATCH] Add CGR_PROCESS_CDR route in KamailioAgent --- agents/kamagent.go | 46 +++++++++++++++++++++++++++++++++++++++ agents/kamevent.go | 54 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/agents/kamagent.go b/agents/kamagent.go index feb07f82d..ddbd97351 100644 --- a/agents/kamagent.go +++ b/agents/kamagent.go @@ -40,6 +40,7 @@ var ( kamCallEndRegexp = regexp.MustCompile(CGR_CALL_END) kamDlgListRegexp = regexp.MustCompile(CGR_DLG_LIST) kamProcessEventRegex = regexp.MustCompile(CGR_PROCESS_EVENT) + kamProcessCDRRegex = regexp.MustCompile(CGR_PROCESS_CDR) ) func NewKamailioAgent(kaCfg *config.KamAgentCfg, @@ -70,6 +71,7 @@ func (self *KamailioAgent) Connect() error { kamCallEndRegexp: {self.onCallEnd}, kamDlgListRegexp: {self.onDlgList}, kamProcessEventRegex: {self.onCgrProcessEvent}, + kamProcessCDRRegex: {self.onCgrProcessCDR}, } errChan := make(chan error) for connIdx, connCfg := range self.cfg.EvapiConns { @@ -302,6 +304,50 @@ func (ka *KamailioAgent) onCgrProcessEvent(evData []byte, connIdx int) { } } +func (ka *KamailioAgent) onCgrProcessCDR(evData []byte, connIdx int) { + if connIdx >= len(ka.conns) { // protection against index out of range panic + err := fmt.Errorf("Index out of range[0,%v): %v ", len(ka.conns), connIdx) + utils.Logger.Err(fmt.Sprintf("<%s> %s", utils.FreeSWITCHAgent, err.Error())) + return + } + kev, err := NewKamEvent(evData, ka.cfg.EvapiConns[connIdx].Alias, ka.conns[connIdx].RemoteAddr().String()) + if err != nil { + utils.Logger.Err(fmt.Sprintf("<%s> unmarshalling event data: %s, error: %s", + utils.KamailioAgent, evData, err.Error())) + return + } + + if kev.MissingParameter() { + if kRply, err := kev.AsKamProcessCDRReply(nil, nil, utils.ErrMandatoryIeMissing); err != nil { + utils.Logger.Err(fmt.Sprintf("<%s> failed building process session event reply for event: %s, error: %s", + utils.KamailioAgent, kev[utils.OriginID], err.Error())) + } else if err = ka.conns[connIdx].Send(kRply.String()); err != nil { + utils.Logger.Err(fmt.Sprintf("<%s> failed sending process session event reply for event: %s, error %s", + utils.KamailioAgent, kev[utils.OriginID], err.Error())) + } + return + } + + procCDRArgs := kev.V1ProcessCDRArgs() + if procCDRArgs == nil { + utils.Logger.Err(fmt.Sprintf("<%s> event: %s cannot generate process cdr session arguments", + utils.KamailioAgent, kev[utils.OriginID])) + return + } + procCDRArgs.CGREvent.Event[EvapiConnID] = connIdx // Attach the connection ID + + var processReply string + err = ka.sessionS.Call(utils.SessionSv1ProcessCDR, procCDRArgs, &processReply) + + if kar, err := kev.AsKamProcessCDRReply(procCDRArgs, &processReply, err); err != nil { + utils.Logger.Err(fmt.Sprintf("<%s> failed building process session event reply for event: %s, error: %s", + utils.KamailioAgent, kev[utils.OriginID], err.Error())) + } else if err = ka.conns[connIdx].Send(kar.String()); err != nil { + utils.Logger.Err(fmt.Sprintf("<%s> failed sending auth reply for event: %s, error: %s", + utils.KamailioAgent, kev[utils.OriginID], err.Error())) + } +} + func (self *KamailioAgent) disconnectSession(connIdx int, dscEv *KamSessionDisconnect) error { if err := self.conns[connIdx].Send(dscEv.String()); err != nil { utils.Logger.Err(fmt.Sprintf("<%s> failed sending disconnect request: %s, connection id: %v, error %s", diff --git a/agents/kamevent.go b/agents/kamevent.go index d206c2eb5..34f6d7db3 100644 --- a/agents/kamevent.go +++ b/agents/kamevent.go @@ -36,6 +36,7 @@ const ( CGR_CALL_START = "CGR_CALL_START" CGR_CALL_END = "CGR_CALL_END" CGR_PROCESS_EVENT = "CGR_PROCESS_EVENT" + CGR_PROCESS_CDR = "CGR_PROCESS_CDR" KamTRIndex = "tr_index" KamTRLabel = "tr_label" KamHashEntry = "h_entry" @@ -119,6 +120,16 @@ func (kev KamEvent) MissingParameter() bool { kev[utils.Destination]) } return utils.IsSliceMember(mndPrm, "") + case CGR_PROCESS_CDR: + // TRIndex and TRLabel must exist in order to know where to send back the response + return utils.IsSliceMember([]string{ + kev[KamTRIndex], + kev[KamTRLabel], + kev[utils.OriginID], + kev[utils.AnswerTime], + kev[utils.Account], + kev[utils.Destination], + }, "") default: // no/unsupported event return true } @@ -173,6 +184,12 @@ func (kev KamEvent) AsCGREvent(timezone string) (cgrEv *utils.CGREvent, err erro return nil, err } sTime = sTimePrv + case CGR_PROCESS_CDR: + sTimePrv, err := utils.ParseTimeDetectLayout(kev[utils.AnswerTime], timezone) + if err != nil { + return nil, err + } + sTime = sTimePrv default: // no/unsupported event return } @@ -315,7 +332,25 @@ func (kev KamEvent) V1ProcessEventArgs() (args *sessions.V1ProcessEventArgs) { return } -// AsKamAuthReply builds up a Kamailio ProcessEvent based on arguments and reply from SessionS +// V1ProcessCDRArgs returns the arguments used in SessionSv1.ProcessCDR +func (kev KamEvent) V1ProcessCDRArgs() (args *utils.CGREventWithArgDispatcher) { + cgrEv, err := kev.AsCGREvent(config.CgrConfig().GeneralCfg().DefaultTimezone) + if err != nil { + return + } + args = &utils.CGREventWithArgDispatcher{ // defaults + CGREvent: cgrEv, + } + subsystems, has := kev[utils.CGRSubsystems] + if !has { + return + } + cgrArgs := cgrEv.ConsumeArgs(strings.Index(subsystems, utils.MetaDispatchers) != -1, true) + args.ArgDispatcher = cgrArgs.ArgDispatcher + return +} + +// AsKamProcessEventReply builds up a Kamailio ProcessEvent based on arguments and reply from SessionS func (kev KamEvent) AsKamProcessEventReply(procEvArgs *sessions.V1ProcessEventArgs, procEvReply *sessions.V1ProcessEventReply, rplyErr error) (kar *KamReply, err error) { evName := CGR_PROCESS_EVENT @@ -356,6 +391,23 @@ func (kev KamEvent) AsKamProcessEventReply(procEvArgs *sessions.V1ProcessEventAr return } +// AsKamProcessEventReply builds up a Kamailio ProcessEvent based on arguments and reply from SessionS +func (kev KamEvent) AsKamProcessCDRReply(cgrEvWithArgDisp *utils.CGREventWithArgDispatcher, + rply *string, rplyErr error) (kar *KamReply, err error) { + evName := CGR_PROCESS_CDR + if kamRouReply, has := kev[KamReplyRoute]; has { + evName = kamRouReply + } + kar = &KamReply{Event: evName, + TransactionIndex: kev[KamTRIndex], + TransactionLabel: kev[KamTRLabel], + } + if rplyErr != nil { + kar.Error = rplyErr.Error() + } + return +} + // AsKamProcessEventEmptyReply builds up a Kamailio ProcessEventEmpty func (kev KamEvent) AsKamProcessEventEmptyReply() (kar *KamReply) { evName := CGR_PROCESS_EVENT