func startSmFreeSWITCH(internalRaterChan chan *engine.Responder, cdrDb engine.CdrStorage, exitChan chan bool) { engine.Logger.Info("Starting CGRateS SM-FreeSWITCH service.") var raterConn, cdrsConn engine.ConnectorPool var client *rpcclient.RpcClient var err error delay := utils.Fib() for _, raterCfg := range cfg.SmFsConfig.HaRater { if raterCfg.Server == utils.INTERNAL { resp := <-internalRaterChan raterConn = append(raterConn, resp) internalRaterChan <- resp } for i := 0; i < cfg.Reconnects; i++ { client, err = rpcclient.NewRpcClient("tcp", raterCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err == nil { //Connected so no need to reiterate break } time.Sleep(delay()) } if err != nil { engine.Logger.Crit(fmt.Sprintf("<SM-FreeSWITCH> Could not connect to rater via RPC: %v", err)) exitChan <- true return } raterConn = append(raterConn, &engine.RPCClientConnector{Client: client, Timeout: raterCfg.Timeout}) } if reflect.DeepEqual(cfg.SmFsConfig.HaCdrs, cfg.SmFsConfig.HaRater) { cdrsConn = raterConn } else if len(cfg.SmFsConfig.HaCdrs) != 0 { delay = utils.Fib() for _, cdrsCfg := range cfg.SmFsConfig.HaCdrs { if cdrsCfg.Server == utils.INTERNAL { resp := <-internalRaterChan raterConn = append(raterConn, resp) internalRaterChan <- resp } for i := 0; i < cfg.Reconnects; i++ { client, err = rpcclient.NewRpcClient("tcp", cdrsCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err == nil { //Connected so no need to reiterate break } time.Sleep(delay()) } if err != nil { engine.Logger.Crit(fmt.Sprintf("<SM-FreeSWITCH> Could not connect to CDRS via RPC: %v", err)) exitChan <- true return } cdrsConn = append(cdrsConn, &engine.RPCClientConnector{Client: client, Timeout: cdrsCfg.Timeout}) } } sm := sessionmanager.NewFSSessionManager(cfg.SmFsConfig, raterConn, cdrsConn, cfg.DefaultTimezone) sms = append(sms, sm) smRpc.SMs = append(smRpc.SMs, sm) if err = sm.Connect(); err != nil { engine.Logger.Err(fmt.Sprintf("<SessionManager> error: %s!", err)) } exitChan <- true }
func NewRPCPool(dispatchStrategy string, connAttempts, reconnects int, connectTimeout, replyTimeout time.Duration, rpcConnCfgs []*config.HaPoolConfig, internalConnChan chan rpcclient.RpcClientConnection, ttl time.Duration) (*rpcclient.RpcClientPool, error) { var rpcClient *rpcclient.RpcClient var err error rpcPool := rpcclient.NewRpcClientPool(dispatchStrategy, replyTimeout) atLestOneConnected := false // If one connected we don't longer return errors for _, rpcConnCfg := range rpcConnCfgs { if rpcConnCfg.Address == utils.MetaInternal { var internalConn rpcclient.RpcClientConnection select { case internalConn = <-internalConnChan: internalConnChan <- internalConn case <-time.After(ttl): return nil, errors.New("TTL triggered") } rpcClient, err = rpcclient.NewRpcClient("", "", connAttempts, reconnects, connectTimeout, replyTimeout, rpcclient.INTERNAL_RPC, internalConn, false) } else if utils.IsSliceMember([]string{utils.MetaJSONrpc, utils.MetaGOBrpc, ""}, rpcConnCfg.Transport) { codec := utils.GOB if rpcConnCfg.Transport != "" { codec = rpcConnCfg.Transport[1:] // Transport contains always * before codec understood by rpcclient } rpcClient, err = rpcclient.NewRpcClient("tcp", rpcConnCfg.Address, connAttempts, reconnects, connectTimeout, replyTimeout, codec, nil, false) } else { return nil, fmt.Errorf("Unsupported transport: <%s>", rpcConnCfg.Transport) } if err == nil { atLestOneConnected = true } rpcPool.AddClient(rpcClient) } if atLestOneConnected { err = nil } return rpcPool, err }
func startDiameterAgent(internalSMGChan chan rpcclient.RpcClientConnection, exitChan chan bool) { utils.Logger.Info("Starting CGRateS DiameterAgent service.") var smgConn *rpcclient.RpcClient var err error if cfg.DiameterAgentCfg().SMGeneric == utils.INTERNAL { smgRpc := <-internalSMGChan internalSMGChan <- smgRpc smgConn, err = rpcclient.NewRpcClient("", "", 0, 0, rpcclient.INTERNAL_RPC, smgRpc) } else { smgConn, err = rpcclient.NewRpcClient("tcp", cfg.DiameterAgentCfg().SMGeneric, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil) } if err != nil { utils.Logger.Crit(fmt.Sprintf("<DiameterAgent> Could not connect to SMG: %s", err.Error())) exitChan <- true return } da, err := agents.NewDiameterAgent(cfg, smgConn) if err != nil { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> error: %s!", err)) exitChan <- true return } if err = da.ListenAndServe(); err != nil { utils.Logger.Err(fmt.Sprintf("<DiameterAgent> error: %s!", err)) } exitChan <- true }
func startSmGeneric(internalSMGChan chan rpcclient.RpcClientConnection, internalRaterChan chan *engine.Responder, server *utils.Server, exitChan chan bool) { utils.Logger.Info("Starting CGRateS SM-Generic service.") var raterConn, cdrsConn engine.Connector var client *rpcclient.RpcClient var err error // Connect to rater for _, raterCfg := range cfg.SmGenericConfig.HaRater { if raterCfg.Server == utils.INTERNAL { resp := <-internalRaterChan raterConn = resp // Will overwrite here for the sake of keeping internally the new configuration format for ha connections internalRaterChan <- resp } else { client, err = rpcclient.NewRpcClient("tcp", raterCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil) if err != nil { //Connected so no need to reiterate utils.Logger.Crit(fmt.Sprintf("<SM-Generic> Could not connect to Rater via RPC: %v", err)) exitChan <- true return } raterConn = &engine.RPCClientConnector{Client: client} } } // Connect to CDRS if reflect.DeepEqual(cfg.SmGenericConfig.HaCdrs, cfg.SmGenericConfig.HaRater) { cdrsConn = raterConn } else if len(cfg.SmGenericConfig.HaCdrs) != 0 { for _, cdrsCfg := range cfg.SmGenericConfig.HaCdrs { if cdrsCfg.Server == utils.INTERNAL { resp := <-internalRaterChan cdrsConn = resp internalRaterChan <- resp } else { client, err = rpcclient.NewRpcClient("tcp", cdrsCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil) if err != nil { utils.Logger.Crit(fmt.Sprintf("<SM-Generic> Could not connect to CDRS via RPC: %v", err)) exitChan <- true return } cdrsConn = &engine.RPCClientConnector{Client: client} } } } smg_econns := sessionmanager.NewSMGExternalConnections() sm := sessionmanager.NewSMGeneric(cfg, raterConn, cdrsConn, cfg.DefaultTimezone, smg_econns) if err = sm.Connect(); err != nil { utils.Logger.Err(fmt.Sprintf("<SM-Generic> error: %s!", err)) } // Register RPC handler smgRpc := v1.NewSMGenericV1(sm) server.RpcRegister(smgRpc) internalSMGChan <- smgRpc // Register BiRpc handlers smgBiRpc := v1.NewSMGenericBiRpcV1(sm) for method, handler := range smgBiRpc.Handlers() { server.BijsonRegisterName(method, handler) } // Register OnConnect handlers so we can intercept connections for session disconnects server.BijsonRegisterOnConnect(smg_econns.OnClientConnect) server.BijsonRegisterOnDisconnect(smg_econns.OnClientDisconnect) }
// Connect rpc client to rater func TestCdrsHttpCdrReplication(t *testing.T) { if !*testIntegration { return } cdrsMasterRpc, err := rpcclient.NewRpcClient("tcp", cdrsMasterCfg.RPCJSONListen, 1, 1, "json", nil) if err != nil { t.Fatal("Could not connect to rater: ", err.Error()) } testCdr1 := &engine.CDR{CGRID: utils.Sha1("httpjsonrpc1", time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC).String()), ToR: utils.VOICE, OriginID: "httpjsonrpc1", OriginHost: "192.168.1.1", Source: "UNKNOWN", RequestType: utils.META_PSEUDOPREPAID, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}, RunID: utils.DEFAULT_RUNID, Cost: 1.201, Rated: true} var reply string if err := cdrsMasterRpc.Call("CdrsV2.ProcessCdr", testCdr1, &reply); err != nil { t.Error("Unexpected error: ", err.Error()) } else if reply != utils.OK { t.Error("Unexpected reply received: ", reply) } time.Sleep(time.Duration(*waitRater) * time.Millisecond) cdrsSlaveRpc, err := rpcclient.NewRpcClient("tcp", "127.0.0.1:12012", 1, 1, "json", nil) if err != nil { t.Fatal("Could not connect to rater: ", err.Error()) } // ToDo: Fix cdr_http to be compatible with rest of processCdr methods var rcvedCdrs []*engine.ExternalCDR if err := cdrsSlaveRpc.Call("ApierV2.GetCdrs", utils.RPCCDRsFilter{CGRIDs: []string{testCdr1.CGRID}, RunIDs: []string{utils.META_DEFAULT}}, &rcvedCdrs); err != nil { t.Error("Unexpected error: ", err.Error()) } else if len(rcvedCdrs) != 1 { t.Error("Unexpected number of CDRs returned: ", len(rcvedCdrs)) } else { rcvSetupTime, _ := utils.ParseTimeDetectLayout(rcvedCdrs[0].SetupTime, "") rcvAnswerTime, _ := utils.ParseTimeDetectLayout(rcvedCdrs[0].AnswerTime, "") //rcvUsage, _ := utils.ParseDurationWithSecs(rcvedCdrs[0].Usage) if rcvedCdrs[0].CGRID != testCdr1.CGRID || rcvedCdrs[0].ToR != testCdr1.ToR || rcvedCdrs[0].OriginHost != testCdr1.OriginHost || rcvedCdrs[0].Source != testCdr1.Source || rcvedCdrs[0].RequestType != testCdr1.RequestType || rcvedCdrs[0].Direction != testCdr1.Direction || rcvedCdrs[0].Tenant != testCdr1.Tenant || rcvedCdrs[0].Category != testCdr1.Category || rcvedCdrs[0].Account != testCdr1.Account || rcvedCdrs[0].Subject != testCdr1.Subject || rcvedCdrs[0].Destination != testCdr1.Destination || !rcvSetupTime.Equal(testCdr1.SetupTime) || !rcvAnswerTime.Equal(testCdr1.AnswerTime) || //rcvUsage != 10 || rcvedCdrs[0].RunID != testCdr1.RunID { //rcvedCdrs[0].Cost != testCdr1.Cost || //!reflect.DeepEqual(rcvedCdrs[0].ExtraFields, testCdr1.ExtraFields) { t.Errorf("Expected: %+v, received: %+v", testCdr1, rcvedCdrs[0]) } } }
func startSessionManager(responder *engine.Responder, loggerDb engine.LogStorage, cacheChan chan struct{}) { var raterConn, cdrsConn engine.Connector var client *rpcclient.RpcClient if cfg.SMRater == utils.INTERNAL { <-cacheChan // Wait for the cache to init before start doing queries raterConn = responder } else { var err error for i := 0; i < cfg.SMReconnects; i++ { client, err = rpcclient.NewRpcClient("tcp", cfg.SMRater, 0, cfg.SMReconnects, utils.GOB) if err == nil { //Connected so no need to reiterate break } time.Sleep(time.Duration(i+1) * time.Second) } if err != nil { engine.Logger.Crit(fmt.Sprintf("<SessionManager> Could not connect to engine: %v", err)) exitChan <- true } raterConn = &engine.RPCClientConnector{Client: client} } if cfg.SMCdrS == cfg.SMRater { cdrsConn = raterConn } else if cfg.SMCdrS == utils.INTERNAL { <-cacheChan // Wait for the cache to init before start doing queries cdrsConn = responder } else if len(cfg.SMCdrS) != 0 { for i := 0; i < cfg.SMReconnects; i++ { client, err = rpcclient.NewRpcClient("tcp", cfg.SMCdrS, 0, cfg.SMReconnects, utils.GOB) if err == nil { //Connected so no need to reiterate break } time.Sleep(time.Duration(i+1) * time.Second) } if err != nil { engine.Logger.Crit(fmt.Sprintf("<SM-OpenSIPS> Could not connect to CDRS via RPC: %v", err)) exitChan <- true } cdrsConn = &engine.RPCClientConnector{Client: client} } switch cfg.SMSwitchType { case FS: dp, _ := time.ParseDuration(fmt.Sprintf("%vs", cfg.SMDebitInterval)) sm = sessionmanager.NewFSSessionManager(cfg, loggerDb, raterConn, cdrsConn, dp) case OSIPS: sm, _ = sessionmanager.NewOSipsSessionManager(cfg, raterConn, cdrsConn) default: engine.Logger.Err(fmt.Sprintf("<SessionManager> Unsupported session manger type: %s!", cfg.SMSwitchType)) exitChan <- true } if err = sm.Connect(); err != nil { engine.Logger.Err(fmt.Sprintf("<SessionManager> error: %s!", err)) } exitChan <- true }
func startSmOpenSIPS(internalRaterChan chan *engine.Responder, cdrDb engine.CdrStorage, exitChan chan bool) { utils.Logger.Info("Starting CGRateS SM-OpenSIPS service.") var raterConn, cdrsConn engine.Connector var client *rpcclient.RpcClient var err error // Connect to rater for _, raterCfg := range cfg.SmOsipsConfig.HaRater { if raterCfg.Server == utils.INTERNAL { resp := <-internalRaterChan raterConn = resp // Will overwrite here for the sake of keeping internally the new configuration format for ha connections internalRaterChan <- resp } else { client, err = rpcclient.NewRpcClient("tcp", raterCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err != nil { //Connected so no need to reiterate utils.Logger.Crit(fmt.Sprintf("<SM-FreeSWITCH> Could not connect to rater via RPC: %v", err)) exitChan <- true return } raterConn = &engine.RPCClientConnector{Client: client} } } // Connect to CDRS if reflect.DeepEqual(cfg.SmOsipsConfig.HaCdrs, cfg.SmOsipsConfig.HaRater) { cdrsConn = raterConn } else if len(cfg.SmOsipsConfig.HaCdrs) != 0 { for _, cdrsCfg := range cfg.SmOsipsConfig.HaCdrs { if cdrsCfg.Server == utils.INTERNAL { resp := <-internalRaterChan cdrsConn = resp internalRaterChan <- resp } else { client, err = rpcclient.NewRpcClient("tcp", cdrsCfg.Server, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err != nil { utils.Logger.Crit(fmt.Sprintf("<SM-FreeSWITCH> Could not connect to CDRS via RPC: %v", err)) exitChan <- true return } cdrsConn = &engine.RPCClientConnector{Client: client} } } } sm, _ := sessionmanager.NewOSipsSessionManager(cfg.SmOsipsConfig, cfg.Reconnects, raterConn, cdrsConn, cfg.DefaultTimezone) sms = append(sms, sm) smRpc.SMs = append(smRpc.SMs, sm) if err := sm.Connect(); err != nil { utils.Logger.Err(fmt.Sprintf("<SM-OpenSIPS> error: %s!", err)) } exitChan <- true }
// Connect rpc client to rater func TestRPCITLclRpcConnPoolFirst(t *testing.T) { rpcPoolFirst = rpcclient.NewRpcClientPool(rpcclient.POOL_FIRST, 0) rpcRAL1, err = rpcclient.NewRpcClient("tcp", rpcITCfg1.RPCJSONListen, 3, 1, time.Duration(1*time.Second), time.Duration(2*time.Second), rpcclient.JSON_RPC, nil, false) if err == nil { t.Fatal("Should receive cannot connect error here") } rpcPoolFirst.AddClient(rpcRAL1) rpcRAL2, err = rpcclient.NewRpcClient("tcp", rpcITCfg2.RPCJSONListen, 3, 1, time.Duration(1*time.Second), time.Duration(2*time.Second), rpcclient.JSON_RPC, nil, false) if err != nil { t.Fatal(err) } rpcPoolFirst.AddClient(rpcRAL2) }
func startMediator(responder *engine.Responder, loggerDb engine.LogStorage, cdrDb engine.CdrStorage, cacheChan, chanDone chan struct{}) { var connector engine.Connector if cfg.MediatorRater == utils.INTERNAL { <-cacheChan // Cache needs to come up before we are ready connector = responder } else { var client *rpcclient.RpcClient var err error for i := 0; i < cfg.MediatorReconnects; i++ { client, err = rpcclient.NewRpcClient("tcp", cfg.MediatorRater, 0, cfg.MediatorReconnects, utils.GOB) if err == nil { //Connected so no need to reiterate break } time.Sleep(time.Duration(i+1) * time.Second) } if err != nil { engine.Logger.Crit(fmt.Sprintf("<Mediator> Could not connect to engine: %v", err)) exitChan <- true return } connector = &engine.RPCClientConnector{Client: client} } var err error medi, err = engine.NewMediator(connector, loggerDb, cdrDb, cdrStats, cfg) if err != nil { engine.Logger.Crit(fmt.Sprintf("Mediator config parsing error: %v", err)) exitChan <- true return } engine.Logger.Info("Registering Mediator RPC service.") server.RpcRegister(&apier.MediatorV1{Medi: medi}) close(chanDone) }
func NewProxyPubSub(addr string, attempts, reconnects int) (*ProxyPubSub, error) { client, err := rpcclient.NewRpcClient("tcp", addr, attempts, reconnects, utils.GOB) if err != nil { return nil, err } return &ProxyPubSub{Client: client}, nil }
func NewProxyUserService(addr string, attempts, reconnects int) (*ProxyUserService, error) { client, err := rpcclient.NewRpcClient("tcp", addr, attempts, reconnects, utils.GOB, nil) if err != nil { return nil, err } return &ProxyUserService{Client: client}, nil }
// Special tests involving remote server (manually set) // The server network will be manually disconnected without TCP close func TestRPCITRmtRpcConnPool(t *testing.T) { if !*testRemoteRALs { return } rpcPoolFirst = rpcclient.NewRpcClientPool(rpcclient.POOL_FIRST, 0) rpcRALRmt, err := rpcclient.NewRpcClient("tcp", "172.16.254.83:2012", 1, 1, time.Duration(1*time.Second), time.Duration(2*time.Second), rpcclient.JSON_RPC, nil) if err != nil { t.Fatal(err) } rpcPoolFirst.AddClient(rpcRALRmt) rpcRAL1, err = rpcclient.NewRpcClient("tcp", rpcITCfg1.RPCJSONListen, 1, 1, time.Duration(1*time.Second), time.Duration(2*time.Second), rpcclient.JSON_RPC, nil) if err != nil { t.Fatal(err) } rpcPoolFirst.AddClient(rpcRAL1) }
// Fires up a cdrc instance func startCdrc(internalCdrSChan chan *engine.CdrServer, internalRaterChan chan *engine.Responder, cdrcCfgs map[string]*config.CdrcConfig, httpSkipTlsCheck bool, closeChan chan struct{}, exitChan chan bool) { var cdrsConn engine.Connector var cdrcCfg *config.CdrcConfig for _, cdrcCfg = range cdrcCfgs { // Take the first config out, does not matter which one break } if cdrcCfg.Cdrs == utils.INTERNAL { cdrsChan := <-internalCdrSChan // This will signal that the cdrs part is populated in internalRaterChan internalCdrSChan <- cdrsChan // Put it back for other components resp := <-internalRaterChan cdrsConn = resp internalRaterChan <- resp } else { conn, err := rpcclient.NewRpcClient("tcp", cdrcCfg.Cdrs, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err != nil { utils.Logger.Crit(fmt.Sprintf("<CDRC> Could not connect to CDRS via RPC: %v", err)) exitChan <- true return } cdrsConn = &engine.RPCClientConnector{Client: conn} } cdrc, err := cdrc.NewCdrc(cdrcCfgs, httpSkipTlsCheck, cdrsConn, closeChan, cfg.DefaultTimezone) if err != nil { utils.Logger.Crit(fmt.Sprintf("Cdrc config parsing error: %s", err.Error())) exitChan <- true return } if err := cdrc.Run(); err != nil { utils.Logger.Crit(fmt.Sprintf("Cdrc run error: %s", err.Error())) exitChan <- true // If run stopped, something is bad, stop the application } }
func main() { flag.Parse() var err error var cdrsMasterRpc *rpcclient.RpcClient var cdrsMasterCfgPath string var cdrsMasterCfg *config.CGRConfig cdrsMasterCfgPath = path.Join(*dataDir, "conf", "samples", "cdrsreplicationmaster") if cdrsMasterCfg, err = config.NewCGRConfigFromFolder(cdrsMasterCfgPath); err != nil { log.Fatal("Got config error: ", err.Error()) } cdrsMasterRpc, err = rpcclient.NewRpcClient("tcp", cdrsMasterCfg.RPCJSONListen, 1, 1, time.Duration(1*time.Second), time.Duration(2*time.Second), "json", nil) if err != nil { log.Fatal("Could not connect to rater: ", err.Error()) } cdrs := make([]*engine.CDR, 0) for i := 0; i < 10000; i++ { cdr := &engine.CDR{OriginID: fmt.Sprintf("httpjsonrpc_%d", i), ToR: utils.VOICE, OriginHost: "192.168.1.1", Source: "UNKNOWN", RequestType: utils.META_PSEUDOPREPAID, Direction: "*out", Tenant: "cgrates.org", Category: "call", Account: "1001", Subject: "1001", Destination: "1002", SetupTime: time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC), AnswerTime: time.Date(2013, 12, 7, 8, 42, 26, 0, time.UTC), Usage: time.Duration(10) * time.Second, ExtraFields: map[string]string{"field_extr1": "val_extr1", "fieldextr2": "valextr2"}} cdrs = append(cdrs, cdr) } var reply string for _, cdr := range cdrs { if err := cdrsMasterRpc.Call("CdrsV2.ProcessCdr", cdr, &reply); err != nil { log.Fatal("Unexpected error: ", err.Error()) } else if reply != utils.OK { log.Fatal("Unexpected reply received: ", reply) } } }
func NewProxyPubSub(addr string, attempts, reconnects int, connectTimeout, replyTimeout time.Duration) (*ProxyPubSub, error) { client, err := rpcclient.NewRpcClient("tcp", addr, attempts, reconnects, connectTimeout, replyTimeout, utils.GOB, nil) if err != nil { return nil, err } return &ProxyPubSub{Client: client}, nil }
// Special tests involving remote server (manually set) // The server network will be manually disconnected without TCP close // Run remote ones with: go test -tags=integration -run="TestRPCITRmt|TestRPCITStop" -remote_rals func TestRPCITRmtRpcConnPool(t *testing.T) { if !*testRemoteRALs { return } rpcPoolFirst = rpcclient.NewRpcClientPool(rpcclient.POOL_FIRST, 0) rpcRALRmt, err := rpcclient.NewRpcClient("tcp", RemoteRALsAddr1, 1, 1, time.Duration(1*time.Second), time.Duration(2*time.Second), rpcclient.JSON_RPC, nil, false) if err != nil { t.Fatal(err) } rpcPoolFirst.AddClient(rpcRALRmt) rpcRAL1, err = rpcclient.NewRpcClient("tcp", RemoteRALsAddr2, 1, 1, time.Duration(1*time.Second), time.Duration(2*time.Second), rpcclient.JSON_RPC, nil, false) if err != nil { t.Fatal(err) } rpcPoolFirst.AddClient(rpcRAL1) }
/* << .Object.Property >> Property can be a attribute or a method both used without () Please also note the initial dot . Currently there are following objects that can be used: Account - the account that this action is called on Action - the action with all it's attributs Actions - the list of actions in the current action set Sq - StatsQueueTriggered object We can actually use everythiong that go templates offer. You can read more here: https://golang.org/pkg/text/template/ */ func cgrRPCAction(account *Account, sq *StatsQueueTriggered, a *Action, acs Actions) error { // parse template tmpl := template.New("extra_params") tmpl.Delims("<<", ">>") t, err := tmpl.Parse(a.ExtraParameters) if err != nil { utils.Logger.Err(fmt.Sprintf("error parsing *cgr_rpc template: %s", err.Error())) return err } var buf bytes.Buffer if err = t.Execute(&buf, struct { Account *Account Sq *StatsQueueTriggered Action *Action Actions Actions }{account, sq, a, acs}); err != nil { utils.Logger.Err(fmt.Sprintf("error executing *cgr_rpc template %s:", err.Error())) return err } processedExtraParam := buf.String() //utils.Logger.Info("ExtraParameters: " + parsedExtraParameters) req := RPCRequest{} if err := json.Unmarshal([]byte(processedExtraParam), &req); err != nil { return err } params, err := utils.GetRpcParams(req.Method) if err != nil { return err } var client rpcclient.RpcClientConnection if req.Address != utils.MetaInternal { if client, err = rpcclient.NewRpcClient("tcp", req.Address, req.Attempts, 0, config.CgrConfig().ConnectTimeout, config.CgrConfig().ReplyTimeout, req.Transport, nil); err != nil { return err } } else { client = params.Object.(rpcclient.RpcClientConnection) } in, out := params.InParam, params.OutParam //utils.Logger.Info("Params: " + utils.ToJSON(req.Params)) //p, err := utils.FromMapStringInterfaceValue(req.Params, in) mapstructure.Decode(req.Params, in) if err != nil { utils.Logger.Info("<*cgr_rpc> err: " + err.Error()) return err } utils.Logger.Info(fmt.Sprintf("<*cgr_rpc> calling: %s with: %s", req.Method, utils.ToJSON(in))) if !req.Async { err = client.Call(req.Method, in, out) utils.Logger.Info(fmt.Sprintf("<*cgr_rpc> result: %s err: %v", utils.ToJSON(out), err)) return err } go func() { err := client.Call(req.Method, in, out) utils.Logger.Info(fmt.Sprintf("<*cgr_rpc> result: %s err: %v", utils.ToJSON(out), err)) }() return nil }
func startSmGeneric(internalSMGChan chan *sessionmanager.SMGeneric, internalRaterChan, internalCDRSChan chan rpcclient.RpcClientConnection, server *utils.Server, exitChan chan bool) { utils.Logger.Info("Starting CGRateS SMGeneric service.") var ralsConns, cdrsConn *rpcclient.RpcClientPool if len(cfg.SmGenericConfig.RALsConns) != 0 { ralsConns, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, cfg.SmGenericConfig.RALsConns, internalRaterChan, cfg.InternalTtl) if err != nil { utils.Logger.Crit(fmt.Sprintf("<SMGeneric> Could not connect to RALs: %s", err.Error())) exitChan <- true return } } if len(cfg.SmGenericConfig.CDRsConns) != 0 { cdrsConn, err = engine.NewRPCPool(rpcclient.POOL_FIRST, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, cfg.SmGenericConfig.CDRsConns, internalCDRSChan, cfg.InternalTtl) if err != nil { utils.Logger.Crit(fmt.Sprintf("<SMGeneric> Could not connect to RALs: %s", err.Error())) exitChan <- true return } } smgReplConns := make([]*sessionmanager.SMGReplicationConn, len(cfg.SmGenericConfig.SMGReplicationConns)) for i, replConnCfg := range cfg.SmGenericConfig.SMGReplicationConns { if replCon, err := rpcclient.NewRpcClient("tcp", replConnCfg.Address, cfg.ConnectAttempts, cfg.Reconnects, cfg.ConnectTimeout, cfg.ReplyTimeout, replConnCfg.Transport[1:], nil); err != nil { utils.Logger.Crit(fmt.Sprintf("<SMGeneric> Could not connect to SMGReplicationConn: <%s>, error: <%s>", replConnCfg.Address, err.Error())) exitChan <- true return } else { smgReplConns[i] = &sessionmanager.SMGReplicationConn{Connection: replCon, Synchronous: replConnCfg.Synchronous} } } sm := sessionmanager.NewSMGeneric(cfg, ralsConns, cdrsConn, smgReplConns, cfg.DefaultTimezone) if err = sm.Connect(); err != nil { utils.Logger.Err(fmt.Sprintf("<SMGeneric> error: %s!", err)) } // Pass internal connection via BiRPCClient internalSMGChan <- sm // Register RPC handler smgRpc := v1.NewSMGenericV1(sm) server.RpcRegister(smgRpc) // Register BiRpc handlers //server.BiRPCRegister(v1.NewSMGenericBiRpcV1(sm)) smgBiRpc := v1.NewSMGenericBiRpcV1(sm) for method, handler := range smgBiRpc.Handlers() { server.BiRPCRegisterName(method, handler) } }
func startCDRS(internalCdrSChan chan *engine.CdrServer, logDb engine.LogStorage, cdrDb engine.CdrStorage, internalRaterChan chan *engine.Responder, internalPubSubSChan chan engine.PublisherSubscriber, internalUserSChan chan engine.UserService, internalAliaseSChan chan engine.AliasService, internalCdrStatSChan chan engine.StatsInterface, server *engine.Server, exitChan chan bool) { utils.Logger.Info("Starting CGRateS CDRS service.") var err error var client *rpcclient.RpcClient // Rater connection init var raterConn engine.Connector if cfg.CDRSRater == utils.INTERNAL { responder := <-internalRaterChan // Wait for rater to come up before start querying raterConn = responder internalRaterChan <- responder // Put back the connection since there might be other entities waiting for it } else if len(cfg.CDRSRater) != 0 { client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSRater, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err != nil { utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to rater: %s", err.Error())) exitChan <- true return } raterConn = &engine.RPCClientConnector{Client: client} } // Pubsub connection init var pubSubConn engine.PublisherSubscriber if cfg.CDRSPubSub == utils.INTERNAL { pubSubs := <-internalPubSubSChan pubSubConn = pubSubs internalPubSubSChan <- pubSubs } else if len(cfg.CDRSPubSub) != 0 { if cfg.CDRSRater == cfg.CDRSPubSub { pubSubConn = &engine.ProxyPubSub{Client: client} } else { client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSPubSub, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err != nil { utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to pubsub server: %s", err.Error())) exitChan <- true return } pubSubConn = &engine.ProxyPubSub{Client: client} } } // Users connection init var usersConn engine.UserService if cfg.CDRSUsers == utils.INTERNAL { userS := <-internalUserSChan usersConn = userS internalUserSChan <- userS } else if len(cfg.CDRSUsers) != 0 { if cfg.CDRSRater == cfg.CDRSUsers { usersConn = &engine.ProxyUserService{Client: client} } else { client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSUsers, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err != nil { utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to users server: %s", err.Error())) exitChan <- true return } usersConn = &engine.ProxyUserService{Client: client} } } // Aliases connection init var aliasesConn engine.AliasService if cfg.CDRSAliases == utils.INTERNAL { aliaseS := <-internalAliaseSChan aliasesConn = aliaseS internalAliaseSChan <- aliaseS } else if len(cfg.CDRSAliases) != 0 { if cfg.CDRSRater == cfg.CDRSAliases { aliasesConn = &engine.ProxyAliasService{Client: client} } else { client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSAliases, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err != nil { utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to aliases server: %s", err.Error())) exitChan <- true return } aliasesConn = &engine.ProxyAliasService{Client: client} } } // Stats connection init var statsConn engine.StatsInterface if cfg.CDRSStats == utils.INTERNAL { statS := <-internalCdrStatSChan statsConn = statS internalCdrStatSChan <- statS } else if len(cfg.CDRSStats) != 0 { if cfg.CDRSRater == cfg.CDRSStats { statsConn = &engine.ProxyStats{Client: client} } else { client, err = rpcclient.NewRpcClient("tcp", cfg.CDRSStats, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB) if err != nil { utils.Logger.Crit(fmt.Sprintf("<CDRS> Could not connect to stats server: %s", err.Error())) exitChan <- true return } statsConn = &engine.ProxyStats{Client: client} } } cdrServer, _ := engine.NewCdrServer(cfg, cdrDb, raterConn, pubSubConn, usersConn, aliasesConn, statsConn) utils.Logger.Info("Registering CDRS HTTP Handlers.") cdrServer.RegisterHanlersToServer(server) utils.Logger.Info("Registering CDRS RPC service.") cdrSrv := v1.CdrsV1{CdrSrv: cdrServer} server.RpcRegister(&cdrSrv) server.RpcRegister(&v2.CdrsV2{CdrsV1: cdrSrv}) // Make the cdr server available for internal communication responder := <-internalRaterChan // Retrieve again the responder responder.CdrSrv = cdrServer // Attach connection to cdrServer in responder, so it can be used later internalRaterChan <- responder // Put back the connection for the rest of the system internalCdrSChan <- cdrServer // Signal that cdrS is operational }
// Starts rater and reports on chan func startRater(internalRaterChan chan *engine.Responder, cacheDoneChan chan struct{}, internalBalancerChan chan *balancer2go.Balancer, internalSchedulerChan chan *scheduler.Scheduler, internalCdrStatSChan chan engine.StatsInterface, internalHistorySChan chan history.Scribe, internalPubSubSChan chan rpcclient.RpcClientConnection, internalUserSChan chan engine.UserService, internalAliaseSChan chan engine.AliasService, server *utils.Server, ratingDb engine.RatingStorage, accountDb engine.AccountingStorage, loadDb engine.LoadStorage, cdrDb engine.CdrStorage, logDb engine.LogStorage, stopHandled *bool, exitChan chan bool) { var waitTasks []chan struct{} //Cache load cacheTaskChan := make(chan struct{}) waitTasks = append(waitTasks, cacheTaskChan) go func() { defer close(cacheTaskChan) if err := ratingDb.CacheRatingAll(); err != nil { utils.Logger.Crit(fmt.Sprintf("Cache rating error: %s", err.Error())) exitChan <- true return } if err := accountDb.CacheAccountingPrefixes(); err != nil { // Used to cache load history utils.Logger.Crit(fmt.Sprintf("Cache accounting error: %s", err.Error())) exitChan <- true return } cacheDoneChan <- struct{}{} }() // Retrieve scheduler for it's API methods var sched *scheduler.Scheduler // Need the scheduler in APIer if cfg.SchedulerEnabled { schedTaskChan := make(chan struct{}) waitTasks = append(waitTasks, schedTaskChan) go func() { defer close(schedTaskChan) select { case sched = <-internalSchedulerChan: internalSchedulerChan <- sched case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal scheduler connection timeout.") exitChan <- true return } }() } // Connection to balancer var bal *balancer2go.Balancer if cfg.RaterBalancer != "" { balTaskChan := make(chan struct{}) waitTasks = append(waitTasks, balTaskChan) go func() { defer close(balTaskChan) if cfg.RaterBalancer == utils.INTERNAL { select { case bal = <-internalBalancerChan: internalBalancerChan <- bal // Put it back if someone else is interested about case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal balancer connection timeout.") exitChan <- true return } } else { go registerToBalancer(exitChan) go stopRaterSignalHandler(internalCdrStatSChan, exitChan) *stopHandled = true } }() } // Connection to CDRStats var cdrStats engine.StatsInterface if cfg.RaterCdrStats != "" { cdrstatTaskChan := make(chan struct{}) waitTasks = append(waitTasks, cdrstatTaskChan) go func() { defer close(cdrstatTaskChan) if cfg.RaterCdrStats == utils.INTERNAL { select { case cdrStats = <-internalCdrStatSChan: internalCdrStatSChan <- cdrStats case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal cdrstats connection timeout.") exitChan <- true return } } else if cdrStats, err = engine.NewProxyStats(cfg.RaterCdrStats, cfg.ConnectAttempts, -1); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect to cdrstats, error: %s", err.Error())) exitChan <- true return } }() } // Connection to HistoryS if cfg.RaterHistoryServer != "" { histTaskChan := make(chan struct{}) waitTasks = append(waitTasks, histTaskChan) go func() { defer close(histTaskChan) var scribeServer history.Scribe if cfg.RaterHistoryServer == utils.INTERNAL { select { case scribeServer = <-internalHistorySChan: internalHistorySChan <- scribeServer case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal historys connection timeout.") exitChan <- true return } } else if scribeServer, err = history.NewProxyScribe(cfg.RaterHistoryServer, cfg.ConnectAttempts, -1); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect historys, error: %s", err.Error())) exitChan <- true return } engine.SetHistoryScribe(scribeServer) // ToDo: replace package sharing with connection based one }() } // Connection to pubsubs if cfg.RaterPubSubServer != "" { pubsubTaskChan := make(chan struct{}) waitTasks = append(waitTasks, pubsubTaskChan) go func() { defer close(pubsubTaskChan) var pubSubServer rpcclient.RpcClientConnection if cfg.RaterPubSubServer == utils.INTERNAL { select { case pubSubServer = <-internalPubSubSChan: internalPubSubSChan <- pubSubServer case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal pubsub connection timeout.") exitChan <- true return } } else if pubSubServer, err = rpcclient.NewRpcClient("tcp", cfg.RaterPubSubServer, cfg.ConnectAttempts, cfg.Reconnects, utils.GOB, nil); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect to pubsubs: %s", err.Error())) exitChan <- true return } engine.SetPubSub(pubSubServer) // ToDo: replace package sharing with connection based one }() } // Connection to AliasService if cfg.RaterAliasesServer != "" { aliasesTaskChan := make(chan struct{}) waitTasks = append(waitTasks, aliasesTaskChan) go func() { defer close(aliasesTaskChan) var aliasesServer engine.AliasService if cfg.RaterAliasesServer == utils.INTERNAL { select { case aliasesServer = <-internalAliaseSChan: internalAliaseSChan <- aliasesServer case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal aliases connection timeout.") exitChan <- true return } } else if aliasesServer, err = engine.NewProxyAliasService(cfg.RaterAliasesServer, cfg.ConnectAttempts, -1); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect to aliases, error: %s", err.Error())) exitChan <- true return } engine.SetAliasService(aliasesServer) // ToDo: replace package sharing with connection based one }() } // Connection to UserService var userServer engine.UserService if cfg.RaterUserServer != "" { usersTaskChan := make(chan struct{}) waitTasks = append(waitTasks, usersTaskChan) go func() { defer close(usersTaskChan) if cfg.RaterUserServer == utils.INTERNAL { select { case userServer = <-internalUserSChan: internalUserSChan <- userServer case <-time.After(cfg.InternalTtl): utils.Logger.Crit("<Rater>: Internal users connection timeout.") exitChan <- true return } } else if userServer, err = engine.NewProxyUserService(cfg.RaterUserServer, cfg.ConnectAttempts, -1); err != nil { utils.Logger.Crit(fmt.Sprintf("<Rater> Could not connect users, error: %s", err.Error())) exitChan <- true return } engine.SetUserService(userServer) }() } // Wait for all connections to complete before going further for _, chn := range waitTasks { <-chn } responder := &engine.Responder{Bal: bal, ExitChan: exitChan, Stats: cdrStats} apierRpcV1 := &v1.ApierV1{StorDb: loadDb, RatingDb: ratingDb, AccountDb: accountDb, CdrDb: cdrDb, LogDb: logDb, Sched: sched, Config: cfg, Responder: responder, CdrStatsSrv: cdrStats, Users: userServer} apierRpcV2 := &v2.ApierV2{ ApierV1: *apierRpcV1} // internalSchedulerChan shared here server.RpcRegister(responder) server.RpcRegister(apierRpcV1) server.RpcRegister(apierRpcV2) internalRaterChan <- responder // Rater done }
func main() { flag.Parse() if *version { fmt.Println("CGRateS " + utils.VERSION) return } var err error client, err = rpcclient.NewRpcClient("tcp", *server, 3, 3, time.Duration(1*time.Second), time.Duration(5*time.Minute), *rpc_encoding, nil) if err != nil { flag.PrintDefaults() log.Fatal("Could not connect to server " + *server) } if len(flag.Args()) != 0 { executeCommand(strings.Join(flag.Args(), " ")) return } fmt.Println("Welcome to CGRateS console!") fmt.Print("Type `help` for a list of commands\n\n") line := liner.NewLiner() defer line.Close() line.SetCompleter(func(line string) (comp []string) { commands := console.GetCommands() for name, cmd := range commands { if strings.HasPrefix(name, strings.ToLower(line)) { comp = append(comp, name) } // try arguments if strings.HasPrefix(line, name) { // get last word lastSpace := strings.LastIndex(line, " ") lastSpace += 1 for _, arg := range cmd.ClientArgs() { if strings.HasPrefix(arg, line[lastSpace:]) { comp = append(comp, line[:lastSpace]+arg) } } } } return }) if f, err := os.Open(history_fn); err == nil { line.ReadHistory(f) f.Close() } stop := false for !stop { if command, err := line.Prompt("cgr> "); err != nil { if err == io.EOF { fmt.Println("\nbye!") stop = true } else { fmt.Print("Error reading line: ", err) } } else { line.AppendHistory(command) switch strings.ToLower(strings.TrimSpace(command)) { case "quit", "exit", "bye", "close": fmt.Println("\nbye!") stop = true default: executeCommand(command) } } } if f, err := os.Create(history_fn); err != nil { log.Print("Error writing history file: ", err) } else { line.WriteHistory(f) f.Close() } }
func main() { flag.Parse() if *version { fmt.Println("CGRateS " + utils.VERSION) return } var errRatingDb, errAccDb, errStorDb, err error var ratingDb engine.RatingStorage var accountDb engine.AccountingStorage var storDb engine.LoadStorage var rater, cdrstats, users *rpc.Client var loader engine.LoadReader if *migrateRC8 != "" { if *datadb_type == "redis" && *tpdb_type == "redis" { var db_nb int db_nb, err = strconv.Atoi(*datadb_name) if err != nil { log.Print("Redis db name must be an integer!") return } host := *datadb_host if *datadb_port != "" { host += ":" + *datadb_port } migratorRC8acc, err := NewMigratorRC8(host, db_nb, *datadb_pass, *dbdata_encoding) if err != nil { log.Print(err.Error()) return } if strings.Contains(*migrateRC8, "acc") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8acc.migrateAccounts(); err != nil { log.Print(err.Error()) } } db_nb, err = strconv.Atoi(*tpdb_name) if err != nil { log.Print("Redis db name must be an integer!") return } host = *tpdb_host if *tpdb_port != "" { host += ":" + *tpdb_port } migratorRC8rat, err := NewMigratorRC8(host, db_nb, *tpdb_pass, *dbdata_encoding) if err != nil { log.Print(err.Error()) return } if strings.Contains(*migrateRC8, "atr") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateActionTriggers(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "act") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateActions(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "dcs") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateDerivedChargers(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "apl") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateActionPlans(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "shg") || strings.Contains(*migrateRC8, "*all") { if err := migratorRC8rat.migrateSharedGroups(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "int") { if err := migratorRC8acc.migrateAccountsInt(); err != nil { log.Print(err.Error()) } if err := migratorRC8rat.migrateActionTriggersInt(); err != nil { log.Print(err.Error()) } if err := migratorRC8rat.migrateActionsInt(); err != nil { log.Print(err.Error()) } } if strings.Contains(*migrateRC8, "vf") { if err := migratorRC8rat.migrateActionsInt2(); err != nil { log.Print(err.Error()) } if err := migratorRC8acc.writeVersion(); err != nil { log.Print(err.Error()) } } } else if *datadb_type == "mongo" && *tpdb_type == "mongo" { mongoMigratorAcc, err := NewMongoMigrator(*datadb_host, *datadb_port, *datadb_name, *datadb_user, *datadb_pass) if err != nil { log.Print(err.Error()) return } mongoMigratorRat, err := NewMongoMigrator(*tpdb_host, *tpdb_port, *tpdb_name, *tpdb_user, *tpdb_pass) if err != nil { log.Print(err.Error()) return } if strings.Contains(*migrateRC8, "vf") { if err := mongoMigratorRat.migrateActions(); err != nil { log.Print(err.Error()) } if err := mongoMigratorAcc.writeVersion(); err != nil { log.Print(err.Error()) } } } log.Print("Done!") return } // Init necessary db connections, only if not already if !*dryRun { // make sure we do not need db connections on dry run, also not importing into any stordb if *fromStorDb { ratingDb, errRatingDb = engine.ConfigureRatingStorage(*tpdb_type, *tpdb_host, *tpdb_port, *tpdb_name, *tpdb_user, *tpdb_pass, *dbdata_encoding, cgrConfig.CacheConfig, *loadHistorySize) accountDb, errAccDb = engine.ConfigureAccountingStorage(*datadb_type, *datadb_host, *datadb_port, *datadb_name, *datadb_user, *datadb_pass, *dbdata_encoding, cgrConfig.CacheConfig, *loadHistorySize) storDb, errStorDb = engine.ConfigureLoadStorage(*stor_db_type, *stor_db_host, *stor_db_port, *stor_db_name, *stor_db_user, *stor_db_pass, *dbdata_encoding, cgrConfig.StorDBMaxOpenConns, cgrConfig.StorDBMaxIdleConns, cgrConfig.StorDBCDRSIndexes) } else if *toStorDb { // Import from csv files to storDb storDb, errStorDb = engine.ConfigureLoadStorage(*stor_db_type, *stor_db_host, *stor_db_port, *stor_db_name, *stor_db_user, *stor_db_pass, *dbdata_encoding, cgrConfig.StorDBMaxOpenConns, cgrConfig.StorDBMaxIdleConns, cgrConfig.StorDBCDRSIndexes) } else { // Default load from csv files to dataDb ratingDb, errRatingDb = engine.ConfigureRatingStorage(*tpdb_type, *tpdb_host, *tpdb_port, *tpdb_name, *tpdb_user, *tpdb_pass, *dbdata_encoding, cgrConfig.CacheConfig, *loadHistorySize) accountDb, errAccDb = engine.ConfigureAccountingStorage(*datadb_type, *datadb_host, *datadb_port, *datadb_name, *datadb_user, *datadb_pass, *dbdata_encoding, cgrConfig.CacheConfig, *loadHistorySize) } // Defer databases opened to be closed when we are done for _, db := range []engine.Storage{ratingDb, accountDb, storDb} { if db != nil { defer db.Close() } } // Stop on db errors for _, err = range []error{errRatingDb, errAccDb, errStorDb} { if err != nil { log.Fatalf("Could not open database connection: %v", err) } } if *toStorDb { // Import files from a directory into storDb if *tpid == "" { log.Fatal("TPid required, please define it via *-tpid* command argument.") } csvImporter := engine.TPCSVImporter{ TPid: *tpid, StorDb: storDb, DirPath: *dataPath, Sep: ',', Verbose: *verbose, ImportId: *runId, } if errImport := csvImporter.Run(); errImport != nil { log.Fatal(errImport) } return } } if *fromStorDb { // Load Tariff Plan from storDb into dataDb loader = storDb } else { // Default load from csv files to dataDb /*for fn, v := range engine.FileValidators { err := engine.ValidateCSVData(path.Join(*dataPath, fn), v.Rule) if err != nil { log.Fatal(err, "\n\t", v.Message) } }*/ loader = engine.NewFileCSVStorage(',', path.Join(*dataPath, utils.DESTINATIONS_CSV), path.Join(*dataPath, utils.TIMINGS_CSV), path.Join(*dataPath, utils.RATES_CSV), path.Join(*dataPath, utils.DESTINATION_RATES_CSV), path.Join(*dataPath, utils.RATING_PLANS_CSV), path.Join(*dataPath, utils.RATING_PROFILES_CSV), path.Join(*dataPath, utils.SHARED_GROUPS_CSV), path.Join(*dataPath, utils.LCRS_CSV), path.Join(*dataPath, utils.ACTIONS_CSV), path.Join(*dataPath, utils.ACTION_PLANS_CSV), path.Join(*dataPath, utils.ACTION_TRIGGERS_CSV), path.Join(*dataPath, utils.ACCOUNT_ACTIONS_CSV), path.Join(*dataPath, utils.DERIVED_CHARGERS_CSV), path.Join(*dataPath, utils.CDR_STATS_CSV), path.Join(*dataPath, utils.USERS_CSV), path.Join(*dataPath, utils.ALIASES_CSV), path.Join(*dataPath, utils.ResourceLimitsCsv), ) } tpReader := engine.NewTpReader(ratingDb, accountDb, loader, *tpid, *timezone) err = tpReader.LoadAll() if err != nil { log.Fatal(err) } if *stats { tpReader.ShowStatistics() } if *validate { if !tpReader.IsValid() { return } } if *dryRun { // We were just asked to parse the data, not saving it return } if *historyServer != "" { // Init scribeAgent so we can store the differences if scribeAgent, err := rpcclient.NewRpcClient("tcp", *historyServer, 3, 3, time.Duration(1*time.Second), time.Duration(5*time.Minute), utils.GOB, nil); err != nil { log.Fatalf("Could not connect to history server, error: %s. Make sure you have properly configured it via -history_server flag.", err.Error()) return } else { engine.SetHistoryScribe(scribeAgent) //defer scribeAgent.Client.Close() } } else { log.Print("WARNING: Rates history archiving is disabled!") } if *raterAddress != "" { // Init connection to rater so we can reload it's data rater, err = rpc.Dial("tcp", *raterAddress) if err != nil { log.Fatalf("Could not connect to rater: %s", err.Error()) return } } else { log.Print("WARNING: Rates automatic cache reloading is disabled!") } if *cdrstatsAddress != "" { // Init connection to rater so we can reload it's data if *cdrstatsAddress == *raterAddress { cdrstats = rater } else { cdrstats, err = rpc.Dial("tcp", *cdrstatsAddress) if err != nil { log.Fatalf("Could not connect to CDRStats API: %s", err.Error()) return } } } else { log.Print("WARNING: CDRStats automatic data reload is disabled!") } if *usersAddress != "" { // Init connection to rater so we can reload it's data if *usersAddress == *raterAddress { users = rater } else { users, err = rpc.Dial("tcp", *usersAddress) if err != nil { log.Fatalf("Could not connect to Users API: %s", err.Error()) return } } } else { log.Print("WARNING: Users automatic data reload is disabled!") } // write maps to database if err := tpReader.WriteToDatabase(*flush, *verbose, *disable_reverse); err != nil { log.Fatal("Could not write to database: ", err) } if len(*historyServer) != 0 && *verbose { log.Print("Wrote history.") } var dstIds, rplIds, rpfIds, actIds, shgIds, alsIds, lcrIds, dcsIds, rlIDs []string if rater != nil { dstIds, _ = tpReader.GetLoadedIds(utils.DESTINATION_PREFIX) rplIds, _ = tpReader.GetLoadedIds(utils.RATING_PLAN_PREFIX) rpfIds, _ = tpReader.GetLoadedIds(utils.RATING_PROFILE_PREFIX) actIds, _ = tpReader.GetLoadedIds(utils.ACTION_PREFIX) shgIds, _ = tpReader.GetLoadedIds(utils.SHARED_GROUP_PREFIX) alsIds, _ = tpReader.GetLoadedIds(utils.ALIASES_PREFIX) lcrIds, _ = tpReader.GetLoadedIds(utils.LCR_PREFIX) dcsIds, _ = tpReader.GetLoadedIds(utils.DERIVEDCHARGERS_PREFIX) rlIDs, _ = tpReader.GetLoadedIds(utils.ResourceLimitsPrefix) } actTmgIds, _ := tpReader.GetLoadedIds(utils.ACTION_PLAN_PREFIX) var statsQueueIds []string if cdrstats != nil { statsQueueIds, _ = tpReader.GetLoadedIds(utils.CDR_STATS_PREFIX) } var userIds []string if users != nil { userIds, _ = tpReader.GetLoadedIds(utils.USERS_PREFIX) } // release the reader with it's structures tpReader.Init() // Reload scheduler and cache if rater != nil { reply := "" // Reload cache first since actions could be calling info from within if *verbose { log.Print("Reloading cache") } if *flush { dstIds, rplIds, rpfIds, lcrIds = nil, nil, nil, nil // Should reload all these on flush } if err = rater.Call("ApierV1.ReloadCache", utils.AttrReloadCache{ DestinationIds: &dstIds, RatingPlanIds: &rplIds, RatingProfileIds: &rpfIds, ActionIds: &actIds, SharedGroupIds: &shgIds, Aliases: &alsIds, LCRIds: &lcrIds, DerivedChargers: &dcsIds, ResourceLimits: &rlIDs, }, &reply); err != nil { log.Printf("WARNING: Got error on cache reload: %s\n", err.Error()) } if len(actTmgIds) != 0 { if *verbose { log.Print("Reloading scheduler") } if err = rater.Call("ApierV1.ReloadScheduler", "", &reply); err != nil { log.Printf("WARNING: Got error on scheduler reload: %s\n", err.Error()) } } } if cdrstats != nil { if *flush { statsQueueIds = []string{} // Force reload all } if len(statsQueueIds) != 0 { if *verbose { log.Print("Reloading CDRStats data") } var reply string if err := cdrstats.Call("CDRStatsV1.ReloadQueues", utils.AttrCDRStatsReloadQueues{StatsQueueIds: statsQueueIds}, &reply); err != nil { log.Printf("WARNING: Failed reloading stat queues, error: %s\n", err.Error()) } } } if users != nil { if len(userIds) > 0 { if *verbose { log.Print("Reloading Users data") } var reply string if err := cdrstats.Call("UsersV1.ReloadUsers", "", &reply); err != nil { log.Printf("WARNING: Failed reloading users data, error: %s\n", err.Error()) } } } }