diff --git a/agents/fsagent.go b/agents/fsagent.go
index b85a66b1c..f66ab69ce 100644
--- a/agents/fsagent.go
+++ b/agents/fsagent.go
@@ -333,7 +333,7 @@ func (sm *FSsessions) Shutdown() (err error) {
// rpcclient.RpcClientConnection interface
func (sm *FSsessions) Call(serviceMethod string, args interface{}, reply interface{}) error {
- return utils.APIerRPCCall(sm, serviceMethod, args, reply)
+ return utils.RPCCall(sm, serviceMethod, args, reply)
}
// Internal method to disconnect session in asterisk
diff --git a/agents/kamagent.go b/agents/kamagent.go
index 5fc65a1c9..4489af7c2 100644
--- a/agents/kamagent.go
+++ b/agents/kamagent.go
@@ -78,7 +78,7 @@ func (self *KamailioAgent) Shutdown() error {
// rpcclient.RpcClientConnection interface
func (ka *KamailioAgent) Call(serviceMethod string, args interface{}, reply interface{}) error {
- return utils.APIerRPCCall(ka, serviceMethod, args, reply)
+ return utils.RPCCall(ka, serviceMethod, args, reply)
}
// onCgrAuth is called when new event of type CGR_AUTH_REQUEST is coming
diff --git a/utils/cgrreply.go b/utils/cgrreply.go
new file mode 100644
index 000000000..d3d10bef0
--- /dev/null
+++ b/utils/cgrreply.go
@@ -0,0 +1,79 @@
+/*
+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 PURPOev. 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 utils
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+)
+
+// CGRReplier is the interface supported by replies convertible to CGRReply
+type CGRReplier interface {
+ AsCGRReply() (CGRReply, error)
+}
+
+func NewCGRReply(rply CGRReplier, errRply error) (cgrReply CGRReply, err error) {
+ if errRply != nil {
+ return CGRReply{Error: errRply.Error()}, nil
+ }
+ if cgrReply, err = rply.AsCGRReply(); err != nil {
+ return
+ }
+ cgrReply[Error] = "" // enforce empty error
+ return
+}
+
+// CGRReply represents the CGRateS answer which can be used in templates
+// it can be layered, case when interface{} will be castable into map[string]interface{}
+type CGRReply map[string]interface{}
+
+// GetFieldAsString returns the field value as string for the path specified
+func (cgrReply CGRReply) GetFieldAsString(fldPath string, sep string) (fldVal string, err error) {
+ path := strings.Split(fldPath, sep)
+ lenPath := len(path)
+ if lenPath == 0 {
+ return "", errors.New("empty field path")
+ }
+ if path[0] == MetaCGRReply {
+ path = path[1:]
+ lenPath -= 1
+ }
+ lastMp := cgrReply // last map when layered
+ var canCast bool
+ for i, spath := range path {
+ if i == lenPath-1 { // lastElement
+ fldValIf, has := lastMp[spath]
+ if !has {
+ return "", fmt.Errorf("no field with path: <%s>", fldPath)
+ }
+
+ if fldVal, canCast = CastFieldIfToString(fldValIf); !canCast {
+ return "", fmt.Errorf("cannot cast field: %s to string", ToJSON(fldValIf))
+ }
+ return
+ } else {
+ lastMp, canCast = lastMp[spath].(map[string]interface{})
+ if !canCast {
+ return "", fmt.Errorf("cannot cast field: %s to map[string]interface{}", ToJSON(lastMp[spath]))
+ }
+ }
+ }
+ return "", errors.New("end of function")
+}
diff --git a/utils/cgrreply_test.go b/utils/cgrreply_test.go
new file mode 100644
index 000000000..a00393099
--- /dev/null
+++ b/utils/cgrreply_test.go
@@ -0,0 +1,86 @@
+/*
+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 utils
+
+import (
+ "errors"
+ "reflect"
+ "testing"
+)
+
+type myEv map[string]interface{}
+
+func (ev myEv) AsCGRReply() (CGRReply, error) {
+ return CGRReply(ev), nil
+}
+
+func TestCGRReplyNew(t *testing.T) {
+ eCgrRply := CGRReply(map[string]interface{}{
+ Error: "some",
+ })
+ if rpl, err := NewCGRReply(nil, errors.New("some")); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(eCgrRply, rpl) {
+ t.Errorf("Expecting: %+v, received: %+v", ToJSON(eCgrRply), ToJSON(rpl))
+ }
+ ev := myEv{
+ "FirstLevel": map[string]interface{}{
+ "SecondLevel": map[string]interface{}{
+ "Fld1": "Val1",
+ },
+ },
+ }
+ eCgrRply = CGRReply(ev)
+ eCgrRply[Error] = ""
+ if rpl, err := NewCGRReply(CGRReplier(ev), nil); err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(eCgrRply, rpl) {
+ t.Errorf("Expecting: %+v, received: %+v", eCgrRply, rpl)
+ }
+}
+
+func TestCGRReplyGetFieldAsString(t *testing.T) {
+ ev := myEv{
+ "FirstLevel": map[string]interface{}{
+ "SecondLevel": map[string]interface{}{
+ "ThirdLevel": map[string]interface{}{
+ "Fld1": "Val1",
+ },
+ },
+ },
+ "AnotherFirstLevel": "ValAnotherFirstLevel",
+ }
+ cgrRply, _ := NewCGRReply(CGRReplier(ev), nil)
+ if strVal, err := cgrRply.GetFieldAsString("*cgrReply>Error", ">"); err != nil {
+ t.Error(err)
+ } else if strVal != "" {
+ t.Error("received: <%s>", strVal)
+ }
+ eVal := "Val1"
+ if strVal, err := cgrRply.GetFieldAsString("*cgrReply>FirstLevel>SecondLevel>ThirdLevel>Fld1", ">"); err != nil {
+ t.Error(err)
+ } else if strVal != eVal {
+ t.Error("expecting: <%s> received: <%s>", eVal, strVal)
+ }
+ eVal = "ValAnotherFirstLevel"
+ if strVal, err := cgrRply.GetFieldAsString("*cgrReply>AnotherFirstLevel", ">"); err != nil {
+ t.Error(err)
+ } else if strVal != eVal {
+ t.Error("expecting: <%s> received: <%s>", eVal, strVal)
+ }
+}