diff --git a/actions/actions.go b/actions/actions.go index 301a3fa23..0e121b3fc 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -66,3 +66,56 @@ func (aS *ActionS) Shutdown() (err error) { func (aS *ActionS) Call(serviceMethod string, args interface{}, reply interface{}) error { return utils.RPCCall(aS, serviceMethod, args, reply) } + +// matchingActionProfilesForEvent returns the matched ActionProfiles for the given event +func (aS *ActionS) matchingActionProfilesForEvent(tnt string, aPrflIDs []string, + cgrEv *utils.CGREventWithOpts) (actPrfls engine.ActionProfiles, err error) { + evNm := utils.MapStorage{ + utils.MetaReq: cgrEv.CGREvent.Event, + utils.MetaOpts: cgrEv.Opts, + } + if len(aPrflIDs) == 0 { + var aPfIDMp utils.StringSet + if aPfIDMp, err = engine.MatchingItemIDsForEvent( + evNm, + aS.cfg.ActionSCfg().StringIndexedFields, + aS.cfg.ActionSCfg().PrefixIndexedFields, + aS.cfg.ActionSCfg().SuffixIndexedFields, + aS.dm, + utils.CacheActionProfilesFilterIndexes, + tnt, + aS.cfg.ActionSCfg().IndexedSelects, + aS.cfg.ActionSCfg().NestedFields, + ); err != nil { + return + } + aPrflIDs = aPfIDMp.AsSlice() + } + for _, aPfID := range aPrflIDs { + var aPf *engine.ActionProfile + if aPf, err = aS.dm.GetActionProfile(tnt, aPfID, + true, true, utils.NonTransactional); err != nil { + if err == utils.ErrNotFound { + err = nil + continue + } + return + } + if aPf.ActivationInterval != nil && cgrEv.Time != nil && + !aPf.ActivationInterval.IsActiveAtTime(*cgrEv.Time) { // not active + continue + } + var pass bool + if pass, err = aS.fltrS.Pass(tnt, aPf.FilterIDs, evNm); err != nil { + return + } else if !pass { + continue + } + actPrfls = append(actPrfls, aPf) + } + if len(actPrfls) == 0 { + return nil, utils.ErrNotFound + } + actPrfls.Sort() + return +} diff --git a/config/actionscfg.go b/config/actionscfg.go new file mode 100644 index 000000000..4c5117656 --- /dev/null +++ b/config/actionscfg.go @@ -0,0 +1,29 @@ +/* +Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments +Copyright (C) ITsysCOM GmbH + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ + +package config + +// ActionSCfg is the configuration of ActionS +type ActionSCfg struct { + Enabled bool + IndexedSelects bool + StringIndexedFields *[]string + PrefixIndexedFields *[]string + SuffixIndexedFields *[]string + NestedFields bool +} diff --git a/config/config.go b/config/config.go index ad7928854..2e2460844 100644 --- a/config/config.go +++ b/config/config.go @@ -194,6 +194,7 @@ func newCGRConfig(config []byte) (cfg *CGRConfig, err error) { cfg.eesCfg = new(EEsCfg) cfg.eesCfg.Cache = make(map[string]*CacheParamCfg) cfg.rateSCfg = new(RateSCfg) + //cfg.actionSCfg = new(ActionSCfg) cfg.sipAgentCfg = new(SIPAgentCfg) cfg.configSCfg = new(ConfigSCfg) cfg.apiBanCfg = new(APIBanCfg) @@ -326,6 +327,7 @@ type CGRConfig struct { ersCfg *ERsCfg // EventReader config eesCfg *EEsCfg // EventExporter config rateSCfg *RateSCfg // RateS config + actionSCfg *ActionSCfg // ActionS config sipAgentCfg *SIPAgentCfg // SIPAgent config configSCfg *ConfigSCfg // ConfigS config apiBanCfg *APIBanCfg // APIBan config @@ -1088,6 +1090,13 @@ func (cfg *CGRConfig) RateSCfg() *RateSCfg { return cfg.rateSCfg } +// ActionSCfg reads the ActionS configuration +func (cfg *CGRConfig) ActionSCfg() *ActionSCfg { + cfg.lks[ActionSJson].RLock() + defer cfg.lks[ActionSJson].RUnlock() + return cfg.actionSCfg +} + // SIPAgentCfg reads the Apier configuration func (cfg *CGRConfig) SIPAgentCfg() *SIPAgentCfg { cfg.lks[SIPAgentJson].Lock() diff --git a/config/config_json.go b/config/config_json.go index ab9d3a999..d75be742e 100644 --- a/config/config_json.go +++ b/config/config_json.go @@ -60,6 +60,7 @@ const ( ERsJson = "ers" EEsJson = "ees" RateSJson = "rates" + ActionSJson = "actions" RPCConnsJsonName = "rpc_conns" SIPAgentJson = "sip_agent" TemplatesJson = "templates" diff --git a/engine/actionprofile.go b/engine/actionprofile.go index aa3c65c8b..85a3132bc 100644 --- a/engine/actionprofile.go +++ b/engine/actionprofile.go @@ -19,6 +19,7 @@ along with this program. If not, see package engine import ( + "sort" "time" "github.com/cgrates/cgrates/config" @@ -42,6 +43,14 @@ func (aP *ActionProfile) TenantID() string { return utils.ConcatenatedKey(aP.Tenant, aP.ID) } +// ActionProfiles is a sortable list of ActionProfiles +type ActionProfiles []*ActionProfile + +// Sort is part of sort interface, sort based on Weight +func (aps ActionProfiles) Sort() { + sort.Slice(aps, func(i, j int) bool { return aps[i].Weight > aps[j].Weight }) +} + // APAction defines action related information used within a ActionProfile type APAction struct { ID string // Action ID @@ -54,6 +63,7 @@ type APAction struct { Value config.RSRParsers // Value to execute on path } +// ActionProfileWithOpts is used in API calls type ActionProfileWithOpts struct { *ActionProfile Opts map[string]interface{}