diff --git a/agents/httpagent.go b/agents/httpagent.go index 92428e3a2..502135388 100644 --- a/agents/httpagent.go +++ b/agents/httpagent.go @@ -19,22 +19,25 @@ along with this program. If not, see package agents import ( + "fmt" "net/http" "github.com/cgrates/cgrates/config" + "github.com/cgrates/cgrates/utils" "github.com/cgrates/rpcclient" ) -// NewHttpAgent will construct a HttpAgent -func NewHttpAgent(sessionS rpcclient.RpcClientConnection, +// NewHttpAgent will construct a HTTPAgent +func NewHTTPAgent(sessionS rpcclient.RpcClientConnection, timezone, reqPayload, rplyPayload string, - reqProcessors []*config.HttpAgntProcCfg) *HttpAgent { - return &HttpAgent{sessionS: sessionS, timezone: timezone, + reqProcessors []*config.HttpAgntProcCfg) *HTTPAgent { + return &HTTPAgent{sessionS: sessionS, timezone: timezone, reqPayload: reqPayload, rplyPayload: rplyPayload, reqProcessors: reqProcessors} } -type HttpAgent struct { +// HTTPAgent is a handler for HTTP requests +type HTTPAgent struct { sessionS rpcclient.RpcClientConnection timezone, reqPayload, @@ -43,5 +46,40 @@ type HttpAgent struct { } // ServeHTTP implements http.Handler interface -func (ha *HttpAgent) ServeHTTP(w http.ResponseWriter, req *http.Request) { +func (ha *HTTPAgent) ServeHTTP(w http.ResponseWriter, req *http.Request) { + _, err := newHAReqDecoder(ha.reqPayload, req) // dcdr + if err != nil { + utils.Logger.Warning( + fmt.Sprintf("<%s> error creating decoder: %s", + utils.HTTPAgent, err.Error())) + } + var processed bool + procVars := make(processorVars) + rpl := newHTTPReplyFields() + for _, reqProcessor := range ha.reqProcessors { + var lclProcessed bool + if lclProcessed, err = ha.processRequest(reqProcessor, req, + procVars, rpl); lclProcessed { + processed = lclProcessed + } + if err != nil || (lclProcessed && !reqProcessor.ContinueOnSuccess) { + break + } + } + if err != nil { + utils.Logger.Warning(fmt.Sprintf("<%s> error: %s processing request: %s, process vars: %+v", + utils.HTTPAgent, err.Error(), utils.ToJSON(req), procVars)) + return // FixMe with returning some error on HTTP level + } else if !processed { + utils.Logger.Warning(fmt.Sprintf("<%s> no request processor enabled, ignoring request %s, process vars: %+v", + utils.RadiusAgent, utils.ToJSON(req), procVars)) + return // FixMe with returning some error on HTTP level + } +} + +// processRequest represents one processor processing the request +func (ha *HTTPAgent) processRequest(reqProc *config.HttpAgntProcCfg, + req *http.Request, procVars processorVars, + reply *httpReplyFields) (processed bool, err error) { + return } diff --git a/agents/libhttpagent.go b/agents/libhttpagent.go new file mode 100644 index 000000000..1d9b72a91 --- /dev/null +++ b/agents/libhttpagent.go @@ -0,0 +1,71 @@ +/* +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 agents + +import ( + "fmt" + "net/http" +) + +// httpReplyField is one field written in HTTP reply +type httpReplyField struct { + fldPath, + fldVal string +} + +func newHTTPReplyFields() *httpReplyFields { + return &httpReplyFields{indexed: make(map[string]*httpReplyField), + ordered: make([]*httpReplyField, 0)} +} + +// httpReplyFields is the reply which will be written to HTTP +// both flds and ordered are pointig towards same httpReplyField +type httpReplyFields struct { + indexed map[string]*httpReplyField // map[fldPath]*httpReplyField + ordered []*httpReplyField // keep order for export +} + +// newHAReqDecoder produces decoders +func newHAReqDecoder(dcdType string, + req *http.Request) (rD httpAgentReqDecoder, err error) { + switch dcdType { + default: + return nil, fmt.Errorf("unsupported decoder type <%s>", dcdType) + } +} + +// httpAgentReqDecoder will decode request values +type httpAgentReqDecoder interface { + getFieldVal(fldPath string) (interface{}, error) +} + +// newHAReplyEncoder constructs a httpAgentReqDecoder based on encoder type +func newHAReplyEncoder(encType string, + w http.ResponseWriter) (rE httpAgentReplyEncoder, err error) { + switch encType { + default: + return nil, fmt.Errorf("unsupported encoder type <%s>", encType) + } +} + +// httpAgentReplyEncoder will encode fields from httpReplyFields +// and write content to http writer +type httpAgentReplyEncoder interface { + encode(*httpReplyFields) error +} diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index a984f5518..db9150f2a 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -368,7 +368,7 @@ func startHTTPAgent(internalSMGChan chan rpcclient.RpcClientConnection, exitChan } } server.RegisterHttpHandler(agntCfg.Url, - agents.NewHttpAgent(sSConn, agntCfg.Timezone, agntCfg.RequestPayload, + agents.NewHTTPAgent(sSConn, agntCfg.Timezone, agntCfg.RequestPayload, agntCfg.ReplyPayload, agntCfg.RequestProcessors)) } exitChan <- true diff --git a/config/httpagntcfg.go b/config/httpagntcfg.go index d626eee34..efef4a4f9 100644 --- a/config/httpagntcfg.go +++ b/config/httpagntcfg.go @@ -77,12 +77,13 @@ func (ca *HttpAgentCfg) loadFromJsonCfg(jsnCfg *HttpAgentJsonCfg) error { } type HttpAgntProcCfg struct { - Id string - DryRun bool - Filters []string - Flags utils.StringMap - RequestFields []*CfgCdrField - ReplyFields []*CfgCdrField + Id string + DryRun bool + Filters []string + Flags utils.StringMap + ContinueOnSuccess bool + RequestFields []*CfgCdrField + ReplyFields []*CfgCdrField } func (ha *HttpAgntProcCfg) loadFromJsonCfg(jsnCfg *HttpAgentProcessorJsnCfg) (err error) { @@ -104,6 +105,9 @@ func (ha *HttpAgntProcCfg) loadFromJsonCfg(jsnCfg *HttpAgentProcessorJsnCfg) (er if jsnCfg.Flags != nil { ha.Flags = utils.StringMapFromSlice(*jsnCfg.Flags) } + if jsnCfg.Continue_on_success != nil { + ha.ContinueOnSuccess = *jsnCfg.Continue_on_success + } if jsnCfg.Request_fields != nil { if ha.RequestFields, err = CfgCdrFieldsFromCdrFieldsJsonCfg(*jsnCfg.Request_fields); err != nil { return diff --git a/config/libconfig_json.go b/config/libconfig_json.go index 2f3f5943d..09587b134 100755 --- a/config/libconfig_json.go +++ b/config/libconfig_json.go @@ -383,12 +383,13 @@ type HttpAgentJsonCfg struct { } type HttpAgentProcessorJsnCfg struct { - Id *string - Dry_run *bool - Filters *[]string - Flags *[]string - Request_fields *[]*CdrFieldJsonCfg - Reply_fields *[]*CdrFieldJsonCfg + Id *string + Dry_run *bool + Filters *[]string + Flags *[]string + Continue_on_success *bool + Request_fields *[]*CdrFieldJsonCfg + Reply_fields *[]*CdrFieldJsonCfg } // History server config section