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) + } +}