diff --git a/apis/tpes.go b/apis/tpes.go
new file mode 100644
index 000000000..95798e3db
--- /dev/null
+++ b/apis/tpes.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 apis
+
+import (
+ "github.com/cgrates/cgrates/tpes"
+)
+
+func NewTpeSv1(tpes *tpes.TpeS) *TpeSv1 {
+ return &TpeSv1{tpes: tpes}
+}
+
+type TpeSv1 struct {
+ tpes *tpes.TpeS
+ ping
+}
diff --git a/apis/tpes_it_test.go b/apis/tpes_it_test.go
new file mode 100644
index 000000000..99b3e83c7
--- /dev/null
+++ b/apis/tpes_it_test.go
@@ -0,0 +1,120 @@
+//go:build integration
+// +build integration
+
+/*
+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 apis
+
+import (
+ "path"
+ "testing"
+
+ "github.com/cgrates/birpc"
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/utils"
+)
+
+var (
+ tpesCfgPath string
+ tpesCfg *config.CGRConfig
+ tpeSRPC *birpc.Client
+ tpeSConfigDIR string //run tests for specific configuration
+
+ sTestTpes = []func(t *testing.T){
+ testTpeSInitCfg,
+ testTpeSInitDataDb,
+ testTpeSResetStorDb,
+ testTpeSStartEngine,
+ testTpeSRPCConn,
+ testTpeSPing,
+ testTpeSKillEngine,
+ }
+)
+
+func TestTpeSIT(t *testing.T) {
+ switch *dbType {
+ case utils.MetaInternal:
+ tpeSConfigDIR = "tutinternal"
+ case utils.MetaMongo:
+ tpeSConfigDIR = "tutmongo"
+ case utils.MetaMySQL:
+ tpeSConfigDIR = "tutmysql"
+ case utils.MetaPostgres:
+ t.SkipNow()
+ default:
+ t.Fatal("Unknown Database type")
+ }
+ for _, stest := range sTestTpes {
+ t.Run(tpeSConfigDIR, stest)
+ }
+}
+
+func testTpeSInitCfg(t *testing.T) {
+ var err error
+ tpesCfgPath = path.Join(*dataDir, "conf", "samples", tpeSConfigDIR)
+ tpesCfg, err = config.NewCGRConfigFromPath(context.Background(), tpesCfgPath)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func testTpeSInitDataDb(t *testing.T) {
+ if err := engine.InitDataDB(tpesCfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testTpeSResetStorDb(t *testing.T) {
+ if err := engine.InitStorDB(tpesCfg); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Start CGR Engine
+func testTpeSStartEngine(t *testing.T) {
+ if _, err := engine.StopStartEngine(tpesCfgPath, *waitRater); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func testTpeSPing(t *testing.T) {
+ var reply string
+ if err := tpeSRPC.Call(context.Background(), utils.TpeSv1Ping, &utils.CGREvent{}, &reply); err != nil {
+ t.Error(err)
+ } else if reply != utils.Pong {
+ t.Errorf("Unexpected reply returned: %s", reply)
+ }
+}
+
+func testTpeSRPCConn(t *testing.T) {
+ var err error
+ tpeSRPC, err = newRPCClient(tpesCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+//Kill the engine when it is about to be finished
+func testTpeSKillEngine(t *testing.T) {
+ if err := engine.KillEngine(100); err != nil {
+ t.Error(err)
+ }
+}
diff --git a/config/config.go b/config/config.go
index 91ebfd45b..db1b666a8 100644
--- a/config/config.go
+++ b/config/config.go
@@ -203,6 +203,7 @@ func newCGRConfig(config []byte) (cfg *CGRConfig, err error) {
MaxItems: []*utils.DynamicIntPointerOpt{},
Usage: []*utils.DynamicDecimalBigOpt{},
}},
+ tpeSCfg: new(TpeSCfg),
sureTaxCfg: new(SureTaxCfg),
dispatcherSCfg: new(DispatcherSCfg),
registrarCCfg: &RegistrarCCfgs{
@@ -352,6 +353,7 @@ type CGRConfig struct {
apiBanCfg *APIBanCfg // APIBan config
coreSCfg *CoreSCfg // CoreS config
accountSCfg *AccountSCfg // AccountS config
+ tpeSCfg *TpeSCfg // TpeS config
configDBCfg *ConfigDBCfg // ConfigDB conifg
cacheDP utils.MapStorage
@@ -687,6 +689,13 @@ func (cfg *CGRConfig) AccountSCfg() *AccountSCfg {
return cfg.accountSCfg
}
+// TpeSCfg reads the TpeS configuration
+func (cfg *CGRConfig) TpeSCfg() *TpeSCfg {
+ cfg.Lock(TpeSJSON)
+ defer cfg.Unlock(TpeSJSON)
+ return cfg.tpeSCfg
+}
+
// SIPAgentCfg reads the Apier configuration
func (cfg *CGRConfig) SIPAgentCfg() *SIPAgentCfg {
cfg.lks[SIPAgentJSON].Lock()
@@ -1037,6 +1046,7 @@ func (cfg *CGRConfig) Clone() (cln *CGRConfig) {
coreSCfg: cfg.coreSCfg.Clone(),
actionSCfg: cfg.actionSCfg.Clone(),
accountSCfg: cfg.accountSCfg.Clone(),
+ tpeSCfg: cfg.tpeSCfg.Clone(),
configDBCfg: cfg.configDBCfg.Clone(),
rldCh: make(chan string),
cacheDP: make(utils.MapStorage),
diff --git a/config/config_defaults.go b/config/config_defaults.go
index 905e88b35..d5051017b 100644
--- a/config/config_defaults.go
+++ b/config/config_defaults.go
@@ -1822,5 +1822,9 @@ const CGRATES_CFG_JSON = `
}
},
+"tpes": {
+ "enabled": false,
+},
+
}`
diff --git a/config/config_json.go b/config/config_json.go
index d70c5dfb8..0dced2000 100644
--- a/config/config_json.go
+++ b/config/config_json.go
@@ -45,6 +45,7 @@ const (
ResourceSJSON = "resources"
StatSJSON = "stats"
ThresholdSJSON = "thresholds"
+ TpeSJSON = "tpes"
RouteSJSON = "routes"
LoaderSJSON = "loaders"
SureTaxJSON = "suretax"
@@ -104,6 +105,7 @@ var (
AccountSJSON: utils.AccountS,
ActionSJSON: utils.ActionS,
CoreSJSON: utils.CoreS,
+ TpeSJSON: utils.TpeS,
RPCConnsJSON: RPCConnsJSON,
}
)
@@ -192,6 +194,7 @@ func newSections(cfg *CGRConfig) Sections {
cfg.apiBanCfg,
cfg.configDBCfg,
cfg.sureTaxCfg,
+ cfg.tpeSCfg,
}
}
diff --git a/config/tpes.go b/config/tpes.go
new file mode 100644
index 000000000..210a5f836
--- /dev/null
+++ b/config/tpes.go
@@ -0,0 +1,69 @@
+/*
+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
+
+import (
+ "github.com/cgrates/birpc/context"
+
+ "github.com/cgrates/cgrates/utils"
+)
+
+type TpeSCfg struct {
+ Enabled bool
+}
+
+type TpeSCfgJson struct {
+ Enabled *bool
+}
+
+func (TpeSCfg) SName() string { return TpeSJSON }
+
+func (tp *TpeSCfg) Load(ctx *context.Context, db ConfigDB, _ *CGRConfig) (err error) {
+ jsn := new(TpeSCfgJson)
+ if err = db.GetSection(ctx, tp.SName(), jsn); err != nil {
+ return
+ }
+ if jsn.Enabled != nil {
+ tp.Enabled = *jsn.Enabled
+ }
+ return
+}
+
+func (tp TpeSCfg) AsMapInterface(string) interface{} {
+ return map[string]interface{}{
+ utils.EnabledCfg: tp.Enabled,
+ }
+}
+
+func (tp TpeSCfg) CloneSection() Section {
+ return tp.Clone()
+}
+
+func (tp TpeSCfg) Clone() (tpCln *TpeSCfg) {
+ return &TpeSCfg{
+ Enabled: tp.Enabled,
+ }
+}
+
+func diffTpeSCfgJson(d *TpeSCfgJson, v1, v2 *TpeSCfg) *TpeSCfgJson {
+ if d == nil {
+ d = new(TpeSCfgJson)
+ }
+ if v1.Enabled != v2.Enabled {
+ d.Enabled = utils.BoolPointer(v2.Enabled)
+ }
+ return d
+}
diff --git a/data/conf/samples/tutinternal/cgrates.json b/data/conf/samples/tutinternal/cgrates.json
index 749d7b322..f08148976 100644
--- a/data/conf/samples/tutinternal/cgrates.json
+++ b/data/conf/samples/tutinternal/cgrates.json
@@ -127,4 +127,8 @@
"accounts_conns": ["*internal"],
},
+"tpes": {
+ "enabled": true
+},
+
}
diff --git a/data/conf/samples/tutmongo/cgrates.json b/data/conf/samples/tutmongo/cgrates.json
index 7bc909c29..32bc8c6cf 100644
--- a/data/conf/samples/tutmongo/cgrates.json
+++ b/data/conf/samples/tutmongo/cgrates.json
@@ -140,6 +140,9 @@
"accounts_conns": ["*internal"],
},
+"tpes": {
+ "enabled": true
+},
}
diff --git a/data/conf/samples/tutmysql/cgrates.json b/data/conf/samples/tutmysql/cgrates.json
index 45994b4ec..005a5483d 100644
--- a/data/conf/samples/tutmysql/cgrates.json
+++ b/data/conf/samples/tutmysql/cgrates.json
@@ -118,5 +118,8 @@
"accounts_conns": ["*internal"],
},
+"tpes": {
+ "enabled": true
+},
}
diff --git a/services/cgr-engine.go b/services/cgr-engine.go
index 7525fbbe7..e8352d188 100644
--- a/services/cgr-engine.go
+++ b/services/cgr-engine.go
@@ -79,6 +79,7 @@ func NewCGREngine(cfg *config.CGRConfig, cM *engine.ConnManager, shdWg *sync.Wai
utils.ThresholdS: new(sync.WaitGroup),
utils.ActionS: new(sync.WaitGroup),
utils.AccountS: new(sync.WaitGroup),
+ utils.TpeS: new(sync.WaitGroup),
},
iFilterSCh: make(chan *engine.FilterS, 1),
}
@@ -159,6 +160,7 @@ func (cgr *CGREngine) InitServices(httpPrfPath string, cpuPrfFl io.Closer, memPr
iRateSCh := make(chan birpc.ClientConnector, 1)
iActionSCh := make(chan birpc.ClientConnector, 1)
iAccountSCh := make(chan birpc.ClientConnector, 1)
+ iTpeSCh := make(chan birpc.ClientConnector, 1)
// initialize the connManager before creating the DMService
// because we need to pass the connection to it
@@ -184,6 +186,7 @@ func (cgr *CGREngine) InitServices(httpPrfPath string, cpuPrfFl io.Closer, memPr
cgr.cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaDispatchers), utils.DispatcherSv1, cgr.iDispatcherSCh)
cgr.cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaAccounts), utils.AccountSv1, iAccountSCh)
cgr.cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaActions), utils.ActionSv1, iActionSCh)
+ cgr.cM.AddInternalConn(utils.ConcatenatedKey(utils.MetaInternal, utils.MetaTpes), utils.TpeSv1, iTpeSCh)
cgr.gvS = NewGlobalVarS(cgr.cfg, cgr.srvDep)
cgr.dmS = NewDataDBService(cgr.cfg, cgr.cM, cgr.srvDep)
@@ -247,6 +250,7 @@ func (cgr *CGREngine) InitServices(httpPrfPath string, cpuPrfFl io.Closer, memPr
cgr.server, iRateSCh, cgr.anzS, cgr.srvDep),
NewActionService(cgr.cfg, cgr.dmS, cgr.cacheS, cgr.iFilterSCh, cgr.cM, cgr.server, iActionSCh, cgr.anzS, cgr.srvDep),
NewAccountService(cgr.cfg, cgr.dmS, cgr.cacheS, cgr.iFilterSCh, cgr.cM, cgr.server, iAccountSCh, cgr.anzS, cgr.srvDep),
+ NewTpeService(cgr.cfg, cgr.cM, cgr.server, cgr.srvDep),
)
return
diff --git a/services/tpes.go b/services/tpes.go
new file mode 100644
index 000000000..f74bf0842
--- /dev/null
+++ b/services/tpes.go
@@ -0,0 +1,95 @@
+/*
+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 services
+
+import (
+ "fmt"
+ "sync"
+
+ "github.com/cgrates/birpc"
+ "github.com/cgrates/birpc/context"
+ "github.com/cgrates/cgrates/apis"
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/cores"
+ "github.com/cgrates/cgrates/engine"
+ "github.com/cgrates/cgrates/servmanager"
+ "github.com/cgrates/cgrates/tpes"
+ "github.com/cgrates/cgrates/utils"
+)
+
+// NewTpeService is the constructor for the TpeService
+func NewTpeService(cfg *config.CGRConfig, connMgr *engine.ConnManager,
+ server *cores.Server, srvDep map[string]*sync.WaitGroup) servmanager.Service {
+ return &TpeService{
+ cfg: cfg,
+ srvDep: srvDep,
+ connMgr: connMgr,
+ server: server,
+ }
+}
+
+// TypeService implements Service interface
+type TpeService struct {
+ sync.RWMutex
+
+ cfg *config.CGRConfig
+ server *cores.Server
+ connMgr *engine.ConnManager
+ tpes *tpes.TpeS
+ srv *birpc.Service
+ stopChan chan struct{}
+
+ srvDep map[string]*sync.WaitGroup
+}
+
+// Start should handle the service start
+func (tpSrv *TpeService) Start(ctx *context.Context, _ context.CancelFunc) (err error) {
+ tpSrv.tpes = tpes.NewTpeS(tpSrv.cfg, tpSrv.connMgr)
+ utils.Logger.Info(fmt.Sprintf("<%s> starting <%s> subsystem", utils.CoreS, utils.TpeS))
+ tpSrv.stopChan = make(chan struct{})
+ tpSrv.srv, _ = birpc.NewService(apis.NewTpeSv1(tpSrv.tpes), utils.EmptyString, false)
+ tpSrv.server.RpcRegister(tpSrv.srv)
+ return
+}
+
+// Reload handles the change of config
+func (tpSrv *TpeService) Reload(*context.Context, context.CancelFunc) (err error) {
+ return
+}
+
+// Shutdown stops the service
+func (tpSrv *TpeService) Shutdown() (err error) {
+ tpSrv.srv = nil
+ close(tpSrv.stopChan)
+ return
+}
+
+// IsRunning returns if the service is running
+func (tpSrv *TpeService) IsRunning() bool {
+ tpSrv.Lock()
+ defer tpSrv.Unlock()
+ return tpSrv != nil && tpSrv.tpes != nil
+}
+
+// ServiceName returns the service name
+func (tpSrv *TpeService) ServiceName() string {
+ return utils.TpeS
+}
+
+// ShouldRun returns if the service should be running
+func (tpSrv *TpeService) ShouldRun() bool {
+ return tpSrv.cfg.TpeSCfg().Enabled
+}
diff --git a/tpes/tpes.go b/tpes/tpes.go
new file mode 100644
index 000000000..acdde15ce
--- /dev/null
+++ b/tpes/tpes.go
@@ -0,0 +1,35 @@
+/*
+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 tpes
+
+import (
+ "github.com/cgrates/cgrates/config"
+ "github.com/cgrates/cgrates/engine"
+)
+
+func NewTpeS(cfg *config.CGRConfig, cm *engine.ConnManager) *TpeS {
+ return &TpeS{
+ cfg: cfg,
+ connMgr: cm,
+ }
+}
+
+// TpeS is managing the TariffPlanExporter
+type TpeS struct {
+ cfg *config.CGRConfig
+ connMgr *engine.ConnManager
+ fltr *engine.FilterS
+}
diff --git a/utils/consts.go b/utils/consts.go
index d75198a4a..99f0eb71b 100644
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -370,6 +370,7 @@ const (
MetaServiceManager = "*servicemanager"
MetaChargers = "*chargers"
MetaConfig = "*config"
+ MetaTpes = "*tpes"
MetaDispatchers = "*dispatchers"
MetaDispatcherHosts = "*dispatcher_hosts"
MetaFilters = "*filters"
@@ -921,6 +922,7 @@ const (
RegistrarC = "RegistrarC"
LoaderS = "LoaderS"
ChargerS = "ChargerS"
+ TpeS = "TpeS"
CacheS = "CacheS"
AnalyzerS = "AnalyzerS"
CDRServer = "CDRServer"
@@ -1250,24 +1252,12 @@ const (
// APIerSv1GetLoadIDs = "APIerSv1.GetLoadIDs"
// APIerSv1GetLoadTimes = "APIerSv1.GetLoadTimes"
AdminSv1GetAttributeProfilesCount = "AdminSv1.GetAttributeProfilesCount"
- // APIerSv1GetTPActionProfile = "APIerSv1.GetTPActionProfile"
- // APIerSv1SetTPActionProfile = "APIerSv1.SetTPActionProfile"
- // APIerSv1GetTPActionProfileIDs = "APIerSv1.GetTPActionProfileIDs"
- // APIerSv1RemoveTPActionProfile = "APIerSv1.RemoveTPActionProfile"
- // APIerSv1GetTPRateProfile = "APIerSv1.GetTPRateProfile"
- // APIerSv1SetTPRateProfile = "APIerSv1.SetTPRateProfile"
- // APIerSv1GetTPRateProfileIds = "APIerSv1.GetTPRateProfileIds"
- // APIerSv1RemoveTPRateProfile = "APIerSv1.RemoveTPRateProfile"
- AdminSv1SetAccount = "AdminSv1.SetAccount"
- AdminSv1GetAccount = "AdminSv1.GetAccount"
- AdminSv1GetAccounts = "AdminSv1.GetAccounts"
- AdminSv1GetAccountIDs = "AdminSv1.GetAccountIDs"
- AdminSv1RemoveAccount = "AdminSv1.RemoveAccount"
- AdminSv1GetAccountsCount = "AdminSv1.GetAccountsCount"
- // APIerSv1GetTPAccountIDs = "APIerSv1.GetTPAccountIDs"
- // APIerSv1GetTPAccount = "APIerSv1.GetTPAccount"
- // APIerSv1SetTPAccount = "APIerSv1.SetTPAccount"
- // APIerSv1RemoveTPAccount = "APIerSv1.RemoveTPAccount"
+ AdminSv1SetAccount = "AdminSv1.SetAccount"
+ AdminSv1GetAccount = "AdminSv1.GetAccount"
+ AdminSv1GetAccounts = "AdminSv1.GetAccounts"
+ AdminSv1GetAccountIDs = "AdminSv1.GetAccountIDs"
+ AdminSv1RemoveAccount = "AdminSv1.RemoveAccount"
+ AdminSv1GetAccountsCount = "AdminSv1.GetAccountsCount"
)
// APIerSv1 TP APIs
@@ -1284,6 +1274,12 @@ const (
ServiceManagerV1Ping = "ServiceManagerV1.Ping"
)
+// TpeSv1 APIs
+const (
+ TpeSv1 = "TpeSv1"
+ TpeSv1Ping = "TpeSv1.Ping"
+)
+
// ConfigSv1 APIs
const (
ConfigS = "ConfigS"