mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-15 05:09:54 +05:00
added RequestProcessors in fsAgent
This commit is contained in:
committed by
Dan Christian Bogos
parent
0497016ad6
commit
1f686fca63
@@ -33,35 +33,55 @@ import (
|
||||
"github.com/cgrates/fsock"
|
||||
)
|
||||
|
||||
func NewFSsessions(fsAgentConfig *config.FsAgentCfg,
|
||||
timezone string, connMgr *engine.ConnManager) (fsa *FSsessions) {
|
||||
fsa = &FSsessions{
|
||||
func NewFSsessions(cgrcfg *config.CGRConfig, filterS *engine.FilterS,
|
||||
timezone string, connMgr *engine.ConnManager) (*FSsessions, error) {
|
||||
fsAgentConfig := cgrcfg.FsAgentCfg()
|
||||
fsa := &FSsessions{
|
||||
cgrcfg: cgrcfg,
|
||||
cfg: fsAgentConfig,
|
||||
conns: make([]*fsock.FSock, len(fsAgentConfig.EventSocketConns)),
|
||||
senderPools: make([]*fsock.FSockPool, len(fsAgentConfig.EventSocketConns)),
|
||||
timezone: timezone,
|
||||
connMgr: connMgr,
|
||||
filterS: filterS,
|
||||
}
|
||||
srv, _ := birpc.NewService(fsa, "", false)
|
||||
fsa.ctx = context.WithClient(context.TODO(), srv)
|
||||
return
|
||||
msgTemplates := fsa.cgrcfg.TemplatesCfg()
|
||||
// Inflate *template field types
|
||||
for _, procsr := range fsa.cfg.RequestProcessors {
|
||||
if tpls, err := config.InflateTemplates(procsr.RequestFields, msgTemplates); err != nil {
|
||||
return nil, err
|
||||
} else if tpls != nil {
|
||||
procsr.RequestFields = tpls
|
||||
}
|
||||
if tpls, err := config.InflateTemplates(procsr.ReplyFields, msgTemplates); err != nil {
|
||||
return nil, err
|
||||
} else if tpls != nil {
|
||||
procsr.ReplyFields = tpls
|
||||
}
|
||||
}
|
||||
return fsa, nil
|
||||
}
|
||||
|
||||
// FSsessions is the freeswitch session manager
|
||||
// it holds a buffer for the network connection
|
||||
// and the active sessions
|
||||
type FSsessions struct {
|
||||
cgrcfg *config.CGRConfig
|
||||
cfg *config.FsAgentCfg
|
||||
conns []*fsock.FSock // Keep the list here for connection management purposes
|
||||
senderPools []*fsock.FSockPool // Keep sender pools here
|
||||
timezone string
|
||||
connMgr *engine.ConnManager
|
||||
ctx *context.Context
|
||||
filterS *engine.FilterS
|
||||
}
|
||||
|
||||
func (fsa *FSsessions) createHandlers() map[string][]func(string, int) {
|
||||
ca := func(body string, connIdx int) {
|
||||
fsa.onChannelAnswer(
|
||||
|
||||
NewFSEvent(body), connIdx)
|
||||
}
|
||||
ch := func(body string, connIdx int) {
|
||||
@@ -140,16 +160,24 @@ func (fsa *FSsessions) unparkCall(uuid string, connIdx int, callDestNb, notify s
|
||||
}
|
||||
|
||||
func (fsa *FSsessions) onChannelPark(fsev FSEvent, connIdx int) {
|
||||
if fsev.GetReqType(utils.MetaDefault) == utils.MetaNone { // Not for us
|
||||
return
|
||||
}
|
||||
if connIdx >= len(fsa.conns) { // protection against index out of range panic
|
||||
err := fmt.Errorf("Index out of range[0,%v): %v ", len(fsa.conns), connIdx)
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> %s", utils.FreeSWITCHAgent, err.Error()))
|
||||
return
|
||||
}
|
||||
fsev[VarCGROriginHost] = utils.FirstNonEmpty(fsev[VarCGROriginHost], fsa.cfg.EventSocketConns[connIdx].Alias) // rewrite the OriginHost variable if it is empty
|
||||
authArgs := fsev.AsCGREvent(fsa.timezone)
|
||||
authArgs, err := fsa.processRequest(fsev)
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> error: %s", utils.FreeSWITCHAgent, err.Error()))
|
||||
return
|
||||
}
|
||||
reqType, err := authArgs.FieldAsString("RequestType")
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> failed to retrieve RequestType: %v", utils.FreeSWITCHAgent, err))
|
||||
return
|
||||
}
|
||||
if reqType == utils.MetaNone {
|
||||
return // do not process this request
|
||||
}
|
||||
authArgs.Event[FsConnID] = connIdx // Attach the connection ID
|
||||
var authReply sessions.V1AuthorizeReply
|
||||
if err := fsa.connMgr.Call(fsa.ctx, fsa.cfg.SessionSConns, utils.SessionSv1AuthorizeEvent, authArgs, &authReply); err != nil {
|
||||
@@ -216,33 +244,43 @@ func (fsa *FSsessions) onChannelPark(fsev FSEvent, connIdx int) {
|
||||
}
|
||||
|
||||
func (fsa *FSsessions) onChannelAnswer(fsev FSEvent, connIdx int) {
|
||||
if fsev.GetReqType(utils.MetaDefault) == utils.MetaNone { // Do not process this request
|
||||
return
|
||||
}
|
||||
if connIdx >= len(fsa.conns) { // protection against index out of range panic
|
||||
err := fmt.Errorf("Index out of range[0,%v): %v ", len(fsa.conns), connIdx)
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> %s", utils.FreeSWITCHAgent, err.Error()))
|
||||
return
|
||||
}
|
||||
_, err := fsa.conns[connIdx].SendApiCmd(
|
||||
cgrEv, err := fsa.processRequest(fsev)
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> error: %s", utils.FreeSWITCHAgent, err.Error()))
|
||||
return
|
||||
}
|
||||
reqType, err := cgrEv.FieldAsString("RequestType")
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> failed to retrieve RequestType: %v", utils.FreeSWITCHAgent, err))
|
||||
return
|
||||
}
|
||||
if reqType == utils.MetaNone {
|
||||
return // do not process this request
|
||||
}
|
||||
|
||||
if _, err := fsa.conns[connIdx].SendApiCmd(
|
||||
fmt.Sprintf("uuid_setvar %s %s %s\n\n", fsev.GetUUID(),
|
||||
utils.CGROriginHost, utils.FirstNonEmpty(fsa.cfg.EventSocketConns[connIdx].Alias,
|
||||
fsa.cfg.EventSocketConns[connIdx].Address)))
|
||||
if err != nil {
|
||||
fsa.cfg.EventSocketConns[connIdx].Address))); err != nil {
|
||||
utils.Logger.Err(
|
||||
fmt.Sprintf("<%s> error %s setting channel variabile: %s",
|
||||
utils.FreeSWITCHAgent, err.Error(), VarCGROriginHost))
|
||||
return
|
||||
}
|
||||
fsev[VarCGROriginHost] = utils.FirstNonEmpty(fsev[VarCGROriginHost], fsa.cfg.EventSocketConns[connIdx].Alias) // rewrite the OriginHost variable if it is empty
|
||||
chanUUID := fsev.GetUUID()
|
||||
if missing := fsev.MissingParameter(fsa.timezone); missing != "" {
|
||||
fsa.disconnectSession(connIdx, chanUUID, "",
|
||||
utils.NewErrMandatoryIeMissing(missing).Error())
|
||||
return
|
||||
for _, val := range []string{utils.AccountField, utils.Subject, utils.Destination, utils.Category, utils.OriginID, utils.Tenant} {
|
||||
if _, err := cgrEv.FieldAsString(val); err != nil {
|
||||
utils.Logger.Debug(fmt.Sprintf("error %v", err))
|
||||
fsa.disconnectSession(connIdx, chanUUID, "",
|
||||
utils.NewErrMandatoryIeMissing(val).Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cgrEv := fsev.AsCGREvent(config.CgrConfig().GeneralCfg().DefaultTimezone)
|
||||
if cgrEv.APIOpts == nil {
|
||||
cgrEv.APIOpts = map[string]any{utils.OptsSesInitiate: true}
|
||||
}
|
||||
@@ -259,18 +297,27 @@ func (fsa *FSsessions) onChannelAnswer(fsev FSEvent, connIdx int) {
|
||||
}
|
||||
|
||||
func (fsa *FSsessions) onChannelHangupComplete(fsev FSEvent, connIdx int) {
|
||||
if fsev.GetReqType(utils.MetaDefault) == utils.MetaNone { // Do not process this request
|
||||
return
|
||||
}
|
||||
if connIdx >= len(fsa.conns) { // protection against index out of range panic
|
||||
err := fmt.Errorf("Index out of range[0,%v): %v ", len(fsa.conns), connIdx)
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> %s", utils.FreeSWITCHAgent, err.Error()))
|
||||
return
|
||||
}
|
||||
var reply string
|
||||
fsev[VarCGROriginHost] = utils.FirstNonEmpty(fsev[VarCGROriginHost], fsa.cfg.EventSocketConns[connIdx].Alias) // rewrite the OriginHost variable if it is empty
|
||||
if fsev[VarAnswerEpoch] != "0" { // call was answered
|
||||
cgrEv := fsev.AsCGREvent(config.CgrConfig().GeneralCfg().DefaultTimezone)
|
||||
cgrEv, err := fsa.processRequest(fsev)
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> error: %s", utils.FreeSWITCHAgent, err.Error()))
|
||||
return
|
||||
}
|
||||
reqType, err := cgrEv.FieldAsString("RequestType")
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> failed to retrieve RequestType: %v", utils.FreeSWITCHAgent, err))
|
||||
return
|
||||
}
|
||||
if reqType == utils.MetaNone {
|
||||
return // do not process this request
|
||||
}
|
||||
|
||||
if fsev[VarAnswerEpoch] != "0" { // call was answered
|
||||
if cgrEv.APIOpts == nil {
|
||||
cgrEv.APIOpts = map[string]any{utils.OptsSesTerminate: true}
|
||||
}
|
||||
@@ -281,9 +328,9 @@ func (fsa *FSsessions) onChannelHangupComplete(fsev FSEvent, connIdx int) {
|
||||
fmt.Sprintf("<%s> Could not terminate session with event %s, error: %s",
|
||||
utils.FreeSWITCHAgent, fsev.GetUUID(), err.Error()))
|
||||
}
|
||||
delete(cgrEv.Event, FsConnID) // Remove the connection ID
|
||||
}
|
||||
if fsa.cfg.CreateCDR {
|
||||
cgrEv := fsev.AsCGREvent(fsa.timezone)
|
||||
if err := fsa.connMgr.Call(fsa.ctx, fsa.cfg.SessionSConns, utils.SessionSv1ProcessCDR,
|
||||
cgrEv, &reply); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Failed processing CGREvent: %s, error: <%s>",
|
||||
@@ -493,3 +540,30 @@ func (fsa *FSsessions) V1WarnDisconnect(ctx *context.Context, args map[string]an
|
||||
*reply = utils.OK
|
||||
return
|
||||
}
|
||||
|
||||
// processRequest processes the FreeSWITCH event by iterating through request processors,
|
||||
// applying filters, and setting the required fields.
|
||||
func (fsa *FSsessions) processRequest(fsev FSEvent) (*utils.CGREvent, error) {
|
||||
for _, reqProcessor := range fsa.cfg.RequestProcessors {
|
||||
agReq := NewAgentRequest(
|
||||
engine.MapStringDP(fsev),
|
||||
nil, nil, nil, nil,
|
||||
reqProcessor.Tenant,
|
||||
fsa.cgrcfg.GeneralCfg().DefaultTenant,
|
||||
fsa.cgrcfg.GeneralCfg().DefaultTimezone,
|
||||
fsa.filterS, nil,
|
||||
)
|
||||
pass, err := fsa.filterS.Pass(context.TODO(), agReq.Tenant, reqProcessor.Filters, agReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !pass {
|
||||
continue
|
||||
}
|
||||
if err := agReq.SetFields(reqProcessor.RequestFields); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return utils.NMAsCGREvent(agReq.CGRRequest, agReq.Tenant, utils.NestingSep, agReq.Opts), nil
|
||||
}
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
|
||||
@@ -1737,29 +1737,73 @@ const CGRATES_CFG_JSON = `
|
||||
},
|
||||
|
||||
"templates": {
|
||||
"*fsa": [
|
||||
{ "tag": "ToR", "path": "*cgreq.ToR","type": "*constant",
|
||||
"value": "*voice"},
|
||||
{"tag":"PDD","path":"*cgreq.PDD","type":"*composed",
|
||||
"value":"~*req.variable_progress_mediamsec;ms"},
|
||||
{"tag":"ACD","path":"*cgreq.ACD","type":"*composed",
|
||||
"value":"~*req.variable_cdr_acd;s"},
|
||||
{"tag": "OriginID","path": "*cgreq.OriginID","type": "*variable",
|
||||
"value": "~*req.Unique-ID"},
|
||||
{"tag": "*originID","path": "*opts.*originID","type": "*variable",
|
||||
"value": "~*req.Unique-ID"},
|
||||
{"tag": "OriginHost","path": "*cgreq.OriginHost","type": "*variable",
|
||||
"value": "~*req.variable_cgr_originhost"},
|
||||
{"tag": "Account","path": "*cgreq.Account","type": "*variable",
|
||||
"value": "~*req.Caller-Username"},
|
||||
{"tag":"Source","path":"*cgreq.Source", "type":"*composed",
|
||||
"value":"FS_;~*req.Event-Name"},
|
||||
{"tag":"RequestType","path":"*cgreq.RequestType","type":"*constant",
|
||||
"value":"*none","filters":["*string:*req.variable_process_cdr:false"]},
|
||||
{"tag":"RequestType","path":"*cgreq.RequestType","type":"*constant",
|
||||
"value":"*none","filters":["*string:*req.Caller-Dialplan:inline"]},
|
||||
{"tag":"RequestType","path": "*cgreq.RequestType","type": "*constant",
|
||||
"filters":["*exists:*cgreq.RequestType:"],"value": "*prepaid"},
|
||||
{"tag":"Tenant","path":"*cgreq.Tenant","type":"*constant",
|
||||
"value":"cgrates.org"},
|
||||
{"tag":"Category","path":"*cgreq.Category","type":"*constant",
|
||||
"value":"call"},
|
||||
{"tag":"Subject","path":"*cgreq.Subject","type":"*variable",
|
||||
"value":"~*req.Caller-Username"},
|
||||
{"tag":"Destination","path":"*cgreq.Destination","type":"*variable",
|
||||
"value":"~*req.Caller-Destination-Number"},
|
||||
{"tag":"SetupTime","path":"*cgreq.SetupTime","type":"*variable",
|
||||
"value":"~*req.Caller-Channel-Created-Time"},
|
||||
{"tag":"AnswerTime","path":"*cgreq.AnswerTime","type":"*variable",
|
||||
"value":"~*req.Caller-Channel-Answered-Time"},
|
||||
{"tag":"Usage","path":"*cgreq.Usage","type":"*composed",
|
||||
"value":"~*req.variable_billsec;s"},
|
||||
{"tag":"Route","path":"*cgreq.Route","type":"*variable",
|
||||
"value":"~*req.variable_cgr_route"},
|
||||
{"tag":"Cost","path":"*cgreq.Cost","type":"*constant",
|
||||
"value":"-1.0"},
|
||||
{"tag":"DisconnectCause","path":"*cgreq.DisconnectCause",
|
||||
"filters":["*notempty:*req.Hangup-Cause:"],"type":"*variable","value":"~*req.Hangup-Cause"},
|
||||
],
|
||||
"*err": [
|
||||
{"tag": "SessionId", "path": "*rep.Session-Id", "type": "*variable",
|
||||
"value": "~*req.Session-Id", "mandatory": true},
|
||||
{"tag": "OriginHost", "path": "*rep.Origin-Host", "type": "*variable",
|
||||
"value": "~*vars.OriginHost", "mandatory": true},
|
||||
{"tag": "OriginRealm", "path": "*rep.Origin-Realm", "type": "*variable",
|
||||
"value": "~*vars.OriginRealm", "mandatory": true}
|
||||
{"tag": "SessionId", "path": "*rep.Session-Id", "type": "*variable",
|
||||
"value": "~*req.Session-Id", "mandatory": true},
|
||||
{"tag": "OriginHost", "path": "*rep.Origin-Host", "type": "*variable",
|
||||
"value": "~*vars.OriginHost", "mandatory": true},
|
||||
{"tag": "OriginRealm", "path": "*rep.Origin-Realm", "type": "*variable",
|
||||
"value": "~*vars.OriginRealm", "mandatory": true}
|
||||
],
|
||||
"*cca": [
|
||||
{"tag": "SessionId", "path": "*rep.Session-Id", "type": "*variable",
|
||||
"value": "~*req.Session-Id", "mandatory": true},
|
||||
{"tag": "ResultCode", "path": "*rep.Result-Code", "type": "*constant",
|
||||
"value": "2001"},
|
||||
{"tag": "OriginHost", "path": "*rep.Origin-Host", "type": "*variable",
|
||||
"value": "~*vars.OriginHost", "mandatory": true},
|
||||
{"tag": "OriginRealm", "path": "*rep.Origin-Realm", "type": "*variable",
|
||||
"value": "~*vars.OriginRealm", "mandatory": true},
|
||||
{"tag": "AuthApplicationId", "path": "*rep.Auth-Application-Id", "type": "*variable",
|
||||
"value": "~*vars.*appid", "mandatory": true},
|
||||
{"tag": "CCRequestType", "path": "*rep.CC-Request-Type", "type": "*variable",
|
||||
"value": "~*req.CC-Request-Type", "mandatory": true},
|
||||
{"tag": "CCRequestNumber", "path": "*rep.CC-Request-Number", "type": "*variable",
|
||||
"value": "~*req.CC-Request-Number", "mandatory": true}
|
||||
{"tag": "SessionId", "path": "*rep.Session-Id", "type": "*variable",
|
||||
"value": "~*req.Session-Id", "mandatory": true},
|
||||
{"tag": "ResultCode", "path": "*rep.Result-Code", "type": "*constant",
|
||||
"value": "2001"},
|
||||
{"tag": "OriginHost", "path": "*rep.Origin-Host", "type": "*variable",
|
||||
"value": "~*vars.OriginHost", "mandatory": true},
|
||||
{"tag": "OriginRealm", "path": "*rep.Origin-Realm", "type": "*variable",
|
||||
"value": "~*vars.OriginRealm", "mandatory": true},
|
||||
{"tag": "AuthApplicationId", "path": "*rep.Auth-Application-Id", "type": "*variable",
|
||||
"value": "~*vars.*appid", "mandatory": true},
|
||||
{"tag": "CCRequestType", "path": "*rep.CC-Request-Type", "type": "*variable",
|
||||
"value": "~*req.CC-Request-Type", "mandatory": true},
|
||||
{"tag": "CCRequestNumber", "path": "*rep.CC-Request-Number", "type": "*variable",
|
||||
"value": "~*req.CC-Request-Number", "mandatory": true}
|
||||
],
|
||||
"*asr": [
|
||||
{"tag": "SessionId", "path": "*diamreq.Session-Id", "type": "*variable",
|
||||
|
||||
@@ -2071,6 +2071,117 @@ func TestDfRateSJsonCfg(t *testing.T) {
|
||||
|
||||
func TestDfTemplateSJsonCfg(t *testing.T) {
|
||||
eCfg := FcTemplatesJsonCfg{
|
||||
"*fsa": {
|
||||
{
|
||||
Tag: utils.StringPointer("ToR"),
|
||||
Path: utils.StringPointer("*cgreq.ToR"),
|
||||
Type: utils.StringPointer(utils.MetaConstant),
|
||||
Value: utils.StringPointer(utils.MetaVoice)},
|
||||
{
|
||||
Tag: utils.StringPointer("PDD"),
|
||||
Path: utils.StringPointer("*cgreq.PDD"),
|
||||
Type: utils.StringPointer(utils.MetaComposed),
|
||||
Value: utils.StringPointer("~*req.variable_progress_mediamsec;ms")},
|
||||
{
|
||||
Tag: utils.StringPointer("ACD"),
|
||||
Path: utils.StringPointer("*cgreq.ACD"),
|
||||
Type: utils.StringPointer(utils.MetaComposed),
|
||||
Value: utils.StringPointer("~*req.variable_cdr_acd;s")},
|
||||
{
|
||||
Tag: utils.StringPointer("OriginID"),
|
||||
Path: utils.StringPointer("*cgreq.OriginID"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Value: utils.StringPointer("~*req.Unique-ID")},
|
||||
{
|
||||
Tag: utils.StringPointer("*originID"),
|
||||
Path: utils.StringPointer("*opts.*originID"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Value: utils.StringPointer("~*req.Unique-ID")},
|
||||
{
|
||||
Tag: utils.StringPointer("OriginHost"),
|
||||
Path: utils.StringPointer("*cgreq.OriginHost"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Value: utils.StringPointer("~*req.variable_cgr_originhost")},
|
||||
{
|
||||
Tag: utils.StringPointer("Account"),
|
||||
Path: utils.StringPointer("*cgreq.Account"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Value: utils.StringPointer("~*req.Caller-Username")},
|
||||
{
|
||||
Tag: utils.StringPointer("Source"),
|
||||
Path: utils.StringPointer("*cgreq.Source"),
|
||||
Type: utils.StringPointer(utils.MetaComposed),
|
||||
Value: utils.StringPointer("FS_;~*req.Event-Name")},
|
||||
{
|
||||
Tag: utils.StringPointer("RequestType"),
|
||||
Path: utils.StringPointer("*cgreq.RequestType"),
|
||||
Type: utils.StringPointer(utils.MetaConstant),
|
||||
Filters: &[]string{"*string:*req.variable_process_cdr:false"},
|
||||
Value: utils.StringPointer("*none")},
|
||||
{
|
||||
Tag: utils.StringPointer("RequestType"),
|
||||
Path: utils.StringPointer("*cgreq.RequestType"),
|
||||
Type: utils.StringPointer(utils.MetaConstant),
|
||||
Filters: &[]string{"*string:*req.Caller-Dialplan:inline"},
|
||||
Value: utils.StringPointer("*none")},
|
||||
{
|
||||
Tag: utils.StringPointer("RequestType"),
|
||||
Path: utils.StringPointer("*cgreq.RequestType"),
|
||||
Type: utils.StringPointer(utils.MetaConstant),
|
||||
Filters: &[]string{"*exists:*cgreq.RequestType:"},
|
||||
Value: utils.StringPointer("*prepaid")},
|
||||
{
|
||||
Tag: utils.StringPointer("Tenant"),
|
||||
Path: utils.StringPointer("*cgreq.Tenant"),
|
||||
Type: utils.StringPointer(utils.MetaConstant),
|
||||
Value: utils.StringPointer("cgrates.org")},
|
||||
{
|
||||
Tag: utils.StringPointer("Category"),
|
||||
Path: utils.StringPointer("*cgreq.Category"),
|
||||
Type: utils.StringPointer(utils.MetaConstant),
|
||||
Value: utils.StringPointer("call")},
|
||||
{
|
||||
Tag: utils.StringPointer("Subject"),
|
||||
Path: utils.StringPointer("*cgreq.Subject"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Value: utils.StringPointer("~*req.Caller-Username")},
|
||||
{
|
||||
Tag: utils.StringPointer("Destination"),
|
||||
Path: utils.StringPointer("*cgreq.Destination"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Value: utils.StringPointer("~*req.Caller-Destination-Number")},
|
||||
{
|
||||
Tag: utils.StringPointer("SetupTime"),
|
||||
Path: utils.StringPointer("*cgreq.SetupTime"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Value: utils.StringPointer("~*req.Caller-Channel-Created-Time")},
|
||||
{
|
||||
Tag: utils.StringPointer("AnswerTime"),
|
||||
Path: utils.StringPointer("*cgreq.AnswerTime"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Value: utils.StringPointer("~*req.Caller-Channel-Answered-Time")},
|
||||
{
|
||||
Tag: utils.StringPointer("Usage"),
|
||||
Path: utils.StringPointer("*cgreq.Usage"),
|
||||
Type: utils.StringPointer(utils.MetaComposed),
|
||||
Value: utils.StringPointer("~*req.variable_billsec;s")},
|
||||
{
|
||||
Tag: utils.StringPointer("Route"),
|
||||
Path: utils.StringPointer("*cgreq.Route"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Value: utils.StringPointer("~*req.variable_cgr_route")},
|
||||
{
|
||||
Tag: utils.StringPointer("Cost"),
|
||||
Path: utils.StringPointer("*cgreq.Cost"),
|
||||
Type: utils.StringPointer(utils.MetaConstant),
|
||||
Value: utils.StringPointer("-1.0")},
|
||||
{
|
||||
Tag: utils.StringPointer("DisconnectCause"),
|
||||
Path: utils.StringPointer("*cgreq.DisconnectCause"),
|
||||
Type: utils.StringPointer(utils.MetaVariable),
|
||||
Filters: &[]string{"*notempty:*req.Hangup-Cause:"},
|
||||
Value: utils.StringPointer("~*req.Hangup-Cause")},
|
||||
},
|
||||
"*errSip": {
|
||||
{
|
||||
Tag: utils.StringPointer("Request"),
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -104,6 +104,7 @@ type FsAgentCfg struct {
|
||||
MaxWaitConnection time.Duration
|
||||
ActiveSessionDelimiter string
|
||||
EventSocketConns []*FsConnCfg
|
||||
RequestProcessors []*RequestProcessor
|
||||
}
|
||||
|
||||
// loadFreeswitchAgentCfg loads the FreeswitchAgent section of the configuration
|
||||
@@ -162,6 +163,7 @@ func (fscfg *FsAgentCfg) loadFromJSONCfg(jsnCfg *FreeswitchAgentJsonCfg) error {
|
||||
fscfg.EventSocketConns[idx].loadFromJSONCfg(jsnConnCfg)
|
||||
}
|
||||
}
|
||||
fscfg.RequestProcessors, err = appendRequestProcessors(fscfg.RequestProcessors, jsnCfg.Request_processors)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -180,6 +182,11 @@ func (fscfg FsAgentCfg) AsMapInterface() any {
|
||||
if fscfg.SessionSConns != nil {
|
||||
mp[utils.SessionSConnsCfg] = getBiRPCInternalJSONConns(fscfg.SessionSConns)
|
||||
}
|
||||
requestProcessors := make([]map[string]any, len(fscfg.RequestProcessors))
|
||||
for i, item := range fscfg.RequestProcessors {
|
||||
requestProcessors[i] = item.AsMapInterface()
|
||||
}
|
||||
mp[utils.RequestProcessorsCfg] = requestProcessors
|
||||
if fscfg.ExtraFields != nil {
|
||||
mp[utils.ExtraFieldsCfg] = fscfg.ExtraFields.AsStringSlice()
|
||||
}
|
||||
@@ -220,6 +227,12 @@ func (fscfg FsAgentCfg) Clone() (cln *FsAgentCfg) {
|
||||
cln.EventSocketConns[i] = req.Clone()
|
||||
}
|
||||
}
|
||||
if fscfg.RequestProcessors != nil {
|
||||
cln.RequestProcessors = make([]*RequestProcessor, len(fscfg.RequestProcessors))
|
||||
for i, req := range fscfg.RequestProcessors {
|
||||
cln.RequestProcessors[i] = req.Clone()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -236,6 +249,7 @@ type FreeswitchAgentJsonCfg struct {
|
||||
MaxWaitConnection *string `json:"max_wait_connection"`
|
||||
ActiveSessionDelimiter *string `json:"active_session_delimiter"`
|
||||
EventSocketConns *[]*FsConnJsonCfg `json:"event_socket_conns"`
|
||||
Request_processors *[]*ReqProcessorJsnCfg
|
||||
}
|
||||
|
||||
// Represents one connection instance towards FreeSWITCH
|
||||
|
||||
@@ -829,6 +829,7 @@ func TestFsAgentCfgAsMapInterfaceCase1(t *testing.T) {
|
||||
utils.AliasCfg: "127.0.0.1:8021",
|
||||
},
|
||||
},
|
||||
utils.RequestProcessorsCfg: []map[string]any{},
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
|
||||
t.Error(err)
|
||||
@@ -871,6 +872,7 @@ func TestFsAgentCfgAsMapInterfaceCase2(t *testing.T) {
|
||||
utils.AliasCfg: "127.0.0.1:8000",
|
||||
},
|
||||
},
|
||||
utils.RequestProcessorsCfg: []map[string]any{},
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
|
||||
t.Error(err)
|
||||
@@ -908,6 +910,7 @@ func TestFsAgentCfgAsMapInterfaceCase3(t *testing.T) {
|
||||
utils.ReplyTimeoutCfg: "1m0s",
|
||||
},
|
||||
},
|
||||
utils.RequestProcessorsCfg: []map[string]any{},
|
||||
}
|
||||
if cgrCfg, err := NewCGRConfigFromJSONStringWithDefaults(cfgJSONStr); err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -67,7 +67,20 @@
|
||||
{"address": "127.0.0.1:8021", "password": "ClueCon", "reconnects": -1,"alias":""}
|
||||
],
|
||||
"sessions_conns": ["*birpc_internal"],
|
||||
"create_cdr": true
|
||||
"create_cdr": true,
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "FSEvent",
|
||||
"request_fields":[
|
||||
{
|
||||
"tag": "BaseTmpl",
|
||||
"type": "*template",
|
||||
"value": "*fsa"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -66,7 +66,20 @@
|
||||
{"address": "127.0.0.1:8021", "password": "ClueCon", "reconnects": -1,"alias":""}
|
||||
],
|
||||
"sessions_conns": ["*birpc_internal"],
|
||||
"create_cdr": true
|
||||
"create_cdr": true,
|
||||
"request_processors": [
|
||||
{
|
||||
"id": "FSEvent",
|
||||
"request_fields":[
|
||||
{
|
||||
"tag": "BaseTmpl",
|
||||
"type": "*template",
|
||||
"value": "*fsa"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -210,3 +210,26 @@ func (me MapEvent) GetBoolOrDefault(fldName string, dflt bool) (out bool) {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type MapStringDP map[string]string // map storage for string values
|
||||
func (me MapStringDP) String() string {
|
||||
return utils.ToJSON(me)
|
||||
}
|
||||
|
||||
func (me MapStringDP) FieldAsInterface(fldPath []string) (any, error) {
|
||||
if len(fldPath) != 1 {
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
fldIface, has := me[fldPath[0]]
|
||||
if !has {
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
return fldIface, nil
|
||||
}
|
||||
|
||||
func (me MapStringDP) FieldAsString(fldPath []string) (string, error) {
|
||||
if len(fldPath) != 1 {
|
||||
return "", utils.ErrNotFound
|
||||
}
|
||||
return fldPath[0], nil
|
||||
}
|
||||
|
||||
@@ -46,16 +46,25 @@ type FreeswitchAgent struct {
|
||||
|
||||
// Start should handle the sercive start
|
||||
func (fS *FreeswitchAgent) Start(shutdown *utils.SyncedChan, registry *servmanager.ServiceRegistry) (err error) {
|
||||
cms, err := WaitForServiceState(utils.StateServiceUP, utils.ConnManager, registry, fS.cfg.GeneralCfg().ConnectTimeout)
|
||||
srvDeps, err := WaitForServicesToReachState(utils.StateServiceUP,
|
||||
[]string{
|
||||
utils.ConnManager,
|
||||
utils.FilterS,
|
||||
},
|
||||
registry, fS.cfg.GeneralCfg().ConnectTimeout)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cms := srvDeps[utils.ConnManager].(*ConnManagerService)
|
||||
fs := srvDeps[utils.FilterS].(*FilterService)
|
||||
|
||||
fS.Lock()
|
||||
defer fS.Unlock()
|
||||
|
||||
fS.fS = agents.NewFSsessions(fS.cfg.FsAgentCfg(), fS.cfg.GeneralCfg().DefaultTimezone, cms.(*ConnManagerService).ConnManager())
|
||||
|
||||
fS.fS, err = agents.NewFSsessions(fs.cfg, fs.FilterS(), fS.cfg.GeneralCfg().DefaultTimezone, cms.ConnManager())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
go fS.connect(shutdown)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user