From 2e9138b55c56fa799d1005dec0c0dd3c4202f55a Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 9 Aug 2019 17:31:48 +0300 Subject: [PATCH] Updated config error handling --- config/config_json.go | 28 ++++++-- config/rjreader.go | 148 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+), 4 deletions(-) diff --git a/config/config_json.go b/config/config_json.go index fe0d4cdf2..e0d383a5b 100644 --- a/config/config_json.go +++ b/config/config_json.go @@ -86,8 +86,18 @@ func NewCgrJsonCfgFromFile(fpath string) (*CgrJsonCfg, error) { if err != nil { return nil, err } - defer cfgFile.Close() - return NewCgrJsonCfgFromReader(cfgFile) + cfg, err := NewCgrJsonCfgFromReader(cfgFile) + cfgFile.Close() + if err != nil { + // for a better error message + cfgFile, oerr := os.Open(fpath) + if oerr != nil { + return cfg, oerr + } + defer cfgFile.Close() + return cfg, HandleJSONError(cfgFile, err) + } + return cfg, nil } // Loads the config out of http request @@ -99,8 +109,18 @@ func NewCgrJsonCfgFromHttp(fpath string) (*CgrJsonCfg, error) { if err != nil { return nil, utils.ErrPathNotReachable(fpath) } - defer cfgReq.Body.Close() - return NewCgrJsonCfgFromReader(cfgReq.Body) + cfg, err := NewCgrJsonCfgFromReader(cfgReq.Body) + cfgReq.Body.Close() + if err != nil { + // for a better error message + cfgReq, rerr := myClient.Get(fpath) + if rerr != nil { + return nil, utils.ErrPathNotReachable(fpath) + } + defer cfgReq.Body.Close() + return cfg, HandleJSONError(cfgReq.Body, err) + } + return cfg, nil } // Main object holding the loaded config as section raw messages diff --git a/config/rjreader.go b/config/rjreader.go index 28bc36574..804db8d4a 100644 --- a/config/rjreader.go +++ b/config/rjreader.go @@ -20,12 +20,16 @@ package config import ( "bufio" + "encoding/json" + "fmt" "io" "os" "github.com/cgrates/cgrates/utils" ) +// NewRawJSONReader returns a raw JSON reader + // NewRawJSONReader returns a raw JSON reader func NewRawJSONReader(r io.Reader) io.Reader { return &EnvReader{ @@ -331,3 +335,147 @@ func (b *EnvReader) Read(p []byte) (n int, err error) { } return len(p), nil } + +// warning: needs to read file again +func HandleJSONError(reader io.Reader, err error) error { + var offset int64 + switch realErr := err.(type) { + case nil: + return nil + case *json.InvalidUTF8Error, *json.UnmarshalFieldError: // deprecated + return err + case *json.InvalidUnmarshalError: // e.g. nil parameter + return err + case *json.SyntaxError: + offset = realErr.Offset + case *json.UnmarshalTypeError: + offset = realErr.Offset + default: + fmt.Printf("%T", err) + return err + } + + var line int64 = 1 // start line counting from 1 + var character int64 + var lastChar byte + if offset == 0 { + return fmt.Errorf("%s at line %v around position %v", err.Error(), line, character) + } + br := bufio.NewReader(reader) + + var i int64 = 0 + readString := func() error { + for i < offset { + b, rerr := br.ReadByte() + if rerr != nil { + return rerr + } + i++ + if isNewLine(b) { + line++ + character = 0 + } else { + character++ + } + if b == '"' { + return nil + } + } + return nil + } + readLineComment := func() error { + for i < offset { + b, rerr := br.ReadByte() + if rerr != nil { + return rerr + } + if isNewLine(b) { + line++ + character = 0 + return nil + } + character++ + } + return nil + } + + readComment := func() error { + for i < offset { + b, rerr := br.ReadByte() + if rerr != nil { + return rerr + } + if isNewLine(b) { + line++ + character = 0 + } else { + character++ + } + if b == '*' { + b, rerr := br.ReadByte() + if rerr != nil { + return rerr + } + if b == '/' { + character++ + return nil + } + rerr = br.UnreadByte() + if rerr != nil { + return rerr + } + } + } + return nil + } + + for i < offset { // handle the parsing + b, rerr := br.ReadByte() + if rerr != nil { + break + } + character++ + if isNewLine(b) { + line++ + character = 0 + } + if (b == ']' || b == '}') && lastChar == ',' { + i-- //ignore ',' if is followed by ] or } + } + if !isWhiteSpace(b) { + i++ + lastChar = b + } + if b == '"' { // read "" value + rerr := readString() + if rerr != nil { + break + } + } + if b == '/' { + b, rerr := br.ReadByte() + if rerr != nil { + break + } + if b == '/' { // read // + i-- + rerr := readLineComment() + if rerr != nil { + break + } + } else if b == '*' { // read /* + i-- + rerr := readComment() + if rerr != nil { + break + } + } else { + rerr := br.UnreadByte() + if rerr != nil { + break + } + } + } + } + return fmt.Errorf("%s around line %v and position %v", err.Error(), line, character) +}