mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Allow configurable event field updates in ARI sessions
This commit is contained in:
committed by
Dan Christian Bogos
parent
a832ea9d7c
commit
6ec0cfb4bc
@@ -249,8 +249,10 @@ func (sma *AsteriskAgent) handleChannelStateChange(ev *SMAsteriskEvent) {
|
||||
if !hasIt { // Not handled by us
|
||||
return
|
||||
}
|
||||
|
||||
// Update the cached event with new channel state.
|
||||
sma.evCacheMux.Lock()
|
||||
err := ev.UpdateCGREvent(cgrEvDisp.CGREvent) // Updates the event directly in the cache
|
||||
err := ev.UpdateCGREvent(cgrEvDisp.CGREvent, sma.cgrCfg.AsteriskAgentCfg().AlterableFields)
|
||||
sma.evCacheMux.Unlock()
|
||||
if err != nil {
|
||||
sma.hangupChannel(ev.ChannelID(),
|
||||
@@ -258,6 +260,7 @@ func (sma *AsteriskAgent) handleChannelStateChange(ev *SMAsteriskEvent) {
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
return
|
||||
}
|
||||
|
||||
// populate init session args
|
||||
initSessionArgs := ev.V1InitSessionArgs(*cgrEvDisp)
|
||||
if initSessionArgs == nil {
|
||||
@@ -289,8 +292,10 @@ func (sma *AsteriskAgent) handleChannelDestroyed(ev *SMAsteriskEvent) {
|
||||
if !hasIt { // Not handled by us
|
||||
return
|
||||
}
|
||||
|
||||
// Update the cached event with new channel state.
|
||||
sma.evCacheMux.Lock()
|
||||
err := ev.UpdateCGREvent(cgrEvDisp.CGREvent) // Updates the event directly in the cache
|
||||
err := ev.UpdateCGREvent(cgrEvDisp.CGREvent, sma.cgrCfg.AsteriskAgentCfg().AlterableFields)
|
||||
sma.evCacheMux.Unlock()
|
||||
if err != nil {
|
||||
utils.Logger.Warning(
|
||||
@@ -298,6 +303,7 @@ func (sma *AsteriskAgent) handleChannelDestroyed(ev *SMAsteriskEvent) {
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
return
|
||||
}
|
||||
|
||||
// populate terminate session args
|
||||
tsArgs := ev.V1TerminateSessionArgs(*cgrEvDisp)
|
||||
if tsArgs == nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package agents
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -186,7 +187,8 @@ func (smaEv *SMAsteriskEvent) ExtraParameters() (extraParams map[string]string)
|
||||
return
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) UpdateCGREvent(cgrEv *utils.CGREvent) error {
|
||||
// UpdateCGREvent updates a previously cached CGREvent (from StasisStart) with data from a new ARI event.
|
||||
func (smaEv *SMAsteriskEvent) UpdateCGREvent(cgrEv *utils.CGREvent, alterableFields []string) error {
|
||||
resCGREv := *cgrEv
|
||||
switch smaEv.EventType() {
|
||||
case ARIChannelStateChange:
|
||||
@@ -212,6 +214,30 @@ func (smaEv *SMAsteriskEvent) UpdateCGREvent(cgrEv *utils.CGREvent) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update fields specified in alterableFields. Each field can be in the format:
|
||||
// - "path.to.field": copies the field value using the last path element as key
|
||||
// - "path.to.field:alias": copies the field value using the alias as key
|
||||
if len(alterableFields) != 0 {
|
||||
ms := utils.MapStorage(smaEv.ariEv)
|
||||
for _, field := range alterableFields {
|
||||
path, alias, hasAlias := strings.Cut(field, utils.InInFieldSep)
|
||||
pathElems := strings.Split(path, utils.NestingSep)
|
||||
fieldVal, err := ms.FieldAsString(pathElems)
|
||||
if errors.Is(err, utils.ErrNotFound) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fieldKey := pathElems[len(pathElems)-1]
|
||||
if hasAlias {
|
||||
fieldKey = alias
|
||||
}
|
||||
resCGREv.Event[fieldKey] = fieldVal
|
||||
}
|
||||
}
|
||||
|
||||
*cgrEv = resCGREv
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -369,15 +369,19 @@ const CGRATES_CFG_JSON = `
|
||||
|
||||
|
||||
"asterisk_agent": {
|
||||
"enabled": false, // starts the Asterisk agent: <true|false>
|
||||
"enabled": false, // starts the Asterisk agent: <true|false>
|
||||
"sessions_conns": ["*internal"],
|
||||
"create_cdr": false, // create CDR out of events and sends it to CDRS component
|
||||
"asterisk_conns":[ // instantiate connections to multiple Asterisk servers
|
||||
{"address": "127.0.0.1:8088", "user": "cgrates", "password": "CGRateS.org", "connect_attempts": 3,"reconnects": 5}
|
||||
],
|
||||
"create_cdr": false, // create CDR out of events and sends it to CDRS component
|
||||
//"alterable_fields": [], // additional fields to update from ARI events, optionally with :alias
|
||||
"asterisk_conns": [{ // instantiate connections to multiple Asterisk servers
|
||||
"address": "127.0.0.1:8088",
|
||||
"user": "cgrates",
|
||||
"password": "CGRateS.org",
|
||||
"connect_attempts": 3,
|
||||
"reconnects": 5
|
||||
}]
|
||||
},
|
||||
|
||||
|
||||
"freeswitch_agent": {
|
||||
"enabled": false, // starts the FreeSWITCH agent: <true|false>
|
||||
"sessions_conns": ["*internal"],
|
||||
|
||||
@@ -268,10 +268,11 @@ type AstConnJsonCfg struct {
|
||||
}
|
||||
|
||||
type AsteriskAgentJsonCfg struct {
|
||||
Enabled *bool
|
||||
Sessions_conns *[]string
|
||||
Create_cdr *bool
|
||||
Asterisk_conns *[]*AstConnJsonCfg
|
||||
Enabled *bool
|
||||
Sessions_conns *[]string
|
||||
Create_cdr *bool
|
||||
Alterable_fields *[]string
|
||||
Asterisk_conns *[]*AstConnJsonCfg
|
||||
}
|
||||
|
||||
type CacheParamJsonCfg struct {
|
||||
|
||||
@@ -20,6 +20,7 @@ package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -598,10 +599,11 @@ func (aConnCfg *AsteriskConnCfg) AsMapInterface() map[string]any {
|
||||
}
|
||||
|
||||
type AsteriskAgentCfg struct {
|
||||
Enabled bool
|
||||
SessionSConns []string
|
||||
CreateCDR bool
|
||||
AsteriskConns []*AsteriskConnCfg
|
||||
Enabled bool
|
||||
SessionSConns []string
|
||||
CreateCDR bool
|
||||
AlterableFields []string
|
||||
AsteriskConns []*AsteriskConnCfg
|
||||
}
|
||||
|
||||
func (aCfg *AsteriskAgentCfg) loadFromJsonCfg(jsnCfg *AsteriskAgentJsonCfg) (err error) {
|
||||
@@ -625,6 +627,9 @@ func (aCfg *AsteriskAgentCfg) loadFromJsonCfg(jsnCfg *AsteriskAgentJsonCfg) (err
|
||||
if jsnCfg.Create_cdr != nil {
|
||||
aCfg.CreateCDR = *jsnCfg.Create_cdr
|
||||
}
|
||||
if jsnCfg.Alterable_fields != nil {
|
||||
aCfg.AlterableFields = *jsnCfg.Alterable_fields
|
||||
}
|
||||
if jsnCfg.Asterisk_conns != nil {
|
||||
aCfg.AsteriskConns = make([]*AsteriskConnCfg, len(*jsnCfg.Asterisk_conns))
|
||||
for i, jsnAConn := range *jsnCfg.Asterisk_conns {
|
||||
@@ -652,9 +657,10 @@ func (aCfg *AsteriskAgentCfg) AsMapInterface() map[string]any {
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
utils.EnabledCfg: aCfg.Enabled,
|
||||
utils.SessionSConnsCfg: sessionSConns,
|
||||
utils.CreateCDRCfg: aCfg.CreateCDR,
|
||||
utils.AsteriskConnsCfg: conns,
|
||||
utils.EnabledCfg: aCfg.Enabled,
|
||||
utils.SessionSConnsCfg: sessionSConns,
|
||||
utils.CreateCDRCfg: aCfg.CreateCDR,
|
||||
utils.AlterableFieldsCfg: slices.Clone(aCfg.AlterableFields),
|
||||
utils.AsteriskConnsCfg: conns,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,15 +497,17 @@ func TestAsteriskAgentCfgAsMapInterface(t *testing.T) {
|
||||
"enabled": true,
|
||||
"sessions_conns": ["*internal"],
|
||||
"create_cdr": false,
|
||||
"alterable_fields": ["field1", "field2"],
|
||||
"asterisk_conns":[
|
||||
{"address": "127.0.0.1:8088", "user": "cgrates", "password": "CGRateS.org", "connect_attempts": 3,"reconnects": 5}
|
||||
],
|
||||
},
|
||||
}`
|
||||
eMap := map[string]any{
|
||||
"enabled": true,
|
||||
"sessions_conns": []string{"*internal"},
|
||||
"create_cdr": false,
|
||||
"enabled": true,
|
||||
"sessions_conns": []string{"*internal"},
|
||||
"create_cdr": false,
|
||||
utils.AlterableFieldsCfg: []string{"field1", "field2"},
|
||||
"asterisk_conns": []map[string]any{
|
||||
{"alias": "", "address": "127.0.0.1:8088", "user": "cgrates", "password": "CGRateS.org", "connect_attempts": 3, "reconnects": 5},
|
||||
},
|
||||
@@ -517,7 +519,7 @@ func TestAsteriskAgentCfgAsMapInterface(t *testing.T) {
|
||||
} else if err = asagcfg.loadFromJsonCfg(jsnAsAgCfg); err != nil {
|
||||
t.Error(err)
|
||||
} else if rcv := asagcfg.AsMapInterface(); !reflect.DeepEqual(eMap, rcv) {
|
||||
t.Errorf("\nExpected: %+v\nReceived: %+v", utils.ToJSON(eMap), utils.ToJSON(rcv))
|
||||
t.Errorf("expected: %s, received: %s", utils.ToJSON(eMap), utils.ToJSON(rcv))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -912,9 +914,10 @@ func TestSMConfigAsteriskAgentCfgloadFromJsonCfg(t *testing.T) {
|
||||
func TestSMConfigAsteriskAgentCfgAsMapInterface(t *testing.T) {
|
||||
str := "test"
|
||||
aCfg := &AsteriskAgentCfg{
|
||||
Enabled: false,
|
||||
SessionSConns: []string{str},
|
||||
CreateCDR: false,
|
||||
Enabled: false,
|
||||
SessionSConns: []string{str},
|
||||
CreateCDR: false,
|
||||
AlterableFields: []string{"field1", "field2"},
|
||||
AsteriskConns: []*AsteriskConnCfg{
|
||||
{
|
||||
Alias: str,
|
||||
@@ -927,15 +930,14 @@ func TestSMConfigAsteriskAgentCfgAsMapInterface(t *testing.T) {
|
||||
},
|
||||
}
|
||||
exp := map[string]any{
|
||||
utils.EnabledCfg: aCfg.Enabled,
|
||||
utils.SessionSConnsCfg: []string{str},
|
||||
utils.CreateCDRCfg: aCfg.CreateCDR,
|
||||
utils.AsteriskConnsCfg: []map[string]any{aCfg.AsteriskConns[0].AsMapInterface()},
|
||||
utils.EnabledCfg: aCfg.Enabled,
|
||||
utils.SessionSConnsCfg: []string{str},
|
||||
utils.CreateCDRCfg: aCfg.CreateCDR,
|
||||
utils.AlterableFieldsCfg: []string{"field1", "field2"},
|
||||
utils.AsteriskConnsCfg: []map[string]any{aCfg.AsteriskConns[0].AsMapInterface()},
|
||||
}
|
||||
|
||||
rcv := aCfg.AsMapInterface()
|
||||
|
||||
if !reflect.DeepEqual(exp, rcv) {
|
||||
if rcv := aCfg.AsMapInterface(); !reflect.DeepEqual(exp, rcv) {
|
||||
t.Errorf("expected %s, received %s", utils.ToJSON(exp), utils.ToJSON(rcv))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user