diff --git a/apier/v1/dispatcher.go b/apier/v1/dispatcher.go
index 3bf98f472..a8efd64ac 100755
--- a/apier/v1/dispatcher.go
+++ b/apier/v1/dispatcher.go
@@ -362,3 +362,16 @@ func (dS *DispatcherSessionSv1) SetPassiveSession(args *dispatchers.SessionWithA
reply *string) (err error) {
return dS.dS.SessionSv1SetPassiveSession(args, reply)
}
+
+func NewDispatcherResponder(dps *dispatchers.DispatcherService) *DispatcherResponder {
+ return &DispatcherResponder{dS: dps}
+}
+
+// Exports RPC from RLs
+type DispatcherResponder struct {
+ dS *dispatchers.DispatcherService
+}
+
+func (dS *DispatcherResponder) Status(args *dispatchers.TntWithApiKey, reply *map[string]interface{}) error {
+ return dS.dS.ResponderStatus(args, reply)
+}
diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go
index 16053cd38..c1a58d7aa 100644
--- a/cmd/cgr-engine/cgr-engine.go
+++ b/cmd/cgr-engine/cgr-engine.go
@@ -981,6 +981,9 @@ func startDispatcherService(internalDispatcherSChan chan *dispatchers.Dispatcher
server.RpcRegisterName(utils.ChargerSv1,
v1.NewDispatcherChargerSv1(dspS))
+ server.RpcRegisterName(utils.Responder,
+ v1.NewDispatcherResponder(dspS))
+
internalDispatcherSChan <- dspS
}
diff --git a/console/status.go b/console/status.go
index c70b9ef8d..e01d04c77 100644
--- a/console/status.go
+++ b/console/status.go
@@ -18,10 +18,12 @@ along with this program. If not, see
package console
+import "github.com/cgrates/cgrates/utils"
+
func init() {
c := &CmdStatus{
name: "status",
- rpcMethod: "Responder.Status",
+ rpcMethod: utils.ResponderStatus,
}
commands[c.Name()] = c
c.CommandExecuter = &CommandExecuter{c}
diff --git a/data/tariffplans/dispatchers/Attributes.csv b/data/tariffplans/dispatchers/Attributes.csv
index 2ca0f2544..c0aa84ab8 100644
--- a/data/tariffplans/dispatchers/Attributes.csv
+++ b/data/tariffplans/dispatchers/Attributes.csv
@@ -8,4 +8,5 @@ cgrates.org,ATTR_API_SUP_AUTH,*auth,*string:APIKey:sup12345,,APIMethods,*any,Sup
cgrates.org,ATTR_API_STAT_AUTH,*auth,*string:APIKey:stat12345,,APIMethods,*any,StatSv1.Ping&StatSv1.GetStatQueuesForEvent&StatSv1.GetQueueStringMetrics&StatSv1.ProcessEvent&StatSv1.GetQueueIDs&StatSv1.GetQueueFloatMetrics,true,false,20
cgrates.org,ATTR_API_RES_AUTH,*auth,*string:APIKey:res12345,,APIMethods,*any,ResourceSv1.Ping&ResourceSv1.GetResourcesForEvent&ResourceSv1.AuthorizeResources&ResourceSv1.AllocateResources&ResourceSv1.ReleaseResources,true,false,20
cgrates.org,ATTR_API_SES_AUTH,*auth,*string:APIKey:ses12345,,APIMethods,*any,SessionSv1.Ping&SessionSv1.AuthorizeEventWithDigest&SessionSv1.InitiateSessionWithDigest&SessionSv1.UpdateSession&SessionSv1.TerminateSession&SessionSv1.ProcessCDR&SessionSv1.ProcessEvent&SessionSv1.GetActiveSessions&SessionSv1.GetActiveSessionsCount&SessionSv1.ForceDisconnect&SessionSv1.GetPassiveSessions&SessionSv1.GetPassiveSessionsCount&SessionSv1.SetPassiveSession&SessionSv1.ReplicateSessions,true,false,20
+cgrates.org,ATTR_API_RSP_AUTH,*auth,*string:APIKey:rsp12345,,APIMethods,*any,Responder.Status,true,false,20
diff --git a/data/tariffplans/dispatchers/Dispatchers.csv b/data/tariffplans/dispatchers/Dispatchers.csv
index c9b788c87..ae6a8f6e8 100644
--- a/data/tariffplans/dispatchers/Dispatchers.csv
+++ b/data/tariffplans/dispatchers/Dispatchers.csv
@@ -5,3 +5,5 @@ cgrates.org,EVENT1,*any,*string:EventName:Event1,,*weight,,ALL2,,20,false,,30
cgrates.org,EVENT1,,,,,,ALL,,10,,,
cgrates.org,EVENT2,*any,*string:EventName:RoundRobin,,*round_robin,,ALL2,,20,false,,20
cgrates.org,EVENT2,,,,,,ALL,,10,,,
+cgrates.org,EVENT3,*any,*string:EventName:Random,,*random,,ALL2,,20,false,,20
+cgrates.org,EVENT3,,,,,,ALL,,10,,,
diff --git a/dispatchers/responder.go b/dispatchers/responder.go
new file mode 100644
index 000000000..a19fdd60e
--- /dev/null
+++ b/dispatchers/responder.go
@@ -0,0 +1,39 @@
+/*
+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 dispatchers
+
+import (
+ "time"
+
+ "github.com/cgrates/cgrates/utils"
+)
+
+func (dS *DispatcherService) ResponderStatus(args *TntWithApiKey,
+ reply *map[string]interface{}) (err error) {
+ if dS.attrS != nil {
+ if err = dS.authorize(utils.ResponderStatus, args.Tenant,
+ args.APIKey, utils.TimePointer(time.Now())); err != nil {
+ return
+ }
+ }
+ return dS.Dispatch(&utils.CGREvent{
+ Tenant: args.Tenant,
+ }, utils.MetaStats, args.RouteID, utils.ResponderStatus,
+ "", reply)
+}
diff --git a/dispatchers/responder_it_test.go b/dispatchers/responder_it_test.go
new file mode 100644
index 000000000..ee90119fe
--- /dev/null
+++ b/dispatchers/responder_it_test.go
@@ -0,0 +1,118 @@
+// +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 dispatchers
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/cgrates/cgrates/utils"
+)
+
+var sTestsDspRsp = []func(t *testing.T){
+ testDspResponderStatus,
+
+ testDspResponderRandom,
+}
+
+//Test start here
+func TestDspResponderTMySQL(t *testing.T) {
+ testDsp(t, sTestsDspRsp, "TestDspAttributeS", "all", "all2", "attributes", "dispatchers", "tutorial", "oldtutorial", "dispatchers")
+}
+
+func TestDspResponderMongo(t *testing.T) {
+ testDsp(t, sTestsDspRsp, "TestDspAttributeS", "all", "all2", "attributes_mongo", "dispatchers_mongo", "tutorial", "oldtutorial", "dispatchers")
+}
+
+func testDspResponderStatus(t *testing.T) {
+ var reply map[string]interface{}
+ if err := allEngine.RCP.Call(utils.ResponderStatus, "", &reply); err != nil {
+ t.Error(err)
+ } else if reply[utils.NodeID] != "ALL" {
+ t.Errorf("Received: %s", reply)
+ }
+ ev := TntWithApiKey{
+ TenantArg: utils.TenantArg{
+ Tenant: "cgrates.org",
+ },
+ DispatcherResource: DispatcherResource{
+ APIKey: "rsp12345",
+ },
+ }
+ if err := dispEngine.RCP.Call(utils.ResponderStatus, &ev, &reply); err != nil {
+ t.Error(err)
+ } else if reply[utils.NodeID] != "ALL" {
+ t.Errorf("Received: %s", utils.ToJSON(reply))
+ }
+ allEngine.stopEngine(t)
+ if err := dispEngine.RCP.Call(utils.ResponderStatus, &ev, &reply); err != nil {
+ t.Error(err)
+ } else if reply[utils.NodeID] != "ALL2" {
+ t.Errorf("Received: %s", utils.ToJSON(reply))
+ }
+ allEngine.startEngine(t)
+}
+
+func getNodeWithRoute(route string, t *testing.T) string {
+ var reply map[string]interface{}
+ var pingReply string
+ pingEv := CGREvWithApiKey{
+ CGREvent: utils.CGREvent{
+ Tenant: "cgrates.org",
+ Event: map[string]interface{}{
+ utils.EVENT_NAME: "Random",
+ },
+ },
+ DispatcherResource: DispatcherResource{
+ APIKey: "attr12345",
+ RouteID: &route,
+ },
+ }
+ ev := TntWithApiKey{
+ TenantArg: utils.TenantArg{
+ Tenant: "cgrates.org",
+ },
+ DispatcherResource: DispatcherResource{
+ APIKey: "rsp12345",
+ RouteID: &route,
+ },
+ }
+
+ if err := dispEngine.RCP.Call(utils.AttributeSv1Ping, pingEv, &pingReply); err != nil {
+ t.Error(err)
+ } else if pingReply != utils.Pong {
+ t.Errorf("Received: %s", pingReply)
+ }
+ if err := dispEngine.RCP.Call(utils.ResponderStatus, &ev, &reply); err != nil {
+ t.Error(err)
+ }
+ return reply[utils.NodeID].(string)
+}
+
+func testDspResponderRandom(t *testing.T) {
+ node := getNodeWithRoute("r_init", t)
+ for i := 0; i < 10; i++ {
+ if node != getNodeWithRoute(fmt.Sprintf("R_%v", i), t) {
+ return
+ }
+ }
+ t.Errorf("Random strategy fail with 0.0009765625%% probability")
+}