mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-12 18:46:24 +05:00
486 lines
13 KiB
Go
486 lines
13 KiB
Go
/*
|
|
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 <http://www.gnu.org/licenses/>
|
|
*/
|
|
|
|
package config
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/cgrates/birpc/context"
|
|
"github.com/cgrates/cgrates/utils"
|
|
"github.com/cgrates/rpcclient"
|
|
)
|
|
|
|
// NewDfltRPCConn returns the default value for a RPCConn
|
|
func NewDfltRPCConn() *RPCConn {
|
|
return &RPCConn{Strategy: rpcclient.PoolFirst}
|
|
}
|
|
|
|
// RPCConns the config for all rpc pools
|
|
type RPCConns map[string]*RPCConn
|
|
|
|
// loadRPCConns loads the RPCConns section of the configuration
|
|
func (rC RPCConns) Load(ctx *context.Context, jsnCfg ConfigDB, _ *CGRConfig) (err error) {
|
|
jsnRPCConns := make(RPCConnsJson)
|
|
if err = jsnCfg.GetSection(ctx, RPCConnsJSON, &jsnRPCConns); err != nil {
|
|
return
|
|
}
|
|
rC.loadFromJSONCfg(jsnRPCConns)
|
|
return
|
|
}
|
|
|
|
func (rC RPCConns) loadFromJSONCfg(jsn RPCConnsJson) {
|
|
// hardoded the *internal connection
|
|
rC[utils.MetaInternal] = &RPCConn{
|
|
Strategy: rpcclient.PoolFirst,
|
|
PoolSize: 0,
|
|
Conns: []*RemoteHost{{
|
|
Address: utils.MetaInternal,
|
|
}},
|
|
}
|
|
rC[rpcclient.BiRPCInternal] = &RPCConn{
|
|
Strategy: rpcclient.PoolFirst,
|
|
PoolSize: 0,
|
|
Conns: []*RemoteHost{{
|
|
Address: rpcclient.BiRPCInternal,
|
|
}},
|
|
}
|
|
rC[utils.MetaLocalHost] = &RPCConn{
|
|
Strategy: rpcclient.PoolFirst,
|
|
PoolSize: 0,
|
|
Conns: []*RemoteHost{{
|
|
Address: "127.0.0.1:2012",
|
|
Transport: utils.MetaJSON,
|
|
}},
|
|
}
|
|
rC[utils.MetaBiJSONLocalHost] = &RPCConn{
|
|
Strategy: rpcclient.PoolFirst,
|
|
PoolSize: 0,
|
|
Conns: []*RemoteHost{{
|
|
Address: "127.0.0.1:2014",
|
|
Transport: rpcclient.BiRPCJSON,
|
|
}},
|
|
}
|
|
for key, val := range jsn {
|
|
rC[key] = NewDfltRPCConn()
|
|
rC[key].loadFromJSONCfg(val)
|
|
}
|
|
}
|
|
|
|
// AsMapInterface returns the config as a map[string]interface{}
|
|
func (rC RPCConns) AsMapInterface(string) interface{} {
|
|
rpcConns := make(map[string]interface{})
|
|
for key, value := range rC {
|
|
rpcConns[key] = value.AsMapInterface()
|
|
}
|
|
return rpcConns
|
|
}
|
|
|
|
func (RPCConns) SName() string { return RPCConnsJSON }
|
|
func (rC RPCConns) CloneSection() Section { return rC.Clone() }
|
|
|
|
// Clone returns a deep copy of RPCConns
|
|
func (rC RPCConns) Clone() (cln RPCConns) {
|
|
cln = make(RPCConns)
|
|
for id, conn := range rC {
|
|
cln[id] = conn.Clone()
|
|
}
|
|
return
|
|
}
|
|
|
|
// RPCConn the connection pool config
|
|
type RPCConn struct {
|
|
Strategy string
|
|
PoolSize int
|
|
ReplyTimeout time.Duration
|
|
Conns []*RemoteHost
|
|
}
|
|
|
|
func (rC *RPCConn) loadFromJSONCfg(jsnCfg *RPCConnJson) (err error) {
|
|
if jsnCfg == nil {
|
|
return
|
|
}
|
|
if jsnCfg.Strategy != nil {
|
|
rC.Strategy = *jsnCfg.Strategy
|
|
}
|
|
if jsnCfg.PoolSize != nil {
|
|
rC.PoolSize = *jsnCfg.PoolSize
|
|
}
|
|
if jsnCfg.Reply_timeout != nil {
|
|
if rC.ReplyTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.Reply_timeout); err != nil {
|
|
return
|
|
}
|
|
}
|
|
if jsnCfg.Conns != nil {
|
|
rC.Conns = make([]*RemoteHost, len(*jsnCfg.Conns))
|
|
for idx, jsnHaCfg := range *jsnCfg.Conns {
|
|
rC.Conns[idx] = getDftRemHstCfg()
|
|
rC.Conns[idx].loadFromJSONCfg(jsnHaCfg) //To review if the function signature changes
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// AsMapInterface returns the config as a map[string]interface{}
|
|
func (rC *RPCConn) AsMapInterface() (mp map[string]interface{}) {
|
|
mp = map[string]interface{}{
|
|
utils.StrategyCfg: rC.Strategy,
|
|
utils.PoolSize: rC.PoolSize,
|
|
}
|
|
if rC.ReplyTimeout != 0 {
|
|
mp[utils.ReplyTimeoutCfg] = rC.ReplyTimeout
|
|
}
|
|
if rC.Conns != nil {
|
|
conns := make([]map[string]interface{}, len(rC.Conns))
|
|
for i, item := range rC.Conns {
|
|
conns[i] = item.AsMapInterface()
|
|
}
|
|
mp[utils.Conns] = conns
|
|
}
|
|
return
|
|
}
|
|
|
|
// Clone returns a deep copy of RPCConn
|
|
func (rC RPCConn) Clone() (cln *RPCConn) {
|
|
cln = &RPCConn{
|
|
Strategy: rC.Strategy,
|
|
PoolSize: rC.PoolSize,
|
|
ReplyTimeout: rC.ReplyTimeout,
|
|
}
|
|
if rC.Conns != nil {
|
|
cln.Conns = make([]*RemoteHost, len(rC.Conns))
|
|
for i, req := range rC.Conns {
|
|
cln.Conns[i] = req.Clone()
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// RemoteHost connection config
|
|
type RemoteHost struct {
|
|
ID string
|
|
Address string
|
|
Transport string
|
|
ConnectAttempts int
|
|
Reconnects int
|
|
MaxReconnectInterval time.Duration
|
|
ConnectTimeout time.Duration
|
|
ReplyTimeout time.Duration
|
|
TLS bool
|
|
ClientKey string
|
|
ClientCertificate string
|
|
CaCertificate string
|
|
}
|
|
|
|
func (rh *RemoteHost) loadFromJSONCfg(jsnCfg *RemoteHostJson) (err error) {
|
|
if jsnCfg == nil {
|
|
return
|
|
}
|
|
if jsnCfg.Id != nil {
|
|
rh.ID = *jsnCfg.Id
|
|
// ignore defaults if we have ID
|
|
rh.Address = utils.EmptyString
|
|
rh.Transport = utils.EmptyString
|
|
}
|
|
if jsnCfg.Address != nil {
|
|
rh.Address = *jsnCfg.Address
|
|
}
|
|
if jsnCfg.Transport != nil {
|
|
rh.Transport = *jsnCfg.Transport
|
|
}
|
|
if jsnCfg.Tls != nil {
|
|
rh.TLS = *jsnCfg.Tls
|
|
}
|
|
if jsnCfg.Client_key != nil {
|
|
rh.ClientKey = *jsnCfg.Client_key
|
|
}
|
|
if jsnCfg.Client_certificate != nil {
|
|
rh.ClientCertificate = *jsnCfg.Client_certificate
|
|
}
|
|
if jsnCfg.Ca_certificate != nil {
|
|
rh.CaCertificate = *jsnCfg.Ca_certificate
|
|
}
|
|
if jsnCfg.Connect_attempts != nil {
|
|
rh.ConnectAttempts = *jsnCfg.Connect_attempts
|
|
}
|
|
if jsnCfg.Reconnects != nil {
|
|
rh.Reconnects = *jsnCfg.Reconnects
|
|
}
|
|
if jsnCfg.Max_reconnect_interval != nil {
|
|
if rh.MaxReconnectInterval, err = utils.ParseDurationWithNanosecs(*jsnCfg.Max_reconnect_interval); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if jsnCfg.Connect_timeout != nil {
|
|
if rh.ConnectTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.Connect_timeout); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if jsnCfg.Reply_timeout != nil {
|
|
if rh.ReplyTimeout, err = utils.ParseDurationWithNanosecs(*jsnCfg.Reply_timeout); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// AsMapInterface returns the config as a map[string]interface{}
|
|
func (rh *RemoteHost) AsMapInterface() (mp map[string]interface{}) {
|
|
mp = map[string]interface{}{
|
|
utils.AddressCfg: rh.Address,
|
|
utils.TransportCfg: rh.Transport,
|
|
}
|
|
if rh.ID != utils.EmptyString {
|
|
mp[utils.IDCfg] = rh.ID
|
|
}
|
|
if rh.TLS {
|
|
mp[utils.TLSNoCaps] = rh.TLS
|
|
}
|
|
if rh.ClientKey != utils.EmptyString {
|
|
mp[utils.KeyPathCgr] = rh.ClientKey
|
|
}
|
|
if rh.ClientCertificate != utils.EmptyString {
|
|
mp[utils.CertPathCgr] = rh.ClientCertificate
|
|
}
|
|
if rh.CaCertificate != utils.EmptyString {
|
|
mp[utils.CAPathCgr] = rh.CaCertificate
|
|
}
|
|
if rh.ConnectAttempts != 0 {
|
|
mp[utils.ConnectAttemptsCfg] = rh.ConnectAttempts
|
|
}
|
|
if rh.Reconnects != 0 {
|
|
mp[utils.ReconnectsCfg] = rh.Reconnects
|
|
}
|
|
if rh.MaxReconnectInterval != 0 {
|
|
mp[utils.MaxReconnectIntervalCfg] = rh.MaxReconnectInterval.String()
|
|
}
|
|
if rh.ConnectTimeout != 0 {
|
|
mp[utils.ConnectTimeoutCfg] = rh.ConnectTimeout
|
|
}
|
|
if rh.ReplyTimeout != 0 {
|
|
mp[utils.ReplyTimeoutCfg] = rh.ReplyTimeout
|
|
}
|
|
return
|
|
}
|
|
|
|
// Clone returns a deep copy of RemoteHost
|
|
func (rh RemoteHost) Clone() (cln *RemoteHost) {
|
|
return &RemoteHost{
|
|
ID: rh.ID,
|
|
Address: rh.Address,
|
|
Transport: rh.Transport,
|
|
TLS: rh.TLS,
|
|
ClientKey: rh.ClientKey,
|
|
ClientCertificate: rh.ClientCertificate,
|
|
CaCertificate: rh.CaCertificate,
|
|
ConnectAttempts: rh.ConnectAttempts,
|
|
Reconnects: rh.Reconnects,
|
|
MaxReconnectInterval: rh.MaxReconnectInterval,
|
|
ConnectTimeout: rh.ConnectTimeout,
|
|
ReplyTimeout: rh.ReplyTimeout,
|
|
}
|
|
}
|
|
|
|
// UpdateRPCCons will parse each conn and update only
|
|
// the conns that have the same ID
|
|
func UpdateRPCCons(rpcConns RPCConns, newHosts map[string]*RemoteHost) (connIDs utils.StringSet) {
|
|
connIDs = make(utils.StringSet)
|
|
for rpcKey, rpcPool := range rpcConns {
|
|
for _, rh := range rpcPool.Conns {
|
|
newHost, has := newHosts[rh.ID]
|
|
if !has {
|
|
continue
|
|
}
|
|
connIDs.Add(rpcKey)
|
|
rh.Address = newHost.Address
|
|
rh.Transport = newHost.Transport
|
|
rh.TLS = newHost.TLS
|
|
rh.ClientKey = newHost.ClientKey
|
|
rh.ClientCertificate = newHost.ClientCertificate
|
|
rh.CaCertificate = newHost.CaCertificate
|
|
rh.ConnectAttempts = newHost.ConnectAttempts
|
|
rh.Reconnects = newHost.Reconnects
|
|
rh.MaxReconnectInterval = newHost.MaxReconnectInterval
|
|
rh.ConnectTimeout = newHost.ConnectTimeout
|
|
rh.ReplyTimeout = newHost.ReplyTimeout
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// RemoveRPCCons will parse each conn and reset only
|
|
// the conns that have the same ID
|
|
func RemoveRPCCons(rpcConns RPCConns, hosts utils.StringSet) (connIDs utils.StringSet) {
|
|
connIDs = make(utils.StringSet)
|
|
for rpcKey, rpcPool := range rpcConns {
|
|
for _, rh := range rpcPool.Conns {
|
|
if !hosts.Has(rh.ID) {
|
|
continue
|
|
}
|
|
connIDs.Add(rpcKey)
|
|
rh.Address = ""
|
|
rh.Transport = ""
|
|
rh.TLS = false
|
|
rh.ClientKey = ""
|
|
rh.ClientCertificate = ""
|
|
rh.CaCertificate = ""
|
|
rh.ConnectAttempts = 0
|
|
rh.Reconnects = 0
|
|
rh.MaxReconnectInterval = 0
|
|
rh.ConnectTimeout = 0
|
|
rh.ReplyTimeout = 0
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// Represents one connection instance towards a rater/cdrs server
|
|
type RemoteHostJson struct {
|
|
Id *string
|
|
Address *string
|
|
Transport *string
|
|
Connect_attempts *int
|
|
Reconnects *int
|
|
Max_reconnect_interval *string
|
|
Connect_timeout *string
|
|
Reply_timeout *string
|
|
Tls *bool
|
|
Client_certificate *string
|
|
Client_key *string
|
|
Ca_certificate *string
|
|
}
|
|
|
|
func diffRemoteHostJson(v1, v2 *RemoteHost) (d *RemoteHostJson) {
|
|
d = new(RemoteHostJson)
|
|
if v1.ID != v2.ID {
|
|
d.Id = utils.StringPointer(v2.ID)
|
|
}
|
|
if v1.Address != v2.Address {
|
|
d.Address = utils.StringPointer(v2.Address)
|
|
}
|
|
if v1.Transport != v2.Transport {
|
|
d.Transport = utils.StringPointer(v2.Transport)
|
|
}
|
|
if v1.TLS != v2.TLS {
|
|
d.Tls = utils.BoolPointer(v2.TLS)
|
|
}
|
|
if v1.ClientKey != v2.ClientKey {
|
|
d.Client_key = utils.StringPointer(v2.ClientKey)
|
|
}
|
|
if v1.ClientCertificate != v2.ClientCertificate {
|
|
d.Client_certificate = utils.StringPointer(v2.ClientCertificate)
|
|
}
|
|
if v1.ClientCertificate != v2.ClientCertificate {
|
|
d.Ca_certificate = utils.StringPointer(v2.CaCertificate)
|
|
}
|
|
if v1.ConnectAttempts != v2.ConnectAttempts {
|
|
d.Connect_attempts = utils.IntPointer(v2.ConnectAttempts)
|
|
}
|
|
if v1.Reconnects != v2.Reconnects {
|
|
d.Reconnects = utils.IntPointer(v2.Reconnects)
|
|
}
|
|
if v1.MaxReconnectInterval != v2.MaxReconnectInterval {
|
|
d.Max_reconnect_interval = utils.StringPointer(v2.MaxReconnectInterval.String())
|
|
}
|
|
if v1.ConnectTimeout != v2.ConnectTimeout {
|
|
d.Connect_timeout = utils.StringPointer(v2.ConnectTimeout.String())
|
|
}
|
|
if v1.ReplyTimeout != v2.ReplyTimeout {
|
|
d.Reply_timeout = utils.StringPointer(v2.ReplyTimeout.String())
|
|
}
|
|
return
|
|
}
|
|
|
|
type RPCConnJson struct {
|
|
Strategy *string
|
|
PoolSize *int
|
|
Reply_timeout *string
|
|
Conns *[]*RemoteHostJson
|
|
}
|
|
|
|
func diffRPCConnJson(d *RPCConnJson, v1, v2 *RPCConn) *RPCConnJson {
|
|
if d == nil {
|
|
d = new(RPCConnJson)
|
|
}
|
|
if v1.Strategy != v2.Strategy {
|
|
d.Strategy = utils.StringPointer(v2.Strategy)
|
|
}
|
|
if v1.PoolSize != v2.PoolSize {
|
|
d.PoolSize = utils.IntPointer(v2.PoolSize)
|
|
}
|
|
if v1.ReplyTimeout != v2.ReplyTimeout {
|
|
d.Reply_timeout = utils.StringPointer(v2.ReplyTimeout.String())
|
|
}
|
|
if v2.Conns != nil {
|
|
conns := make([]*RemoteHostJson, len(v2.Conns))
|
|
dft := getDftRemHstCfg()
|
|
for i, conn := range v2.Conns {
|
|
conns[i] = diffRemoteHostJson(dft, conn)
|
|
}
|
|
d.Conns = &conns
|
|
}
|
|
return d
|
|
}
|
|
|
|
func equalsRemoteHosts(v1, v2 []*RemoteHost) bool {
|
|
if len(v1) != len(v2) {
|
|
return false
|
|
}
|
|
for i := range v2 {
|
|
if v1[i].ID != v2[i].ID ||
|
|
v1[i].Address != v2[i].Address ||
|
|
v1[i].Transport != v2[i].Transport ||
|
|
v1[i].TLS != v2[i].TLS ||
|
|
v1[i].ClientKey != v2[i].ClientKey ||
|
|
v1[i].ClientCertificate != v2[i].ClientCertificate ||
|
|
v1[i].CaCertificate != v2[i].CaCertificate ||
|
|
v1[i].ConnectAttempts != v2[i].ConnectAttempts ||
|
|
v1[i].Reconnects != v2[i].Reconnects ||
|
|
v1[i].MaxReconnectInterval != v2[i].MaxReconnectInterval ||
|
|
v1[i].ConnectTimeout != v2[i].ConnectTimeout ||
|
|
v1[i].ReplyTimeout != v2[i].ReplyTimeout {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func equalsRPCConn(v1, v2 *RPCConn) bool {
|
|
return (v1 == nil && v2 == nil) ||
|
|
(v1 != nil && v2 != nil &&
|
|
v1.Strategy == v2.Strategy &&
|
|
v1.PoolSize == v2.PoolSize &&
|
|
v1.ReplyTimeout == v2.ReplyTimeout &&
|
|
equalsRemoteHosts(v1.Conns, v2.Conns))
|
|
}
|
|
|
|
type RPCConnsJson map[string]*RPCConnJson
|
|
|
|
func diffRPCConnsJson(d RPCConnsJson, v1, v2 RPCConns) RPCConnsJson {
|
|
if d == nil {
|
|
d = make(RPCConnsJson)
|
|
}
|
|
dft := NewDfltRPCConn()
|
|
for k, val := range v2 {
|
|
if !equalsRPCConn(v1[k], val) {
|
|
d[k] = diffRPCConnJson(d[k], dft, val)
|
|
}
|
|
}
|
|
return d
|
|
}
|