From c67ec00baac303af1778832f07b6f43f6e26e46c Mon Sep 17 00:00:00 2001 From: ionutboangiu Date: Wed, 21 Feb 2024 11:50:46 -0500 Subject: [PATCH] Implement *alter_sessions action --- agents/radius_coa_it_test.go | 14 ++------ engine/action.go | 68 ++++++++++++++++++++++++++++++++++++ engine/actions_test.go | 41 ++++++++++++++++++++++ utils/consts.go | 1 + 4 files changed, 112 insertions(+), 12 deletions(-) diff --git a/agents/radius_coa_it_test.go b/agents/radius_coa_it_test.go index 84522e98e..01765a858 100644 --- a/agents/radius_coa_it_test.go +++ b/agents/radius_coa_it_test.go @@ -100,18 +100,8 @@ func TestRadiusCoADisconnect(t *testing.T) { actRadCoaAcnt1001 := &utils.AttrSetActions{ ActionsId: "ACT_RAD_COA_ACNT_1001", Actions: []*utils.TPAction{{ - Identifier: utils.MetaCgrRpc, - ExtraParameters: `{ - "Address":"localhost:2012", - "Attempts":1, - "Transport":"*json", - "Method":"SessionSv1.AlterSessions", - "Params":{ - "Filters":["*string:~*req.Account:1001"], - "Tenant":"cgrates.org", - "APIOpts":{"*radCoATemplate":"mycoa"}, - "Event":{"CustomFilter":"custom_filter"}}, - "Id":2}`, + Identifier: utils.MetaAlterSessions, + ExtraParameters: "cgrates.org;*string:~*req.Account:1001;1;*radCoATemplate:mycoa;CustomFilter:custom_filter", }}} if err := raDiscRPC.Call(context.Background(), utils.APIerSv2SetActions, actRadCoaAcnt1001, &reply); err != nil { diff --git a/engine/action.go b/engine/action.go index 68725b60d..83e958b85 100644 --- a/engine/action.go +++ b/engine/action.go @@ -102,6 +102,7 @@ func init() { actionFuncMap[utils.MetaSetBalance] = setBalanceAction actionFuncMap[utils.MetaTransferMonetaryDefault] = transferMonetaryDefaultAction actionFuncMap[utils.MetaCgrRpc] = cgrRPCAction + actionFuncMap[utils.MetaAlterSessions] = alterSessionsAction actionFuncMap[utils.TopUpZeroNegative] = topupZeroNegativeAction actionFuncMap[utils.SetExpiry] = setExpiryAction actionFuncMap[utils.MetaPublishAccount] = publishAccount @@ -849,6 +850,73 @@ func cgrRPCAction(ub *Account, a *Action, acs Actions, _ *FilterS, extraData any return } +func alterSessionsAction(_ *Account, a *Action, _ Actions, _ *FilterS, _ any) error { + client, err := rpcclient.NewRPCClient(context.TODO(), utils.TCP, + config.CgrConfig().ListenCfg().RPCJSONListen, + false, "", "", "", 1, 0, + config.CgrConfig().GeneralCfg().MaxReconnectInterval, + utils.FibDuration, + config.CgrConfig().GeneralCfg().ConnectTimeout, + config.CgrConfig().GeneralCfg().ReplyTimeout, + utils.MetaJSON, nil, false, nil) + if err != nil { + return err + } + + // Parse action parameters, expecting 5 parameters separated by ";". + params := strings.Split(a.ExtraParameters, ";") + if len(params) != 5 { + return errors.New("invalid number of parameters; expected 5") + } + + // Default limit to 1 if not specified, else parse the limit from parameters. + var limit int + if params[2] == "" { + limit = 1 + } else { + if limit, err = strconv.Atoi(params[2]); err != nil { + return fmt.Errorf("invalid limit parameter: %s", params[2]) + } + } + + // Prepare request argument with provided parameters. + attr := utils.SessionFilterWithEvent{ + SessionFilter: &utils.SessionFilter{ + Limit: &limit, + Tenant: params[0], + Filters: strings.Split(params[1], "&"), + APIOpts: make(map[string]any), + }, + Event: make(map[string]any), + } + + // Use default tenant if not specified. + if attr.Tenant == "" { + attr.Tenant = config.CgrConfig().GeneralCfg().DefaultTenant + } + + // Parse API options and event parameters from provided strings. + parseKVParams := func(paramStr string, targetMap map[string]any) error { + for _, tuple := range strings.Split(paramStr, "&") { + key, value, found := strings.Cut(tuple, ":") + if !found { + return fmt.Errorf("invalid key-value pair: %s", tuple) + } + targetMap[key] = value + } + return nil + } + if err := parseKVParams(params[3], attr.APIOpts); err != nil { + return err + } + if err := parseKVParams(params[4], attr.Event); err != nil { + return err + } + + var reply string + return client.Call(context.Background(), utils.SessionSv1AlterSessions, attr, &reply) +} + func topupZeroNegativeAction(ub *Account, a *Action, acs Actions, fltrS *FilterS, extraData any) error { if ub == nil { return errors.New("nil account") diff --git a/engine/actions_test.go b/engine/actions_test.go index 10cfcd599..db327a2fa 100644 --- a/engine/actions_test.go +++ b/engine/actions_test.go @@ -4574,3 +4574,44 @@ func TestActionsTransferBalance(t *testing.T) { }) } } + +// func TestActionsAlterSessions(t *testing.T) { + +// testcases := []struct { +// name string +// extraParams string +// expectedErr string +// }{ +// { +// name: "SuccessfulParse", +// extraParams: "tenant.com;*string:~*req.Account:1001&*prefix:~*req.Destination:+40;1;*radCoATemplate:mytemplate&secondopt:secondval;Account:1002&Destination:+40123456", +// expectedErr: utils.ErrNotFound.Error(), +// }, +// { +// name: "WrongNumberOfParams", +// extraParams: "tenant;;1;", +// }, +// { +// name: "InvalidMap", +// extraParams: "tenant;;1;opt:value;key", +// }, +// } + +// for _, tc := range testcases { +// t.Run(tc.name, func(t *testing.T) { +// action := &Action{ +// ExtraParameters: tc.extraParams, +// } +// err := alterSessionsAction(nil, action, nil, nil, nil) +// if tc.expectedErr != "" { +// if err == nil || err.Error() != tc.expectedErr { +// t.Errorf("expected error %v, received %v", tc.expectedErr, err) +// } +// return +// } +// if err != nil { +// t.Error(err) +// } +// }) +// } +// } diff --git a/utils/consts.go b/utils/consts.go index 943483ff3..6d3898d55 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -1056,6 +1056,7 @@ const ( MetaSetDDestinations = "*set_ddestinations" MetaTransferMonetaryDefault = "*transfer_monetary_default" MetaCgrRpc = "*cgr_rpc" + MetaAlterSessions = "*alter_sessions" TopUpZeroNegative = "*topup_zero_negative" SetExpiry = "*set_expiry" MetaPublishAccount = "*publish_account"