diff --git a/agents/httpagent_it_test.go b/agents/httpagent_it_test.go index c004e166a..76708478e 100644 --- a/agents/httpagent_it_test.go +++ b/agents/httpagent_it_test.go @@ -57,14 +57,10 @@ func TestHAitInitCfg(t *testing.T) { } // Remove data in both rating and accounting db -func TestHAitResetDataDb(t *testing.T) { +func TestHAitResetDB(t *testing.T) { if err := engine.InitDataDb(haCfg); err != nil { t.Fatal(err) } -} - -// Wipe out the cdr database -func TestHAitResetStorDb(t *testing.T) { if err := engine.InitStorDb(haCfg); err != nil { t.Fatal(err) } diff --git a/config/chargerscfg.go b/config/chargerscfg.go new file mode 100644 index 000000000..074332a59 --- /dev/null +++ b/config/chargerscfg.go @@ -0,0 +1,58 @@ +/* +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 + +// SupplierSCfg is the configuration of supplier service +type ChargerSCfg struct { + Enabled bool + AttributeSConns []*HaPoolConfig + StringIndexedFields *[]string + PrefixIndexedFields *[]string +} + +func (cS *ChargerSCfg) loadFromJsonCfg(jsnCfg *ChargerSJsonCfg) (err error) { + if jsnCfg == nil { + return + } + if jsnCfg.Enabled != nil { + cS.Enabled = *jsnCfg.Enabled + } + if jsnCfg.Attributes_conns != nil { + cS.AttributeSConns = make([]*HaPoolConfig, len(*jsnCfg.Attributes_conns)) + for idx, jsnHaCfg := range *jsnCfg.Attributes_conns { + cS.AttributeSConns[idx] = NewDfltHaPoolConfig() + cS.AttributeSConns[idx].loadFromJsonCfg(jsnHaCfg) + } + } + if jsnCfg.String_indexed_fields != nil { + sif := make([]string, len(*jsnCfg.String_indexed_fields)) + for i, fID := range *jsnCfg.String_indexed_fields { + sif[i] = fID + } + cS.StringIndexedFields = &sif + } + if jsnCfg.Prefix_indexed_fields != nil { + pif := make([]string, len(*jsnCfg.Prefix_indexed_fields)) + for i, fID := range *jsnCfg.Prefix_indexed_fields { + pif[i] = fID + } + cS.PrefixIndexedFields = &pif + } + return +} diff --git a/config/config.go b/config/config.go index c36219a51..f9f1b6083 100755 --- a/config/config.go +++ b/config/config.go @@ -341,19 +341,20 @@ type CGRConfig struct { CdreProfiles map[string]*CdreConfig CdrcProfiles map[string][]*CdrcConfig // Number of CDRC instances running imports, format map[dirPath][]{Configs} sessionSCfg *SessionSCfg - fsAgentCfg *FsAgentConfig // FreeSWITCHAgent configuration - kamAgentCfg *KamAgentCfg // KamailioAgent Configuration - SmOsipsConfig *SmOsipsConfig // SMOpenSIPS Configuration - asteriskAgentCfg *AsteriskAgentCfg // SMAsterisk Configuration - diameterAgentCfg *DiameterAgentCfg // DiameterAgent configuration - radiusAgentCfg *RadiusAgentCfg // RadiusAgent configuration - httpAgentCfg []*HttpAgentCfg // HttpAgent configuration - filterSCfg *FilterSCfg // FilterS configuration - PubSubServerEnabled bool // Starts PubSub as server: . - AliasesServerEnabled bool // Starts PubSub as server: . - UserServerEnabled bool // Starts User as server: - UserServerIndexes []string // List of user profile field indexes - attributeSCfg *AttributeSCfg // Attribute service configuration + fsAgentCfg *FsAgentConfig // FreeSWITCHAgent configuration + kamAgentCfg *KamAgentCfg // KamailioAgent Configuration + SmOsipsConfig *SmOsipsConfig // SMOpenSIPS Configuration + asteriskAgentCfg *AsteriskAgentCfg // SMAsterisk Configuration + diameterAgentCfg *DiameterAgentCfg // DiameterAgent configuration + radiusAgentCfg *RadiusAgentCfg // RadiusAgent configuration + httpAgentCfg []*HttpAgentCfg // HttpAgent configuration + filterSCfg *FilterSCfg // FilterS configuration + PubSubServerEnabled bool // Starts PubSub as server: . + AliasesServerEnabled bool // Starts PubSub as server: . + UserServerEnabled bool // Starts User as server: + UserServerIndexes []string // List of user profile field indexes + attributeSCfg *AttributeSCfg // Attribute service configuration + chargerSCfg *ChargerSCfg resourceSCfg *ResourceSConfig // Configuration for resource limiter statsCfg *StatSCfg // Configuration for StatS thresholdSCfg *ThresholdSCfg // configuration for ThresholdS @@ -646,6 +647,14 @@ func (self *CGRConfig) checkConfigSanity() error { } } } + if self.chargerSCfg != nil && self.chargerSCfg.Enabled { + for _, connCfg := range self.chargerSCfg.AttributeSConns { + if connCfg.Address == utils.MetaInternal && + (self.attributeSCfg == nil || !self.attributeSCfg.Enabled) { + return errors.New("AttributeS not enabled but requested by ChargerS component.") + } + } + } // ResourceLimiter checks if self.resourceSCfg != nil && self.resourceSCfg.Enabled { for _, connCfg := range self.resourceSCfg.ThresholdSConns { @@ -818,6 +827,11 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { return err } + jsnChargerSCfg, err := jsnCfg.ChargerServJsonCfg() + if err != nil { + return err + } + jsnRLSCfg, err := jsnCfg.ResourceSJsonCfg() if err != nil { return err @@ -1376,6 +1390,15 @@ func (self *CGRConfig) loadFromJsonCfg(jsnCfg *CgrJsonCfg) (err error) { } } + if jsnChargerSCfg != nil { + if self.chargerSCfg == nil { + self.chargerSCfg = new(ChargerSCfg) + } + if self.chargerSCfg.loadFromJsonCfg(jsnChargerSCfg); err != nil { + return err + } + } + if jsnRLSCfg != nil { if self.resourceSCfg == nil { self.resourceSCfg = new(ResourceSConfig) @@ -1496,6 +1519,10 @@ func (cfg *CGRConfig) AttributeSCfg() *AttributeSCfg { return cfg.attributeSCfg } +func (cfg *CGRConfig) ChargerSCfg() *ChargerSCfg { + return cfg.chargerSCfg +} + // ToDo: fix locking here func (self *CGRConfig) ResourceSCfg() *ResourceSConfig { return self.resourceSCfg diff --git a/config/config_defaults.go b/config/config_defaults.go index 5c6dc034a..031314365 100755 --- a/config/config_defaults.go +++ b/config/config_defaults.go @@ -429,6 +429,14 @@ const CGRATES_CFG_JSON = ` }, +"chargers": { // Charger service + "enabled": false, // starts charger service: . + "attributes_conns": [], // address where to reach the AttributeS <""|127.0.0.1:2013> + //"string_indexed_fields": [], // query indexes based on these fields for faster processing + "prefix_indexed_fields": [], // query indexes based on these fields for faster processing +}, + + "resources": { // Resource service (*new) "enabled": false, // starts ResourceLimiter service: . "store_interval": "", // dump cache regularly to dataDB, 0 - dump at start/shutdown: <""|$dur> diff --git a/config/config_json.go b/config/config_json.go index 70b56e7af..52cb0dada 100644 --- a/config/config_json.go +++ b/config/config_json.go @@ -67,6 +67,7 @@ const ( DispatcherSJson = "dispatcher" CgrLoaderCfgJson = "loader" CgrMigratorCfgJson = "migrator" + ChargerSCfgJson = "chargers" ) // Loads the json config out of io.Reader, eg other sources than file, maybe over http @@ -368,6 +369,18 @@ func (cgrJsn CgrJsonCfg) AttributeServJsonCfg() (*AttributeSJsonCfg, error) { return cfg, nil } +func (cgrJsn CgrJsonCfg) ChargerServJsonCfg() (*ChargerSJsonCfg, error) { + rawCfg, hasKey := cgrJsn[ChargerSCfgJson] + if !hasKey { + return nil, nil + } + cfg := new(ChargerSJsonCfg) + if err := json.Unmarshal(*rawCfg, cfg); err != nil { + return nil, err + } + return cfg, nil +} + func (self CgrJsonCfg) ResourceSJsonCfg() (*ResourceSJsonCfg, error) { rawCfg, hasKey := self[RESOURCES_JSON] if !hasKey { diff --git a/config/config_json_test.go b/config/config_json_test.go index e0751d0b9..9906559ba 100755 --- a/config/config_json_test.go +++ b/config/config_json_test.go @@ -705,6 +705,20 @@ func TestDfAttributeServJsonCfg(t *testing.T) { } } +func TestDfChargerServJsonCfg(t *testing.T) { + eCfg := &ChargerSJsonCfg{ + Enabled: utils.BoolPointer(false), + Attributes_conns: &[]*HaPoolJsonCfg{}, + String_indexed_fields: nil, + Prefix_indexed_fields: &[]string{}, + } + if cfg, err := dfCgrJsonCfg.ChargerServJsonCfg(); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(eCfg, cfg) { + t.Error("Received: ", cfg) + } +} + func TestDfFilterSJsonCfg(t *testing.T) { eCfg := &FilterSJsonCfg{ Stats_conns: &[]*HaPoolJsonCfg{}, diff --git a/config/config_test.go b/config/config_test.go index 90628520d..3bfc82409 100755 --- a/config/config_test.go +++ b/config/config_test.go @@ -801,6 +801,18 @@ func TestCgrCfgJSONDefaultSAttributeSCfg(t *testing.T) { } } +func TestCgrCfgJSONDefaultSChargerSCfg(t *testing.T) { + eChargerSCfg := &ChargerSCfg{ + Enabled: false, + AttributeSConns: []*HaPoolConfig{}, + StringIndexedFields: nil, + PrefixIndexedFields: &[]string{}, + } + if !reflect.DeepEqual(eChargerSCfg, cgrCfg.chargerSCfg) { + t.Errorf("received: %+v, expecting: %+v", eChargerSCfg, cgrCfg.chargerSCfg) + } +} + func TestCgrCfgJSONDefaultsResLimCfg(t *testing.T) { eResLiCfg := &ResourceSConfig{ Enabled: false, diff --git a/config/libconfig_json.go b/config/libconfig_json.go index d3bcd1096..66136dbf0 100755 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -429,6 +429,14 @@ type AttributeSJsonCfg struct { Prefix_indexed_fields *[]string } +// ChargerSJsonCfg service config section +type ChargerSJsonCfg struct { + Enabled *bool + Attributes_conns *[]*HaPoolJsonCfg + String_indexed_fields *[]string + Prefix_indexed_fields *[]string +} + // ResourceLimiter service config section type ResourceSJsonCfg struct { Enabled *bool diff --git a/data/tariffplans/tutorial/Chargers.csv b/data/tariffplans/tutorial/Chargers.csv new file mode 100644 index 000000000..d9f4caed0 --- /dev/null +++ b/data/tariffplans/tutorial/Chargers.csv @@ -0,0 +1 @@ +#Tenant,ID,FilterIDs,ActivationInterval,RunID,AttributeIDs,Weight \ No newline at end of file diff --git a/engine/chargers.go b/engine/chargers.go new file mode 100644 index 000000000..95c5fb7a3 --- /dev/null +++ b/engine/chargers.go @@ -0,0 +1,54 @@ +/* +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 engine + +import ( + "fmt" + + "github.com/cgrates/cgrates/utils" +) + +func NewChargerService(dm *DataManager, filterS *FilterS, + strgIdxFlds, prfxIdxFlds *[]string) (*ChargerService, error) { + return &ChargerService{dm: dm, filterS: filterS, + strgIdxFlds: strgIdxFlds, + prfxIdxFlds: prfxIdxFlds}, nil +} + +type ChargerService struct { + dm *DataManager + filterS *FilterS + strgIdxFlds *[]string + prfxIdxFlds *[]string +} + +// ListenAndServe will initialize the service +func (cS *ChargerService) ListenAndServe(exitChan chan bool) (err error) { + utils.Logger.Info(fmt.Sprintf("Starting %s", utils.ChargerS)) + e := <-exitChan + exitChan <- e + return +} + +// Shutdown is called to shutdown the service +func (cS *ChargerService) Shutdown() (err error) { + utils.Logger.Info(fmt.Sprintf("<%s> shutdown initialized", utils.ChargerS)) + utils.Logger.Info(fmt.Sprintf("<%s> shutdown complete", utils.ChargerS)) + return +} diff --git a/engine/models.go b/engine/models.go index 8c5e8f9d1..11e7e5114 100644 --- a/engine/models.go +++ b/engine/models.go @@ -558,3 +558,16 @@ type TPAttribute struct { Weight float64 `index:"9" re:"\d+\.?\d*"` CreatedAt time.Time } + +type TPCharger struct { + PK uint `gorm:"primary_key"` + Tpid string + Tenant string `index:"0" re:""` + ID string `index:"1" re:""` + FilterIDs string `index:"2" re:""` + ActivationInterval string `index:"3" re:""` + RunID string `index:"4" re:""` + AttributeIDs string `index:"5" re:""` + Weight float64 `index:"6" re:"\d+\.?\d*"` + CreatedAt time.Time +} diff --git a/utils/consts.go b/utils/consts.go index 53f03e03d..fad828173 100755 --- a/utils/consts.go +++ b/utils/consts.go @@ -655,6 +655,7 @@ const ( APIKey = "APIKey" APIMethods = "APIMethods" NestingSep = "." + ChargerS = "ChargerS" ) // MetaFilterIndexesAPIs