Files
cgrates/analyzers/libanalyzers.go
2025-10-13 09:57:41 +02:00

155 lines
4.1 KiB
Go

/*
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 Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
*/
package analyzers
import (
"encoding/json"
"strconv"
"time"
"github.com/blevesearch/bleve/v2/index/scorch"
"github.com/blevesearch/bleve/v2/index/upsidedown"
"github.com/blevesearch/bleve/v2/index/upsidedown/store/boltdb"
"github.com/blevesearch/bleve/v2/index/upsidedown/store/goleveldb"
"github.com/blevesearch/bleve/v2/index/upsidedown/store/moss"
"github.com/cgrates/cgrates/utils"
)
// NewInfoRPC returns a structure to be indexed
func NewInfoRPC(id uint64, method string,
params, result, err any,
enc, from, to string, sTime, eTime time.Time) *InfoRPC {
var e any
switch val := err.(type) {
default:
case nil:
case string:
e = val
case error:
e = val.Error()
}
return &InfoRPC{
RequestDuration: eTime.Sub(sTime),
RequestStartTime: sTime,
// EndTime: eTime,
RequestEncoding: enc,
RequestSource: from,
RequestDestination: to,
RequestID: id,
RequestMethod: method,
RequestParams: utils.ToJSON(params),
Reply: utils.ToJSON(result),
ReplyError: e,
}
}
// InfoRPC the structure to be indexed
type InfoRPC struct {
RequestDuration time.Duration
RequestStartTime time.Time
// EndTime time.Time
RequestEncoding string
RequestSource string
RequestDestination string
RequestID uint64
RequestMethod string
RequestParams any
Reply any
ReplyError any
}
type rpcAPI struct {
ID uint64 `json:"id"`
Method string `json:"method"`
Params any `json:"params"`
Error string `json:"err,omitempty"`
StartTime time.Time
}
func getIndex(indx string) (indxType, storeType string) {
switch indx {
case utils.MetaScorch:
indxType, storeType = scorch.Name, scorch.Name
case utils.MetaBoltdb:
indxType, storeType = upsidedown.Name, boltdb.Name
case utils.MetaLeveldb:
indxType, storeType = upsidedown.Name, goleveldb.Name
case utils.MetaMoss:
indxType, storeType = upsidedown.Name, moss.Name
}
return
}
// unmarshalJSON will transform the message in a map[string]any of []any
// depending of the first character
func unmarshalJSON(jsn json.RawMessage) (any, error) {
switch {
case string(jsn) == "null" ||
len(jsn) == 0: // nil or empty response
// by default consider nil as an empty map for filtering purposes
return nil, nil
case string(jsn) == "true": // booleans
return true, nil
case string(jsn) == "false":
return false, nil
case jsn[0] == '"': // string
return string(jsn[1 : len(jsn)-1]), nil
case jsn[0] >= '0' && jsn[0] <= '9': // float64
return strconv.ParseFloat(string(jsn), 64)
case jsn[0] == '[': // slice
var val []any
err := json.Unmarshal(jsn, &val)
return val, err
case jsn[0] == '{': // map
var val map[string]any
err := json.Unmarshal(jsn, &val)
return val, err
default:
return nil, new(json.SyntaxError)
}
}
// getDPFromSearchresult will unmarshal the request and reply and populate a DataProvider
// if the req is a map[string]any we will try to put in *opts prefix the Opts field from req
func getDPFromSearchresult(req, rep json.RawMessage, hdr utils.MapStorage) (utils.MapStorage, error) {
repDP, err := unmarshalJSON(rep)
if err != nil {
return nil, err
}
reqDP, err := unmarshalJSON(req)
if err != nil {
return nil, err
}
var opts any
if reqMp, canCast := reqDP.(map[string]any); canCast {
opts = reqMp[utils.Opts]
}
return utils.MapStorage{
utils.MetaReq: reqDP,
utils.MetaOpts: opts,
utils.MetaRep: repDP,
utils.MetaHdr: hdr,
}, nil
}