diff --git a/README.md b/README.md index 8445189..f61b348 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ go get -u github.com/nabbar/golib/... second, import the needed lib in your code ```go -import "github.com/nabbar/golib/njs-version" +import "github.com/nabbar/golib/version" ``` more information in each lib diff --git a/njs-archive/archive.go b/archive/archive.go similarity index 79% rename from njs-archive/archive.go rename to archive/archive.go index 4ac56d6..8f514f5 100644 --- a/njs-archive/archive.go +++ b/archive/archive.go @@ -23,31 +23,30 @@ * */ -package njs_archive +package archive import ( "os" - "github.com/nabbar/golib/njs-archive/bz2" - "github.com/nabbar/golib/njs-archive/gzip" - "github.com/nabbar/golib/njs-archive/tar" - "github.com/nabbar/golib/njs-archive/zip" + "github.com/nabbar/golib/archive/bz2" + "github.com/nabbar/golib/archive/gzip" + "github.com/nabbar/golib/archive/tar" + "github.com/nabbar/golib/archive/zip" - //. "github.com/nabbar/golib/njs-logger" + . "github.com/nabbar/golib/errors" + //. "github.com/nabbar/golib/logger" - iou "github.com/nabbar/golib/njs-ioutils" + iou "github.com/nabbar/golib/ioutils" ) type ArchiveType uint8 -func ExtractFile(src *os.File, fileNameContain, fileNameRegex string) (*os.File, error) { - var err error - +func ExtractFile(src *os.File, fileNameContain, fileNameRegex string) (*os.File, Error) { loc := src.Name() if dst, err := bz2.GetFile(src, fileNameContain, fileNameRegex); err == nil { //DebugLevel.Log("try deleting source archive...") - if err = iou.DelTempFile(src, true); err != nil { + if err = iou.DelTempFile(src); err != nil { return nil, err } //DebugLevel.Log("try another archive...") @@ -56,7 +55,7 @@ func ExtractFile(src *os.File, fileNameContain, fileNameRegex string) (*os.File, if dst, err := gzip.GetFile(src, fileNameContain, fileNameRegex); err == nil { //DebugLevel.Log("try deleting source archive...") - if err = iou.DelTempFile(src, true); err != nil { + if err = iou.DelTempFile(src); err != nil { return nil, err } //DebugLevel.Log("try another archive...") @@ -65,7 +64,7 @@ func ExtractFile(src *os.File, fileNameContain, fileNameRegex string) (*os.File, if dst, err := tar.GetFile(src, fileNameContain, fileNameRegex); err == nil { //DebugLevel.Log("try deleting source archive...") - if err = iou.DelTempFile(src, true); err != nil { + if err = iou.DelTempFile(src); err != nil { return nil, err } //DebugLevel.Log("try another archive...") @@ -74,17 +73,24 @@ func ExtractFile(src *os.File, fileNameContain, fileNameRegex string) (*os.File, if dst, err := zip.GetFile(src, fileNameContain, fileNameRegex); err == nil { //DebugLevel.Log("try deleting source archive...") - if err = iou.DelTempFile(src, true); err != nil { + if err = iou.DelTempFile(src); err != nil { return nil, err } //DebugLevel.Log("try another archive...") return ExtractFile(dst, fileNameContain, fileNameRegex) } + var ( + err error + ) + if _, err = src.Seek(0, 0); err != nil { + e1 := FILE_SEEK.ErrorParent(err) if src, err = os.Open(loc); err != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "reopening file", err) - return nil, err + e2 := FILE_OPEN.ErrorParent(err) + e2.AddParentError(e1) + return nil, e2 } } diff --git a/njs-archive/archive/model.go b/archive/archive/model.go similarity index 100% rename from njs-archive/archive/model.go rename to archive/archive/model.go diff --git a/archive/bz2/error.go b/archive/bz2/error.go new file mode 100644 index 0000000..ad07a3e --- /dev/null +++ b/archive/bz2/error.go @@ -0,0 +1,52 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package bz2 + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Archive + 10 + FILE_SEEK + IO_COPY +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case FILE_SEEK: + return "cannot seek into file" + case IO_COPY: + return "io copy occurs error" + } + + return "" +} diff --git a/njs-archive/bz2/reader.go b/archive/bz2/reader.go similarity index 85% rename from njs-archive/bz2/reader.go rename to archive/bz2/reader.go index f4b5ea4..57bc41a 100644 --- a/njs-archive/bz2/reader.go +++ b/archive/bz2/reader.go @@ -30,15 +30,16 @@ import ( "io" "os" - //. "github.com/nabbar/golib/njs-logger" + . "github.com/nabbar/golib/errors" + //. "github.com/nabbar/golib/logger" - iou "github.com/nabbar/golib/njs-ioutils" + iou "github.com/nabbar/golib/ioutils" ) -func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, err error) { +func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, err Error) { if _, e := src.Seek(0, 0); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "seeking buffer", e) - return nil, e + return nil, FILE_SEEK.ErrorParent(e) } r := bzip2.NewReader(src) @@ -46,12 +47,12 @@ func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, if t, e := iou.NewTempFile(); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "init new temporary buffer", e) return nil, e - } else if _, e = io.Copy(t, r); e != nil { + } else if _, e := io.Copy(t, r); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "copy buffer from archive reader", e) - return nil, e + return nil, IO_COPY.ErrorParent(e) } else if _, e = t.Seek(0, 0); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "seeking temp file", e) - return nil, e + return nil, FILE_SEEK.ErrorParent(e) } else { return t, nil } diff --git a/archive/error.go b/archive/error.go new file mode 100644 index 0000000..f223a26 --- /dev/null +++ b/archive/error.go @@ -0,0 +1,52 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package archive + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Archive + FILE_SEEK + FILE_OPEN +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case FILE_SEEK: + return "cannot seek into file" + case FILE_OPEN: + return "cannot open file" + } + + return "" +} diff --git a/archive/gzip/error.go b/archive/gzip/error.go new file mode 100644 index 0000000..3bb6b92 --- /dev/null +++ b/archive/gzip/error.go @@ -0,0 +1,55 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package gzip + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Archive + 20 + GZ_READER + FILE_SEEK + IO_COPY +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case GZ_READER: + return "cannot create new reader GZip" + case FILE_SEEK: + return "cannot seek into file" + case IO_COPY: + return "io copy occurs error" + } + + return "" +} diff --git a/njs-archive/gzip/reader.go b/archive/gzip/reader.go similarity index 82% rename from njs-archive/gzip/reader.go rename to archive/gzip/reader.go index 1cc183e..5f061a0 100644 --- a/njs-archive/gzip/reader.go +++ b/archive/gzip/reader.go @@ -30,21 +30,22 @@ import ( "io" "os" - //. "github.com/nabbar/golib/njs-logger" + . "github.com/nabbar/golib/errors" + //. "github.com/nabbar/golib/logger" - iou "github.com/nabbar/golib/njs-ioutils" + iou "github.com/nabbar/golib/ioutils" ) -func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, err error) { +func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, err Error) { if _, e := src.Seek(0, 0); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "seeking buffer", e) - return nil, e + return nil, FILE_SEEK.ErrorParent(e) } r, e := gz.NewReader(src) if e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "init gzip reader", e) - return nil, e + return nil, GZ_READER.ErrorParent(e) } defer r.Close() @@ -52,12 +53,12 @@ func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, if t, e := iou.NewTempFile(); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "init new temporary buffer", e) return nil, e - } else if _, e = io.Copy(t, r); e != nil { + } else if _, e := io.Copy(t, r); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "copy buffer from archive reader", e) - return nil, e - } else if _, e = t.Seek(0, 0); e != nil { + return nil, IO_COPY.ErrorParent(e) + } else if _, e := t.Seek(0, 0); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "seeking temp file", e) - return nil, e + return nil, FILE_SEEK.ErrorParent(e) } else { return t, nil } diff --git a/archive/tar/error.go b/archive/tar/error.go new file mode 100644 index 0000000..25a58e4 --- /dev/null +++ b/archive/tar/error.go @@ -0,0 +1,55 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package tar + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Archive + 30 + TAR_NEXT + FILE_SEEK + IO_COPY +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case TAR_NEXT: + return "cannot get next tar file" + case FILE_SEEK: + return "cannot seek into file" + case IO_COPY: + return "io copy occurs error" + } + + return "" +} diff --git a/njs-archive/tar/reader.go b/archive/tar/reader.go similarity index 82% rename from njs-archive/tar/reader.go rename to archive/tar/reader.go index 24a0ed0..e3750a6 100644 --- a/njs-archive/tar/reader.go +++ b/archive/tar/reader.go @@ -30,17 +30,18 @@ import ( "io" "os" - "github.com/nabbar/golib/njs-archive/archive" + "github.com/nabbar/golib/archive/archive" - //. "github.com/nabbar/golib/njs-logger" + . "github.com/nabbar/golib/errors" + //. "github.com/nabbar/golib/logger" - iou "github.com/nabbar/golib/njs-ioutils" + iou "github.com/nabbar/golib/ioutils" ) -func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, err error) { +func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, err Error) { if _, e := src.Seek(0, 0); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "seeking buffer", e) - return nil, e + return nil, FILE_SEEK.ErrorParent(e) } r := tar.NewReader(src) @@ -52,7 +53,7 @@ func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, return nil, nil } else if e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "trying to read next file", e) - return nil, e + return nil, TAR_NEXT.ErrorParent(e) } if h.FileInfo().Mode()&os.ModeType == os.ModeType { @@ -64,12 +65,12 @@ func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, if t, e := iou.NewTempFile(); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "init new temporary buffer", e) return nil, e - } else if _, e = io.Copy(t, r); e != nil { + } else if _, e := io.Copy(t, r); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "copy buffer from archive reader", e) - return nil, e - } else if _, e = t.Seek(0, 0); e != nil { + return nil, IO_COPY.ErrorParent(e) + } else if _, e := t.Seek(0, 0); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "seeking temp file", e) - return nil, e + return nil, FILE_SEEK.ErrorParent(e) } else { return t, nil } diff --git a/archive/zip/error.go b/archive/zip/error.go new file mode 100644 index 0000000..839f56c --- /dev/null +++ b/archive/zip/error.go @@ -0,0 +1,61 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package zip + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Archive + 40 + FILE_OPEN + FILE_CLOSE + FILE_SEEK + IO_COPY + ZIP_OPEN +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case FILE_OPEN: + return "cannot open zipped file" + case FILE_CLOSE: + return "closing file occurs error" + case FILE_SEEK: + return "cannot seek into file" + case IO_COPY: + return "io copy occurs error" + case ZIP_OPEN: + return "cannot open zip file" + } + + return "" +} diff --git a/njs-archive/zip/reader.go b/archive/zip/reader.go similarity index 76% rename from njs-archive/zip/reader.go rename to archive/zip/reader.go index 29ba71f..8b95971 100644 --- a/njs-archive/zip/reader.go +++ b/archive/zip/reader.go @@ -30,25 +30,26 @@ import ( "io" "os" - //. "github.com/nabbar/golib/njs-logger" + . "github.com/nabbar/golib/errors" + //. "github.com/nabbar/golib/logger" - iou "github.com/nabbar/golib/njs-ioutils" + iou "github.com/nabbar/golib/ioutils" - "github.com/nabbar/golib/njs-archive/archive" + "github.com/nabbar/golib/archive/archive" ) -func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, err error) { +func GetFile(src *os.File, filenameContain, filenameRegex string) (dst *os.File, err Error) { location := iou.GetTempFilePath(src) - if err = src.Close(); err != nil { + if e := src.Close(); err != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "trying to close temp file", err) - return + return dst, FILE_CLOSE.ErrorParent(e) } return getFile(location, filenameContain, filenameRegex) } -func getFile(src string, filenameContain, filenameRegex string) (dst *os.File, err error) { +func getFile(src string, filenameContain, filenameRegex string) (dst *os.File, err Error) { var ( r *zip.ReadCloser e error @@ -56,10 +57,12 @@ func getFile(src string, filenameContain, filenameRegex string) (dst *os.File, e if r, e = zip.OpenReader(src); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "trying to open zip file", e) - return nil, e + return nil, ZIP_OPEN.ErrorParent(e) } - defer r.Close() + defer func() { + _ = r.Close() + }() for _, f := range r.File { if f.Mode()&os.ModeType == os.ModeType { @@ -75,25 +78,30 @@ func getFile(src string, filenameContain, filenameRegex string) (dst *os.File, e return nil, nil } -func extratFile(f *zip.File) (dst *os.File, err error) { - var r io.ReadCloser +func extratFile(f *zip.File) (dst *os.File, err Error) { + var ( + r io.ReadCloser + e error + ) - if r, err = f.Open(); err != nil { + if r, e = f.Open(); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "open zipped file reader", err) - return + return dst, FILE_OPEN.ErrorParent(e) } - defer r.Close() + defer func() { + _ = r.Close() + }() if dst, err = iou.NewTempFile(); err != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "init new temporary buffer", err) return - } else if _, err = io.Copy(dst, r); err != nil { + } else if _, e = io.Copy(dst, r); e != nil { //ErrorLevel.LogErrorCtx(DebugLevel, "copy buffer from archive reader", err) - return + return dst, IO_COPY.ErrorParent(e) } - _, err = dst.Seek(0, 0) + _, e = dst.Seek(0, 0) //ErrorLevel.LogErrorCtx(DebugLevel, "seeking temp file", err) - return + return dst, FILE_SEEK.ErrorParent(e) } diff --git a/njs-certif/README.md b/certificates/README.md similarity index 100% rename from njs-certif/README.md rename to certificates/README.md diff --git a/certificates/error.go b/certificates/error.go new file mode 100644 index 0000000..191e348 --- /dev/null +++ b/certificates/error.go @@ -0,0 +1,61 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package certificates + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Certif + FILE_STAT_ERROR + FILE_READ_ERROR + CERT_APPEND_KO + CERT_LOAD_KEYPAIR + CERT_PARSE_KEYPAIR +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case FILE_STAT_ERROR: + return "cannot get file stat" + case FILE_READ_ERROR: + return "cannot read file" + case CERT_APPEND_KO: + return "cannot append PEM file" + case CERT_LOAD_KEYPAIR: + return "cannot X509 parsing certificate string" + case CERT_PARSE_KEYPAIR: + return "cannot x509 loading certificate file" + } + + return "" +} diff --git a/njs-certif/tlsTools.go b/certificates/tlsTools.go similarity index 77% rename from njs-certif/tlsTools.go rename to certificates/tlsTools.go index ee5d156..93717eb 100644 --- a/njs-certif/tlsTools.go +++ b/certificates/tlsTools.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_certif +package certificates import ( "crypto/tls" @@ -32,7 +32,7 @@ import ( "runtime" "strings" - logger "github.com/nabbar/golib/njs-logger" + . "github.com/nabbar/golib/errors" ) var ( @@ -40,6 +40,7 @@ var ( certificates = make([]tls.Certificate, 0) caCertificates = x509.NewCertPool() tlsMinVersion uint16 = tls.VersionTLS12 + tlsMaxVersion uint16 = tls.VersionTLS12 cipherList = []uint16{ tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, @@ -76,21 +77,26 @@ func AddRootCAContents(rootContent string) bool { return false } -func AddRootCAFile(rootFile string) bool { +func AddRootCAFile(rootFile string) Error { if rootFile == "" { - return false + return EMPTY_PARAMS.Error(nil) } - if _, e := os.Stat(rootFile); logger.ErrorLevel.LogErrorCtxf(logger.InfoLevel, "checking certificates file '%s'", e, rootFile) { - return false + if _, e := os.Stat(rootFile); e != nil { + return FILE_STAT_ERROR.ErrorParent(e) } c, e := ioutil.ReadFile(rootFile) // #nosec - if !logger.ErrorLevel.LogErrorCtxf(logger.InfoLevel, "loading certificates file '%s'", e, rootFile) { - return rootCA.AppendCertsFromPEM(c) + + if e == nil { + if rootCA.AppendCertsFromPEM(c) { + return nil + } + + return CERT_APPEND_KO.Error(nil) } - return false + return FILE_READ_ERROR.ErrorParent(e) } func AddCACertificateContents(caContent string) bool { @@ -101,61 +107,68 @@ func AddCACertificateContents(caContent string) bool { return false } -func AddCACertificateFile(caFile string) bool { +func AddCACertificateFile(caFile string) Error { if caFile == "" { - return false + return EMPTY_PARAMS.Error(nil) } - if _, e := os.Stat(caFile); logger.ErrorLevel.LogErrorCtxf(logger.InfoLevel, "checking certificates file '%s'", e, caFile) { - return false + if _, e := os.Stat(caFile); e != nil { + return FILE_STAT_ERROR.ErrorParent(e) } c, e := ioutil.ReadFile(caFile) // #nosec - if !logger.ErrorLevel.LogErrorCtxf(logger.InfoLevel, "loading certificates file '%s'", e, caFile) { - return caCertificates.AppendCertsFromPEM(c) + + if e == nil { + if caCertificates.AppendCertsFromPEM(c) { + return nil + } + + return CERT_APPEND_KO.Error(nil) } - return false + return FILE_READ_ERROR.ErrorParent(e) } func CheckCertificates() bool { return len(certificates) > 0 } -func AddCertificateContents(keyContents, certContents string) bool { +func AddCertificateContents(keyContents, certContents string) Error { keyContents = strings.TrimSpace(keyContents) certContents = strings.TrimSpace(certContents) if keyContents != "" && keyContents != "\n" && certContents != "" && certContents != "\n" { c, err := tls.X509KeyPair([]byte(certContents), []byte(keyContents)) - if !logger.ErrorLevel.LogErrorCtx(logger.InfoLevel, "loading certificates contents", err) { + if err == nil { certificates = append(certificates, c) - return true + return nil } + + return CERT_PARSE_KEYPAIR.ErrorParent(err) } - return false + return EMPTY_PARAMS.Error(nil) } -func AddCertificateFile(keyFile, certFile string) bool { +func AddCertificateFile(keyFile, certFile string) Error { if keyFile == "" || certFile == "" { - return false + return EMPTY_PARAMS.Error(nil) } - if _, e := os.Stat(keyFile); logger.ErrorLevel.LogErrorCtxf(logger.InfoLevel, "loading certificates file '%s'", e, keyFile) { - return false + if _, e := os.Stat(keyFile); e != nil { + return FILE_STAT_ERROR.ErrorParent(e) } - if _, e := os.Stat(certFile); logger.ErrorLevel.LogErrorCtxf(logger.InfoLevel, "loading certificates file '%s'", e, certFile) { - return false + if _, e := os.Stat(certFile); e != nil { + return FILE_STAT_ERROR.ErrorParent(e) } - if c, e := tls.LoadX509KeyPair(certFile, keyFile); !logger.ErrorLevel.LogErrorCtx(logger.InfoLevel, "loading X509 Pair file", e) { + if c, e := tls.LoadX509KeyPair(certFile, keyFile); e == nil { certificates = append(certificates, c) - return true + return nil + } else { + return CERT_LOAD_KEYPAIR.ErrorParent(e) } - - return false } func GetCertificates() []tls.Certificate { @@ -178,29 +191,30 @@ func GetClientCA() *x509.CertPool { return caCertificates } -func SetStringTlsVersion(tlsVersStr string) { +func SetVersionMin(vers uint16) { + tlsMinVersion = vers +} + +func SetVersionMax(vers uint16) { + tlsMaxVersion = vers +} + +func SetStringTlsVersion(tlsVersStr string) uint16 { tlsVersStr = strings.ToLower(tlsVersStr) tlsVersStr = strings.Replace(tlsVersStr, "TLS", "", -1) tlsVersStr = strings.TrimSpace(tlsVersStr) switch tlsVersStr { case "1", "1.0": - tlsMinVersion = tls.VersionTLS10 + return tls.VersionTLS10 case "1.1": - tlsMinVersion = tls.VersionTLS11 + return tls.VersionTLS11 + case "1.2": + return tls.VersionTLS12 + case "1.3": + return tls.VersionTLS13 default: - tlsMinVersion = tls.VersionTLS12 - } -} - -func SetTlsVersion(tlsVers uint16) { - switch tlsVers { - case tls.VersionTLS10: - tlsMinVersion = tls.VersionTLS10 - case tls.VersionTLS11: - tlsMinVersion = tls.VersionTLS11 - default: - tlsMinVersion = tls.VersionTLS12 + return tls.VersionTLS12 } } @@ -287,10 +301,17 @@ func GetTLSConfig(serverName string) *tls.Config { cnf := &tls.Config{ RootCAs: rootCA, ClientCAs: caCertificates, - MinVersion: tlsMinVersion, InsecureSkipVerify: false, } + if tlsMinVersion > 0 { + cnf.MinVersion = tlsMinVersion + } + + if tlsMaxVersion > 0 { + cnf.MaxVersion = tlsMaxVersion + } + if serverName != "" { cnf.ServerName = serverName } @@ -326,8 +347,9 @@ func GetTlsConfigCertificates() *tls.Config { cnf.ClientAuth = clientAuth } - cnf.Certificates = certificates - cnf.BuildNameToCertificate() + if len(cnf.Certificates) > 0 { + cnf.Certificates = certificates + } return cnf } diff --git a/njs-console/README.md b/console/README.md similarity index 100% rename from njs-console/README.md rename to console/README.md diff --git a/njs-console/color.go b/console/color.go similarity index 85% rename from njs-console/color.go rename to console/color.go index cf069b4..f2d0b79 100644 --- a/njs-console/color.go +++ b/console/color.go @@ -23,13 +23,15 @@ * */ -package njs_console +package console import ( "bufio" "fmt" "github.com/fatih/color" + + . "github.com/nabbar/golib/errors" ) type colorType uint8 @@ -84,13 +86,28 @@ func (c colorType) Print(text string) { } } -func (c colorType) BuffPrintf(buff *bufio.ReadWriter, format string, args ...interface{}) (n int, err error) { +func (c colorType) BuffPrintf(buff *bufio.ReadWriter, format string, args ...interface{}) (n int, err Error) { if colorList[c] != nil && buff != nil { - return colorList[c].Fprintf(buff, format, args...) // #nosec + + i, e := colorList[c].Fprintf(buff, format, args...) // #nosec + + if e != nil { + return i, COLOR_IO_FRINTF.ErrorParent(e) + } + + return i, nil + } else if buff != nil { - return buff.Write([]byte(fmt.Sprintf(format, args...))) + + i, e := buff.Write([]byte(fmt.Sprintf(format, args...))) + + if e != nil { + return i, COLOR_BUFF_WRITE.ErrorParent(e) + } + + return i, nil } else { - return 0, fmt.Errorf("buffer is not defined") + return 0, COLOR_BUFF_UNDEFINED.Error(nil) } } diff --git a/console/error.go b/console/error.go new file mode 100644 index 0000000..4dbc9c0 --- /dev/null +++ b/console/error.go @@ -0,0 +1,55 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package console + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Console + COLOR_IO_FRINTF + COLOR_BUFF_WRITE + COLOR_BUFF_UNDEFINED +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case COLOR_IO_FRINTF: + return "cannot write on IO" + case COLOR_BUFF_WRITE: + return "cannot write on buffer" + case COLOR_BUFF_UNDEFINED: + return "buffer is not defined" + } + + return "" +} diff --git a/njs-console/padding.go b/console/padding.go similarity index 98% rename from njs-console/padding.go rename to console/padding.go index 5cec1e0..88fb323 100644 --- a/njs-console/padding.go +++ b/console/padding.go @@ -23,7 +23,7 @@ * */ -package njs_console +package console import ( "strings" diff --git a/njs-console/prompt.go b/console/prompt.go similarity index 99% rename from njs-console/prompt.go rename to console/prompt.go index 95c5464..533373d 100644 --- a/njs-console/prompt.go +++ b/console/prompt.go @@ -23,7 +23,7 @@ * */ -package njs_console +package console import ( "bufio" diff --git a/njs-crypt/README.md b/crypt/README.md similarity index 100% rename from njs-crypt/README.md rename to crypt/README.md diff --git a/njs-crypt/crypt.go b/crypt/crypt.go similarity index 75% rename from njs-crypt/crypt.go rename to crypt/crypt.go index 9a6ce83..19c1662 100644 --- a/njs-crypt/crypt.go +++ b/crypt/crypt.go @@ -23,15 +23,17 @@ * */ -package njs_crypt +package crypt import ( + "io" + "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/hex" - "fmt" - "io" + + . "github.com/nabbar/golib/errors" ) var ( @@ -39,20 +41,22 @@ var ( cryptNonce = make([]byte, 12) ) -func SetKeyHex(key, nonce string) error { +func SetKeyHex(key, nonce string) Error { var err error // Load your secret key from a safe place and reuse it across multiple // Seal/Open calls. (Obviously don't use this example key for anything // real.) If you want to convert a passphrase to a key, use a suitable // package like bcrypt or scrypt. cryptKey, err = hex.DecodeString(key) + if err != nil { - return fmt.Errorf("converting hexa key error : %v", err) + return HEXA_KEY.ErrorParent(err) } cryptNonce, err = hex.DecodeString(nonce) + if err != nil { - return fmt.Errorf("converting hexa nonce error : %v", err) + return HEXA_NONCE.ErrorParent(err) } return nil @@ -63,51 +67,55 @@ func SetKeyByte(key [32]byte, nonce [12]byte) { cryptNonce = nonce[:] } -func GenKeyByte() ([]byte, []byte, error) { +func GenKeyByte() ([]byte, []byte, Error) { // Never use more than 2^32 random key with a given key because of the risk of a repeat. if _, err := io.ReadFull(rand.Reader, cryptKey); err != nil { - return make([]byte, 32), make([]byte, 12), fmt.Errorf("key generate error : %v", err) + return make([]byte, 32), make([]byte, 12), BYTE_KEYGEN.ErrorParent(err) } // Never use more than 2^32 random nonces with a given key because of the risk of a repeat. if _, err := io.ReadFull(rand.Reader, cryptNonce); err != nil { - return make([]byte, 32), make([]byte, 12), fmt.Errorf("nonce generate error : %v", err) + return make([]byte, 32), make([]byte, 12), BYTE_NONCEGEN.ErrorParent(err) } return cryptKey, cryptNonce, nil } -func Encrypt(clearValue []byte) (string, error) { +func Encrypt(clearValue []byte) (string, Error) { // When decoded the key should be 16 bytes (AES-128) or 32 (AES-256). block, err := aes.NewCipher(cryptKey) if err != nil { - return "", fmt.Errorf("init AES block error : %v", err) + return "", AES_BLOCK.ErrorParent(err) } aesgcm, err := cipher.NewGCM(block) if err != nil { - return "", fmt.Errorf("AES GSM cipher init : %v", err) + return "", AES_GCM.ErrorParent(err) } return hex.EncodeToString(aesgcm.Seal(nil, cryptNonce, clearValue, nil)), nil } -func Decrypt(hexaVal string) ([]byte, error) { +func Decrypt(hexaVal string) ([]byte, Error) { // When decoded the key should be 16 bytes (AES-128) or 32 (AES-256). ciphertext, err := hex.DecodeString(hexaVal) if err != nil { - return nil, fmt.Errorf("hexa decode crypted value error : %v", err) + return nil, HEXA_DECODE.ErrorParent(err) } block, err := aes.NewCipher(cryptKey) if err != nil { - return nil, fmt.Errorf("AES block init error : %v", err) + return nil, AES_BLOCK.ErrorParent(err) } aesgcm, err := cipher.NewGCM(block) if err != nil { - return nil, fmt.Errorf("AES GSM cipher init error : %v", err) + return nil, AES_GCM.ErrorParent(err) } - return aesgcm.Open(nil, cryptNonce, ciphertext, nil) + if res, err := aesgcm.Open(nil, cryptNonce, ciphertext, nil); err != nil { + return res, AES_DECRYPT.ErrorParent(err) + } else { + return res, nil + } } diff --git a/crypt/error.go b/crypt/error.go new file mode 100644 index 0000000..282e543 --- /dev/null +++ b/crypt/error.go @@ -0,0 +1,70 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package crypt + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Crypt + HEXA_DECODE + HEXA_KEY + HEXA_NONCE + BYTE_KEYGEN + BYTE_NONCEGEN + AES_BLOCK + AES_GCM + AES_DECRYPT +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case HEXA_DECODE: + return "hexa decode error" + case HEXA_KEY: + return "converting hexa key error" + case HEXA_NONCE: + return "converting hexa nonce error" + case BYTE_KEYGEN: + return "key generate error" + case BYTE_NONCEGEN: + return "nonce generate error" + case AES_BLOCK: + return "init AES block error" + case AES_GCM: + return "init AES GCM error" + case AES_DECRYPT: + return "decrypt AES GCM error" + } + + return "" +} diff --git a/errors/code.go b/errors/code.go new file mode 100644 index 0000000..534a955 --- /dev/null +++ b/errors/code.go @@ -0,0 +1,88 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package errors + +import ( + "strconv" +) + +var msgfct = make([]Message, 0) + +type Message func(code CodeError) (message string) +type CodeError uint16 + +const UNK_ERROR CodeError = 0 +const UNK_MESSAGE = "unknown error" + +func (c CodeError) GetUint16() uint16 { + return uint16(c) +} + +func (c CodeError) GetInt() int { + return int(c) +} + +func (c CodeError) GetString() string { + return strconv.Itoa(c.GetInt()) +} + +func (c CodeError) GetMessage() string { + if c == UNK_ERROR { + return UNK_MESSAGE + } + + for _, f := range msgfct { + m := f(c) + if m != "" { + return m + } + } + + return UNK_MESSAGE +} + +func (c CodeError) Error(p Error) Error { + return NewError(c.GetUint16(), c.GetMessage(), p) +} + +func (c CodeError) ErrorParent(p ...error) Error { + e := c.Error(nil) + e.AddParent(p...) + return e +} + +func (c CodeError) IfError(e Error) Error { + return NewErrorIfError(c.GetUint16(), c.GetMessage(), e) +} + +func (c CodeError) Iferror(e error) Error { + return NewErrorIferror(c.GetUint16(), c.GetMessage(), e) +} + +func RegisterFctMessage(fct Message) { + msgfct = append(msgfct, fct) +} diff --git a/errors/errors.go b/errors/errors.go new file mode 100644 index 0000000..bdc1a88 --- /dev/null +++ b/errors/errors.go @@ -0,0 +1,397 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package errors + +import ( + errs "errors" + "fmt" + "runtime" + "strconv" + "strings" +) + +var ( + defaultGlue = ", " + defaultPattern = "[Error #%s] %s" + defaultPatternTrace = "[Error #%s] %s (%s)" +) + +func SetDefaultGlue(glue string) { + defaultGlue = glue +} + +func GetDefaultGlue() string { + return defaultGlue +} + +func SetDefaultPattern(pattern string) { + defaultPattern = pattern +} + +func GetDefaultPattern() string { + return defaultPattern +} + +func SetDefaultPatternTrace(patternTrace string) { + defaultPatternTrace = patternTrace +} + +func GetDefaultPatternTrace() string { + return defaultPatternTrace +} + +type errors struct { + c uint16 + e string + p []Error + t runtime.Frame +} + +type Error interface { + IsCodeError(code CodeError) bool + HasCodeError(code CodeError) bool + + IsError(e error) bool + HasError(err error) bool + + AddParent(parent ...error) + SetParent(parent ...error) + AddParentError(parent ...Error) + SetParentError(parent ...Error) + + Code() string + CodeFull(glue string) string + CodeSlice() []string + + CodeError(pattern string) string + CodeErrorFull(pattern, glue string) string + CodeErrorSlice(pattern string) []string + + CodeErrorTrace(pattern string) string + CodeErrorTraceFull(pattern, glue string) string + CodeErrorTraceSlice(pattern string) []string + + Error() string + + StringError() string + StringErrorFull(glue string) string + StringErrorSlice() []string + + GetError() error + GetErrorFull(glue string) error + GetErrorSlice() []error + + GetIError() Error + GetIErrorSlice() []Error + + GetTrace() string + GetTraceSlice() []string +} + +func MakeErrorIfError(err ...Error) Error { + var e Error = nil + + for _, p := range err { + if p == nil { + continue + } + if e == nil { + e = p + } else { + e.AddParentError(p) + } + } + + return e +} + +func NewError(code uint16, message string, parent Error) Error { + if parent == nil { + parent = &errors{ + c: 0, + e: "", + p: make([]Error, 0), + } + } + + return &errors{ + c: code, + e: message, + p: parent.GetIErrorSlice(), + t: getFrame(), + } +} + +func NewErrorIferror(code uint16, message string, parent error) Error { + if parent == nil { + return nil + } + + p := make([]Error, 0) + p = append(p, &errors{ + c: 0, + e: parent.Error(), + p: nil, + }) + + return &errors{ + c: code, + e: message, + p: p, + t: getFrame(), + } +} + +func NewErrorIfError(code uint16, message string, parent Error) Error { + if parent == nil { + return nil + } + + return &errors{ + c: code, + e: message, + p: parent.GetIErrorSlice(), + t: getFrame(), + } +} + +func (e *errors) AddParent(parent ...error) { + for _, v := range parent { + + if v == nil { + continue + } + + e.p = append(e.p, &errors{ + c: 0, + e: v.Error(), + p: nil, + }) + } +} + +func (e *errors) IsCodeError(code CodeError) bool { + return e.c == code.GetUint16() +} + +func (e *errors) IsError(err error) bool { + return e.e == err.Error() +} + +func (e *errors) HasCodeError(code CodeError) bool { + if e.IsCodeError(code) { + return true + } + + for _, p := range e.p { + if p.IsCodeError(code) { + return true + } + } + + return false +} + +func (e *errors) HasError(err error) bool { + if e.IsError(err) { + return true + } + + for _, p := range e.p { + if p.IsError(err) { + return true + } + } + + return false +} + +func (e *errors) SetParent(parent ...error) { + e.p = make([]Error, 0) + e.AddParent(parent...) +} + +func (e *errors) AddParentError(parent ...Error) { + e.p = append(e.p, parent...) +} + +func (e *errors) SetParentError(parent ...Error) { + e.p = parent +} + +func (e *errors) Code() string { + return strconv.Itoa(int(e.c)) +} + +func (e *errors) CodeFull(glue string) string { + if glue == "" { + glue = defaultGlue + } + + return strings.Join(e.CodeSlice(), glue) +} + +func (e *errors) CodeSlice() []string { + var r = []string{e.Code()} + + for _, v := range e.p { + r = append(r, v.Code()) + } + + return r +} + +func (e *errors) Error() string { + return modeError.error(e) +} + +func (e *errors) StringError() string { + return e.e +} + +func (e *errors) StringErrorFull(glue string) string { + if glue == "" { + glue = defaultGlue + } + + return strings.Join(e.StringErrorSlice(), glue) +} + +func (e *errors) StringErrorSlice() []string { + var r = []string{e.Error()} + + for _, v := range e.p { + r = append(r, v.Error()) + } + + return r +} + +func (e *errors) GetError() error { + return errs.New(e.e) +} + +func (e *errors) GetErrorFull(glue string) error { + return errs.New(e.StringErrorFull(glue)) +} + +func (e *errors) GetErrorSlice() []error { + var r = []error{e.GetError()} + + for _, v := range e.p { + r = append(r, v.GetError()) + } + + return r +} + +func (e *errors) GetIError() Error { + return e +} + +func (e *errors) GetIErrorSlice() []Error { + var r = []Error{e} + + for _, v := range e.p { + r = append(r, v.GetIError()) + } + + return r +} + +func (e *errors) GetTrace() string { + if e.t.File != "" { + return fmt.Sprintf("%s#%d", e.t.File, e.t.Line) + } else if e.t.Function != "" { + return fmt.Sprintf("%s#%d", e.t.Function, e.t.Line) + } + + return "" +} + +func (e *errors) GetTraceSlice() []string { + var r = []string{e.GetTrace()} + + for _, v := range e.p { + if t := v.GetTrace(); t != "" { + r = append(r, v.GetTrace()) + } + } + + return r +} + +func (e *errors) CodeError(pattern string) string { + if pattern == "" { + pattern = defaultPattern + } + return fmt.Sprintf(pattern, e.Code(), e.Error()) +} + +func (e *errors) CodeErrorFull(pattern, glue string) string { + if glue == "" { + glue = defaultGlue + } + + return strings.Join(e.CodeErrorSlice(pattern), glue) +} + +func (e *errors) CodeErrorSlice(pattern string) []string { + var r = []string{e.CodeError(pattern)} + + for _, v := range e.p { + r = append(r, v.CodeError(pattern)) + } + + return r +} + +func (e *errors) CodeErrorTrace(pattern string) string { + if pattern == "" { + pattern = defaultPatternTrace + } + + return fmt.Sprintf(pattern, e.Code(), e.GetTrace(), e.Error()) +} + +func (e *errors) CodeErrorTraceFull(pattern, glue string) string { + if glue == "" { + glue = defaultGlue + } + + return strings.Join(e.CodeErrorTraceSlice(pattern), glue) +} + +func (e *errors) CodeErrorTraceSlice(pattern string) []string { + var r = []string{e.CodeErrorTrace(pattern)} + + for _, v := range e.p { + r = append(r, v.CodeErrorTrace(pattern)) + } + + return r +} diff --git a/errors/mode.go b/errors/mode.go new file mode 100644 index 0000000..47d6d07 --- /dev/null +++ b/errors/mode.go @@ -0,0 +1,99 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package errors + +var modeError = ERROR_RETURN_Default + +func SetModeReturnError(mode ErrorMode) { + modeError = mode +} + +func GetModeReturnError() ErrorMode { + return modeError +} + +type ErrorMode uint8 + +const ( + ERROR_RETURN_Default ErrorMode = iota + ERROR_RETURN_Code + ERROR_RETURN_CodeFull + ERROR_RETURN_CodeError + ERROR_RETURN_CodeErrorFull + ERROR_RETURN_CodeErrorTrace + ERROR_RETURN_CodeErrorTraceFull + ERROR_RETURN_StringError + ERROR_RETURN_StringErrorFull +) + +func (m ErrorMode) String() string { + switch m { + case ERROR_RETURN_Code: + return "Code" + case ERROR_RETURN_CodeFull: + return "CodeFull" + case ERROR_RETURN_CodeError: + return "CodeError" + case ERROR_RETURN_CodeErrorFull: + return "CodeErrorFull" + case ERROR_RETURN_CodeErrorTrace: + return "CodeErrorTrace" + case ERROR_RETURN_CodeErrorTraceFull: + return "CodeErrorTraceFull" + case ERROR_RETURN_StringError: + return "StringError" + case ERROR_RETURN_StringErrorFull: + return "StringErrorFull" + + default: + return "default" + } +} + +func (m ErrorMode) error(e *errors) string { + switch m { + case ERROR_RETURN_Code: + return e.Code() + case ERROR_RETURN_CodeFull: + return e.CodeFull("") + case ERROR_RETURN_CodeError: + return e.CodeError("") + case ERROR_RETURN_CodeErrorFull: + return e.CodeErrorFull("", "") + case ERROR_RETURN_CodeErrorTrace: + return e.CodeErrorTrace("") + case ERROR_RETURN_CodeErrorTraceFull: + return e.CodeErrorTraceFull("", "") + case ERROR_RETURN_StringError: + return e.StringError() + case ERROR_RETURN_StringErrorFull: + return e.StringErrorFull("") + + default: + return e.StringError() + } +} diff --git a/errors/modules.go b/errors/modules.go new file mode 100644 index 0000000..472089a --- /dev/null +++ b/errors/modules.go @@ -0,0 +1,51 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package errors + +const ( + MIN_PKG_Archive = 100 + // MIN_PKG_Artifact = 200 // unused + MIN_PKG_Certif = 300 + MIN_PKG_Console = 400 + MIN_PKG_Crypt = 500 + MIN_PKG_Httpcli = 600 + MIN_PKG_Httpserver = 700 + MIN_PKG_IOUtils = 800 + MIN_PKG_LDAP = 900 + // MIN_PKG_Logger = 1000 // unused + // MIN_PKG_Password = 1100 // unused + // MIN_PKG_Progress = 1200 // unused + MIN_PKG_Router = 1300 + MIN_PKG_Semaphore = 1400 + MIN_PKG_SMTP = 1500 + MIN_PKG_Static = 1600 + // MIN_PKG_Status = 1700 // unused + // MIN_PKG_Update = 1800 // unused + MIN_PKG_Version = 1900 + + MIN_AVAILABLE = 2000 +) diff --git a/errors/trace.go b/errors/trace.go new file mode 100644 index 0000000..7557d5b --- /dev/null +++ b/errors/trace.go @@ -0,0 +1,67 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package errors + +import ( + "path" + "reflect" + "runtime" + "strings" +) + +var currPkgs = path.Base(reflect.TypeOf(UNK_ERROR).PkgPath()) + +func getFrame() runtime.Frame { + // Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need + programCounters := make([]uintptr, 0) + n := runtime.Callers(0, programCounters) + + if n > 0 { + frames := runtime.CallersFrames(programCounters[:n]) + more := true + + for more { + var ( + frame runtime.Frame + ) + + frame, more = frames.Next() + + if strings.Contains(frame.Function, currPkgs) { + continue + } + + return frame + } + } + + return getNilFrame() +} + +func getNilFrame() runtime.Frame { + return runtime.Frame{Function: "", File: "", Line: 0} +} diff --git a/go.mod b/go.mod index c6caeb6..4e4f9c5 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/VividCortex/ewma v1.1.1 // indirect github.com/fatih/color v1.9.0 github.com/gin-gonic/gin v1.6.3 + github.com/go-ldap/ldap/v3 v3.2.2 github.com/go-playground/validator/v10 v10.3.0 // indirect github.com/gobuffalo/envy v1.9.0 // indirect github.com/gobuffalo/packd v1.0.0 // indirect @@ -27,12 +28,13 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/vbauerster/mpb v3.4.0+incompatible // indirect - github.com/vbauerster/mpb/v5 v5.2.2 + github.com/vbauerster/mpb/v5 v5.2.3 github.com/vjeantet/ldapserver v0.0.0-20170919170217-479fece7c5f1 // indirect - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 - golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect + golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 + golang.org/x/net v0.0.0-20200707034311-ab3426394381 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect + golang.org/x/text v0.3.3 // indirect google.golang.org/protobuf v1.25.0 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v9 v9.31.0 // indirect diff --git a/go.sum b/go.sum index ac67303..7334664 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= +github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= @@ -26,6 +28,11 @@ github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM= github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8= +github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHjsvuZyatzwk= +github.com/go-ldap/ldap/v3 v3.2.2 h1:XIXsu/Z2SbIMrh51WMAf0t7zWftlCKoZiLU6MS8KWm8= +github.com/go-ldap/ldap/v3 v3.2.2/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= @@ -176,6 +183,8 @@ github.com/vbauerster/mpb v3.4.0+incompatible h1:mfiiYw87ARaeRW6x5gWwYRUawxaW1tL github.com/vbauerster/mpb v3.4.0+incompatible/go.mod h1:zAHG26FUhVKETRu+MWqYXcI70POlC6N8up9p1dID7SU= github.com/vbauerster/mpb/v5 v5.2.2 h1:zIICVOm+XD+uV6crpSORaL6I0Q1WqOdvxZTp+r3L9cw= github.com/vbauerster/mpb/v5 v5.2.2/go.mod h1:W5Fvgw4dm3/0NhqzV8j6EacfuTe5SvnzBRwiXxDR9ww= +github.com/vbauerster/mpb/v5 v5.2.3 h1:OfqncMAhUojApki4/AxW4Z14cpiYBw7+MVLOyGklBmM= +github.com/vbauerster/mpb/v5 v5.2.3/go.mod h1:K4iCHQp5sWnmAgEn+uW1sAxSilctb4JPAGXx49jV+Aw= github.com/vjeantet/ldapserver v0.0.0-20170919170217-479fece7c5f1/go.mod h1:+KHPMCVmFBVXK3UAUom0AgP/IeOXH5C3ieEwA+JU3WE= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -191,6 +200,8 @@ golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -215,6 +226,8 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYc golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -255,7 +268,10 @@ golang.org/x/sys v0.0.0-20200620081246-981b61492c35/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= diff --git a/njs-httpcli/README.md b/httpcli/README.md similarity index 100% rename from njs-httpcli/README.md rename to httpcli/README.md diff --git a/httpcli/cli.go b/httpcli/cli.go new file mode 100644 index 0000000..c46de8f --- /dev/null +++ b/httpcli/cli.go @@ -0,0 +1,92 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package httpcli + +import ( + "crypto/tls" + "net" + "net/http" + "time" + + "golang.org/x/net/http2" + + . "github.com/nabbar/golib/errors" + + njs_certif "github.com/nabbar/golib/certificates" +) + +const ( + TIMEOUT_30_SEC = 30 * time.Second + TIMEOUT_10_SEC = 10 * time.Second + TIMEOUT_5_SEC = 5 * time.Second + TIMEOUT_1_SEC = 1 * time.Second +) + +func GetClient(serverName string) *http.Client { + c, e := getClient(true, TIMEOUT_30_SEC, TIMEOUT_10_SEC, TIMEOUT_30_SEC, TIMEOUT_30_SEC, TIMEOUT_5_SEC, TIMEOUT_1_SEC, njs_certif.GetTLSConfig(serverName)) + + if e != nil { + c, _ = getClient(false, TIMEOUT_30_SEC, TIMEOUT_10_SEC, TIMEOUT_30_SEC, TIMEOUT_30_SEC, TIMEOUT_5_SEC, TIMEOUT_1_SEC, njs_certif.GetTLSConfig(serverName)) + } + + return c +} + +func GetClientError(serverName string) (*http.Client, Error) { + return getClient(true, TIMEOUT_30_SEC, TIMEOUT_10_SEC, TIMEOUT_30_SEC, TIMEOUT_30_SEC, TIMEOUT_5_SEC, TIMEOUT_1_SEC, njs_certif.GetTLSConfig(serverName)) +} + +func GetClientTimeout(serverName string, GlobalTimeout, DialTimeOut, DialKeepAlive, IdleConnTimeout, TLSHandshakeTimeout, ExpectContinueTimeout time.Duration) (*http.Client, Error) { + return getClient(true, GlobalTimeout, DialTimeOut, DialKeepAlive, IdleConnTimeout, TLSHandshakeTimeout, ExpectContinueTimeout, njs_certif.GetTLSConfig(serverName)) +} + +func getClient(http2Transport bool, GlobalTimeout, DialTimeOut, DialKeepAlive, IdleConnTimeout, TLSHandshakeTimeout, ExpectContinueTimeout time.Duration, tlsConfig *tls.Config) (*http.Client, Error) { + tr := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: DialTimeOut, + KeepAlive: DialKeepAlive, + }).DialContext, + MaxIdleConns: 100, + IdleConnTimeout: IdleConnTimeout, + TLSHandshakeTimeout: TLSHandshakeTimeout, + ExpectContinueTimeout: ExpectContinueTimeout, + DisableCompression: true, + TLSClientConfig: tlsConfig, + } + + if http2Transport { + if e := http2.ConfigureTransport(tr); e != nil { + return nil, HTTP2_CONFIGURE.ErrorParent(e) + } + } + + return &http.Client{ + Transport: tr, + Timeout: GlobalTimeout, + }, nil +} diff --git a/httpcli/error.go b/httpcli/error.go new file mode 100644 index 0000000..52a5180 --- /dev/null +++ b/httpcli/error.go @@ -0,0 +1,67 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package httpcli + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Httpcli + URL_PARSE + HTTP_CLIENT + HTTP_REQUEST + HTTP_DO + IO_READ + BUFFER_WRITE + HTTP2_CONFIGURE +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case URL_PARSE: + return "uri/url parse error" + case HTTP_CLIENT: + return "error on creating a new http/http2 client" + case HTTP_REQUEST: + return "error on creating a new http/http2 request" + case HTTP_DO: + return "error on sending a http/http2 request" + case IO_READ: + return "error on reading i/o stream" + case BUFFER_WRITE: + return "error on writing bytes on buffer" + case HTTP2_CONFIGURE: + return "error while configure http2 transport for client" + } + + return "" +} diff --git a/njs-httpcli/http.go b/httpcli/http.go similarity index 50% rename from njs-httpcli/http.go rename to httpcli/http.go index a1a9c2f..497899d 100644 --- a/njs-httpcli/http.go +++ b/httpcli/http.go @@ -23,21 +23,17 @@ * */ -package njs_httpcli +package httpcli import ( "bytes" - "fmt" "io/ioutil" - "net" "net/http" "net/url" "strings" - "time" - njs_certif "github.com/nabbar/golib/njs-certif" - - njs_logger "github.com/nabbar/golib/njs-logger" + . "github.com/nabbar/golib/errors" + . "github.com/nabbar/golib/logger" ) type httpClient struct { @@ -46,11 +42,11 @@ type httpClient struct { } type HTTP interface { - Check() bool - Call(file *bytes.Buffer) (bool, *bytes.Buffer) + Check() Error + Call(file *bytes.Buffer) (bool, *bytes.Buffer, Error) } -func NewClient(uri string) HTTP { +func NewClient(uri string) (HTTP, Error) { var ( pUri *url.URL err error @@ -59,85 +55,100 @@ func NewClient(uri string) HTTP { if uri != "" { pUri, err = url.Parse(uri) - njs_logger.PanicLevel.LogErrorCtx(njs_logger.NilLevel, fmt.Sprintf("parsing url '%s'", uri), err) + + if err != nil { + return nil, URL_PARSE.ErrorParent(err) + } + host = pUri.Host } else { pUri = nil host = "" } + c, e := GetClientError(host) + + if e != nil { + return nil, HTTP_CLIENT.Error(e) + } + return &httpClient{ url: pUri, - cli: GetClient(host), + cli: c, + }, nil +} + +func (obj *httpClient) Check() Error { + req, e := obj.newRequest(http.MethodHead, nil) + + if e != nil { + return e } + + _, e = obj.doRequest(req) + + return e } -func GetClient(serverName string) *http.Client { - return &http.Client{ - Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 10 * time.Second, - KeepAlive: 30 * time.Second, - DualStack: true, - }).DialContext, - MaxIdleConns: 100, - IdleConnTimeout: 30 * time.Second, - TLSHandshakeTimeout: 5 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - DisableCompression: true, - TLSClientConfig: njs_certif.GetTLSConfig(serverName), - }, +func (obj *httpClient) Call(body *bytes.Buffer) (bool, *bytes.Buffer, Error) { + req, e := obj.newRequest(http.MethodPost, body) + + if e != nil { + return false, nil, e } + + res, e := obj.doRequest(req) + + if e != nil { + return false, nil, e + } + + return obj.checkResponse(res) } -func (obj *httpClient) Check() bool { - obj.doRequest(obj.newRequest(http.MethodHead, nil)) - return true -} - -func (obj *httpClient) Call(body *bytes.Buffer) (bool, *bytes.Buffer) { - return obj.checkResponse( - obj.doRequest( - obj.newRequest(http.MethodPost, body), - ), - ) -} - -func (obj *httpClient) newRequest(method string, body *bytes.Buffer) *http.Request { +func (obj *httpClient) newRequest(method string, body *bytes.Buffer) (*http.Request, Error) { var reader *bytes.Reader if body != nil && body.Len() > 0 { reader = bytes.NewReader(body.Bytes()) } - req, err := http.NewRequest(method, obj.url.String(), reader) - njs_logger.PanicLevel.LogErrorCtx(njs_logger.NilLevel, fmt.Sprintf("creating '%s' request to '%s'", method, obj.url.Host), err) + req, e := http.NewRequest(method, obj.url.String(), reader) + if e != nil { + return req, HTTP_REQUEST.ErrorParent(e) + } - return req + return req, nil } -func (obj *httpClient) doRequest(req *http.Request) *http.Response { - res, err := obj.cli.Do(req) - njs_logger.PanicLevel.LogErrorCtx(njs_logger.NilLevel, fmt.Sprintf("running request '%s:%s'", req.Method, req.URL.Host), err) +func (obj *httpClient) doRequest(req *http.Request) (*http.Response, Error) { + res, e := obj.cli.Do(req) - return res + if e != nil { + return res, HTTP_DO.ErrorParent(e) + } + + return res, nil } -func (obj *httpClient) checkResponse(res *http.Response) (bool, *bytes.Buffer) { +func (obj *httpClient) checkResponse(res *http.Response) (bool, *bytes.Buffer, Error) { var buf *bytes.Buffer if res.Body != nil { bdy, err := ioutil.ReadAll(res.Body) - if err == nil { - _, err = buf.Write(bdy) + if err != nil { + return false, nil, IO_READ.ErrorParent(err) } - njs_logger.DebugLevel.LogError(err) + _, err = buf.Write(bdy) + + if err != nil { + return false, nil, BUFFER_WRITE.ErrorParent(err) + } + + DebugLevel.LogError(err) } - njs_logger.InfoLevel.Logf("Calling '%s:%s' result %s (Body : %d bytes)", res.Request.Method, res.Request.URL.Host, res.Status, buf.Len()) - - return strings.HasPrefix(res.Status, "2"), buf + return strings.HasPrefix(res.Status, "2"), buf, nil } diff --git a/njs-httpserver/README.md b/httpserver/README.md similarity index 100% rename from njs-httpserver/README.md rename to httpserver/README.md diff --git a/httpserver/error.go b/httpserver/error.go new file mode 100644 index 0000000..68813ae --- /dev/null +++ b/httpserver/error.go @@ -0,0 +1,46 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package httpserver + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Httpserver +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + } + + return "" +} diff --git a/njs-httpserver/http.go b/httpserver/http.go similarity index 77% rename from njs-httpserver/http.go rename to httpserver/http.go index bafe9fb..383acea 100644 --- a/njs-httpserver/http.go +++ b/httpserver/http.go @@ -23,7 +23,7 @@ * */ -package njs_httpserver +package httpserver import ( "context" @@ -40,8 +40,18 @@ import ( "syscall" "time" - njs_certif "github.com/nabbar/golib/njs-certif" - njs_logger "github.com/nabbar/golib/njs-logger" + "golang.org/x/net/http2" + + njs_certif "github.com/nabbar/golib/certificates" + + . "github.com/nabbar/golib/logger" +) + +const ( + TIMEOUT_30_SEC = 30 * time.Second + TIMEOUT_10_SEC = 10 * time.Second + TIMEOUT_5_SEC = 5 * time.Second + TIMEOUT_1_SEC = 1 * time.Second ) type modelServer struct { @@ -169,22 +179,36 @@ func (srv *modelServer) Listen() { srv.srv = &http.Server{ Addr: srv.GetBindable(), - ErrorLog: njs_logger.GetLogger(njs_logger.ErrorLevel, log.LstdFlags | log.LstdFlags | log.Lmicroseconds, "server '%s'", srv.GetBindable()), + ErrorLog: GetLogger(ErrorLevel, log.LstdFlags|log.Lmicroseconds, "[http/http2 server '%s']", srv.GetBindable()), Handler: srv.hdl, TLSConfig: srv.ssl, } - njs_logger.InfoLevel.Logf("Server starting with bindable: %s", srv.GetBindable()) + cnf := &http2.Server{ + //MaxHandlers: 0, + //MaxConcurrentStreams: 0, + //MaxReadFrameSize: 0, + //PermitProhibitedCipherSuites: false, + IdleTimeout: TIMEOUT_30_SEC, + //MaxUploadBufferPerConnection: 0, + //MaxUploadBufferPerStream: 0, + //NewWriteScheduler: nil, + } + + err := http2.ConfigureServer(srv.srv, cnf) + FatalLevel.Logf("Configuring Server '%s' Error: %v", srv.host, err) go func() { if srv.ssl == nil || !njs_certif.CheckCertificates() { + InfoLevel.Logf("Server '%s' is starting with bindable: %s", srv.host, srv.GetBindable()) if err := srv.srv.ListenAndServe(); err != nil { - njs_logger.FatalLevel.Logf("Listen Error: %v", err) + FatalLevel.Logf("Listen Server '%s' Error: %v", srv.host, err) return } } else { + InfoLevel.Logf("TLS Server '%s' is starting with bindable: %s", srv.host, srv.GetBindable()) if err := srv.srv.ListenAndServeTLS("", ""); err != nil { - njs_logger.FatalLevel.Logf("Listen config Error: %v", err) + FatalLevel.Logf("Listen TLS Server '%s' Error: %v", srv.host, err) return } } @@ -213,7 +237,7 @@ func (srv *modelServer) Restart() { } func (srv *modelServer) Shutdown() { - njs_logger.InfoLevel.Logf("Shutdown Server ...") + InfoLevel.Logf("Shutdown Server '%s'...", srv.addr.Host) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() @@ -223,7 +247,7 @@ func (srv *modelServer) Shutdown() { } if err := srv.srv.Shutdown(ctx); err != nil { - njs_logger.FatalLevel.Logf("Server Shutdown Error: %v", err) + FatalLevel.Logf("Shutdown Server '%s' Error: %v", srv.host, err) } srv.srv = nil diff --git a/ioutils/error.go b/ioutils/error.go new file mode 100644 index 0000000..19f0741 --- /dev/null +++ b/ioutils/error.go @@ -0,0 +1,61 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package ioutils + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_IOUtils + SYSCALL_RLIMIT_GET + SYSCALL_RLIMIT_SET + IO_TEMP_FILE_NEW + IO_TEMP_FILE_CLOSE + IO_TEMP_FILE_REMOVE +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case SYSCALL_RLIMIT_GET: + return "error on retrieve value in syscall rlimit" + case SYSCALL_RLIMIT_SET: + return "error on changing value in syscall rlimit" + case IO_TEMP_FILE_NEW: + return "error occur while trying to create new temporary file" + case IO_TEMP_FILE_CLOSE: + return "closing temporary file occurs error" + case IO_TEMP_FILE_REMOVE: + return "error occurs on removing temporary file" + } + + return "" +} diff --git a/njs-ioutils/fileDescriptor.go b/ioutils/fileDescriptor.go similarity index 97% rename from njs-ioutils/fileDescriptor.go rename to ioutils/fileDescriptor.go index 3fd44fc..ec341c7 100644 --- a/njs-ioutils/fileDescriptor.go +++ b/ioutils/fileDescriptor.go @@ -23,7 +23,9 @@ * */ -package njs_ioutils +package ioutils + +import . "github.com/nabbar/golib/errors" /** * SystemFileDescriptor is returning current Limit & max system limit for file descriptor (open file or I/O resource) currently set in the system @@ -49,6 +51,6 @@ package njs_ioutils * Normally no problem will be result in the build * */ -func SystemFileDescriptor(newValue int) (current int, max int, err error) { +func SystemFileDescriptor(newValue int) (current int, max int, err Error) { return systemFileDescriptor(newValue) } diff --git a/njs-ioutils/fileDescriptor_ko.go b/ioutils/fileDescriptor_ko.go similarity index 93% rename from njs-ioutils/fileDescriptor_ko.go rename to ioutils/fileDescriptor_ko.go index b4f1f1a..fc22596 100644 --- a/njs-ioutils/fileDescriptor_ko.go +++ b/ioutils/fileDescriptor_ko.go @@ -25,13 +25,14 @@ * */ -package njs_ioutils +package ioutils import ( - "github.com/nabbar/golib/njs-ioutils/maxstdio" + . "github.com/nabbar/golib/errors" + "github.com/nabbar/golib/ioutils/maxstdio" ) -func systemFileDescriptor(newValue int) (current int, max int, err error) { +func systemFileDescriptor(newValue int) (current int, max int, err Error) { rLimit := maxstdio.GetMaxStdio() if rLimit < 0 { diff --git a/njs-ioutils/fileDescriptor_ok.go b/ioutils/fileDescriptor_ok.go similarity index 82% rename from njs-ioutils/fileDescriptor_ok.go rename to ioutils/fileDescriptor_ok.go index 91fa419..ab53202 100644 --- a/njs-ioutils/fileDescriptor_ok.go +++ b/ioutils/fileDescriptor_ok.go @@ -25,14 +25,22 @@ * */ -package njs_ioutils +package ioutils -import "syscall" +import ( + "syscall" -func systemFileDescriptor(newValue int) (current int, max int, err error) { - var rLimit syscall.Rlimit + . "github.com/nabbar/golib/errors" +) - if err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil { +func systemFileDescriptor(newValue int) (current int, max int, err Error) { + var ( + rLimit syscall.Rlimit + e error + ) + + if e = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); e != nil { + err = SYSCALL_RLIMIT_GET.ErrorParent(e) return } @@ -56,7 +64,8 @@ func systemFileDescriptor(newValue int) (current int, max int, err error) { } if chg { - if err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil { + if e = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); e != nil { + err = SYSCALL_RLIMIT_SET.ErrorParent(e) return } diff --git a/njs-ioutils/iowrapper.go b/ioutils/iowrapper.go similarity index 99% rename from njs-ioutils/iowrapper.go rename to ioutils/iowrapper.go index 64c7d42..170cd47 100644 --- a/njs-ioutils/iowrapper.go +++ b/ioutils/iowrapper.go @@ -23,7 +23,7 @@ * */ -package njs_ioutils +package ioutils import "io" diff --git a/njs-ioutils/maxstdio/maxstdio.c b/ioutils/maxstdio/maxstdio.c similarity index 100% rename from njs-ioutils/maxstdio/maxstdio.c rename to ioutils/maxstdio/maxstdio.c diff --git a/njs-ioutils/maxstdio/maxstdio.go b/ioutils/maxstdio/maxstdio.go similarity index 100% rename from njs-ioutils/maxstdio/maxstdio.go rename to ioutils/maxstdio/maxstdio.go diff --git a/njs-ioutils/maxstdio/maxstdio.h b/ioutils/maxstdio/maxstdio.h similarity index 100% rename from njs-ioutils/maxstdio/maxstdio.h rename to ioutils/maxstdio/maxstdio.h diff --git a/njs-ioutils/maxstdio/maxstdio.o b/ioutils/maxstdio/maxstdio.o similarity index 100% rename from njs-ioutils/maxstdio/maxstdio.o rename to ioutils/maxstdio/maxstdio.o diff --git a/njs-ioutils/tempFile.go b/ioutils/tempFile.go similarity index 79% rename from njs-ioutils/tempFile.go rename to ioutils/tempFile.go index 934fa89..7bd7b65 100644 --- a/njs-ioutils/tempFile.go +++ b/ioutils/tempFile.go @@ -23,21 +23,19 @@ * */ -package njs_ioutils +package ioutils import ( - "fmt" "io/ioutil" "os" "path" + + . "github.com/nabbar/golib/errors" ) -func NewTempFile() (*os.File, error) { - if f, e := ioutil.TempFile(os.TempDir(), ""); e != nil { - return nil, e - } else { - return f, nil - } +func NewTempFile() (*os.File, Error) { + f, e := ioutil.TempFile(os.TempDir(), "") + return f, IO_TEMP_FILE_NEW.Iferror(e) } func GetTempFilePath(f *os.File) string { @@ -48,24 +46,18 @@ func GetTempFilePath(f *os.File) string { return path.Join(os.TempDir(), path.Base(f.Name())) } -func DelTempFile(f *os.File, ignoreErrClose bool) error { +func DelTempFile(f *os.File) Error { if f == nil { return nil } n := GetTempFilePath(f) + a := f.Close() + e1 := IO_TEMP_FILE_CLOSE.Iferror(a) + b := os.Remove(n) + e2 := IO_TEMP_FILE_REMOVE.Iferror(b) - if ignoreErrClose { - return b - } - - if a != nil && b != nil { - return fmt.Errorf("%v, %v", a, b) - } else if a != nil { - return a - } - - return b + return MakeErrorIfError(e2, e1) } diff --git a/njs-ldap/README.md b/ldap/README.md similarity index 100% rename from njs-ldap/README.md rename to ldap/README.md diff --git a/ldap/error.go b/ldap/error.go new file mode 100644 index 0000000..97622a9 --- /dev/null +++ b/ldap/error.go @@ -0,0 +1,70 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package ldap + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_LDAP + LDAP_SERVER_CONFIG + LDAP_SERVER_DIAL + LDAP_SERVER_TLS + LDAP_SERVER_STARTTLS + LDAP_BIND + LDAP_SEARCH + LDAP_USER_NOT_UNIQ + LDAP_USER_NOT_FOUND +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case LDAP_SERVER_CONFIG: + return "LDAP server config is not well defined" + case LDAP_SERVER_DIAL: + return "dialing server occurs error " + case LDAP_SERVER_TLS: + return "cannot start dial to server with TLS Mode" + case LDAP_SERVER_STARTTLS: + return "cannot init starttls mode on opening server connection" + case LDAP_BIND: + return "error on binding user/pass" + case LDAP_SEARCH: + return "error on calling search on connected server" + case LDAP_USER_NOT_UNIQ: + return "user uid is not uniq" + case LDAP_USER_NOT_FOUND: + return "user uid is not found" + } + + return "" +} diff --git a/njs-ldap/ldap.go b/ldap/ldap.go similarity index 63% rename from njs-ldap/ldap.go rename to ldap/ldap.go index 3fa2d62..dbcb832 100644 --- a/njs-ldap/ldap.go +++ b/ldap/ldap.go @@ -23,17 +23,18 @@ * */ -package njs_ldap +package ldap import ( "crypto/tls" "fmt" "strings" - "github.com/pkg/errors" - "github.com/nabbar/golib/njs-certif" - "github.com/nabbar/golib/njs-logger" - "gopkg.in/ldap.v3" + "github.com/go-ldap/ldap/v3" + + njs_certif "github.com/nabbar/golib/certificates" + . "github.com/nabbar/golib/errors" + . "github.com/nabbar/golib/logger" ) //HelperLDAP struct use to manage connection to server and request it @@ -48,9 +49,9 @@ type HelperLDAP struct { } //NewLDAP build a new LDAP helper based on config struct given -func NewLDAP(cnf *Config, attributes []string) *HelperLDAP { +func NewLDAP(cnf *Config, attributes []string) (*HelperLDAP, Error) { if cnf == nil { - panic("given config is a nil struct") + return nil, EMPTY_PARAMS.Error(nil) } return &HelperLDAP{ @@ -58,7 +59,7 @@ func NewLDAP(cnf *Config, attributes []string) *HelperLDAP { tlsConfig: njs_certif.GetTLSConfig(cnf.Uri), tlsMode: tlsmode_init, config: cnf.Clone(), - } + }, nil } //SetCredentials used to defined the BindDN and password for connection @@ -79,45 +80,45 @@ func (lc *HelperLDAP) ForceTLSMode(tlsMode TLSMode, tlsConfig *tls.Config) { } } -func (lc *HelperLDAP) tryConnect() (TLSMode, error) { +func (lc *HelperLDAP) tryConnect() (TLSMode, Error) { var ( l *ldap.Conn err error ) - defer func(l *ldap.Conn) { + defer func() { if l != nil { l.Close() } - }(l) + }() if lc.config.Portldaps != 0 { l, err = ldap.DialTLS("tcp", lc.config.ServerAddr(true), lc.tlsConfig) if err == nil { - njs_logger.DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String()) + DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String()) return TLSMODE_TLS, nil } } if lc.config.PortLdap == 0 { - return 0, fmt.Errorf("ldap server not well defined") + return tlsmode_init, LDAP_SERVER_CONFIG.Error(nil) } l, err = ldap.Dial("tcp", lc.config.ServerAddr(false)) if err != nil { - return 0, err + return 0, LDAP_SERVER_DIAL.ErrorParent(err) } - if e := l.StartTLS(lc.tlsConfig); e == nil { - njs_logger.DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String()) + if err = l.StartTLS(lc.tlsConfig); err == nil { + DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String()) return TLSMODE_STARTTLS, nil } - njs_logger.DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String()) + DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String()) return TLSMODE_NONE, nil } -func (lc *HelperLDAP) connect() error { +func (lc *HelperLDAP) connect() Error { if lc.conn == nil { var ( l *ldap.Conn @@ -137,25 +138,25 @@ func (lc *HelperLDAP) connect() error { if lc.tlsMode == TLSMODE_TLS { l, err = ldap.DialTLS("tcp", lc.config.ServerAddr(true), lc.tlsConfig) if err != nil { - return fmt.Errorf("ldap connection error with tls mode '%s': %v", lc.tlsMode.String(), err) + return LDAP_SERVER_TLS.ErrorParent(err) } } if lc.tlsMode == TLSMODE_NONE || lc.tlsMode == TLSMODE_STARTTLS { l, err = ldap.Dial("tcp", lc.config.ServerAddr(false)) if err != nil { - return fmt.Errorf("ldap connection error with tls mode '%s': %v", lc.tlsMode.String(), err) + return LDAP_SERVER_DIAL.ErrorParent(err) } } if lc.tlsMode == TLSMODE_STARTTLS { err = l.StartTLS(lc.tlsConfig) if err != nil { - return fmt.Errorf("ldap connection error with tls mode '%s': %v", lc.tlsMode.String(), err) + return LDAP_SERVER_STARTTLS.ErrorParent(err) } } - njs_logger.DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String()) + DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String()) lc.conn = l } @@ -163,7 +164,7 @@ func (lc *HelperLDAP) connect() error { } //Check used to check if connection success (without any bind) -func (lc *HelperLDAP) Check() error { +func (lc *HelperLDAP) Check() Error { if err := lc.connect(); err != nil { return err } @@ -181,37 +182,39 @@ func (lc *HelperLDAP) Close() { } //AuthUser used to test bind given user uid and password -func (lc *HelperLDAP) AuthUser(username, password string) error { +func (lc *HelperLDAP) AuthUser(username, password string) Error { if err := lc.connect(); err != nil { return err } if username == "" || password == "" { - return errors.New("Cannot bind with partial credentials, bindDN or bind password is empty string") + return EMPTY_PARAMS.Error(nil) } - return lc.conn.Bind(username, password) + err := lc.conn.Bind(username, password) + + return LDAP_BIND.Iferror(err) } //Connect used to connect and bind to server -func (lc *HelperLDAP) Connect() error { +func (lc *HelperLDAP) Connect() Error { if err := lc.AuthUser(lc.bindDN, lc.bindPass); err != nil { - return fmt.Errorf("error while trying to bind on LDAP server %s with tls mode '%s': %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), err) + return err } - njs_logger.DebugLevel.Logf("Bind success on LDAP server %s with tls mode '%s'", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String()) + DebugLevel.Logf("Bind success on LDAP server %s with tls mode '%s'", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String()) return nil } -func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.SearchResult, error) { +func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.SearchResult, Error) { var ( err error src *ldap.SearchResult ) - if err = lc.Connect(); err != nil { - return nil, err + if e := lc.Connect(); e != nil { + return nil, e } defer lc.Close() @@ -227,17 +230,17 @@ func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.Searc ) if src, err = lc.conn.Search(searchRequest); err != nil { - return nil, fmt.Errorf("error while looking for '%s' on ldap server %s with tls mode '%s': %v", filter, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), err) + return nil, LDAP_SEARCH.ErrorParent(err) } - njs_logger.DebugLevel.Logf("Search success on server '%s' with tls mode '%s', with filter [%s] and attribute %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), filter, attributes) + DebugLevel.Logf("Search success on server '%s' with tls mode '%s', with filter [%s] and attribute %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), filter, attributes) return src, nil } //UserInfo used to retrieve the information of a given username -func (lc *HelperLDAP) UserInfo(username string) (map[string]string, error) { +func (lc *HelperLDAP) UserInfo(username string) (map[string]string, Error) { var ( - err error + e Error src *ldap.SearchResult userRes map[string]string ) @@ -250,18 +253,18 @@ func (lc *HelperLDAP) UserInfo(username string) (map[string]string, error) { userRes = make(map[string]string) attributes := append(lc.Attributes, "cn") - if src, err = lc.runSearch(fmt.Sprintf(lc.config.FilterUser, username), attributes); err != nil { - return userRes, err + src, e = lc.runSearch(fmt.Sprintf(lc.config.FilterUser, username), attributes) + + if e != nil { + return userRes, e } if len(src.Entries) != 1 { if len(src.Entries) > 1 { - err = errors.New("Username not unique") + return userRes, LDAP_USER_NOT_UNIQ.Error(nil) } else { - err = errors.New("Username not found") + return userRes, LDAP_USER_NOT_FOUND.Error(nil) } - - return userRes, fmt.Errorf("error while looking for username '%s' on ldap server '%s' with tls mode '%s': %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), err) } for _, attr := range attributes { @@ -272,14 +275,14 @@ func (lc *HelperLDAP) UserInfo(username string) (map[string]string, error) { userRes["DN"] = src.Entries[0].DN } - njs_logger.DebugLevel.Logf("Map info retrieve in ldap server '%s' with tls mode '%s' about user [%s] : %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), username, userRes) + DebugLevel.Logf("Map info retrieve in ldap server '%s' with tls mode '%s' about user [%s] : %v", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), username, userRes) return userRes, nil } //UserMemberOf returns the group list of a given user. -func (lc *HelperLDAP) UserMemberOf(username string) ([]string, error) { +func (lc *HelperLDAP) UserMemberOf(username string) ([]string, Error) { var ( - err error + err Error src *ldap.SearchResult grp []string ) @@ -291,26 +294,27 @@ func (lc *HelperLDAP) UserMemberOf(username string) ([]string, error) { grp = make([]string, 0) - if src, err = lc.runSearch(fmt.Sprintf(lc.config.FilterUser, username), []string{"memberOf"}); err != nil { + src, err = lc.runSearch(fmt.Sprintf(lc.config.FilterUser, username), []string{"memberOf"}) + if err != nil { return grp, err } for _, entry := range src.Entries { for _, mmb := range entry.GetAttributeValues("memberOf") { - njs_logger.DebugLevel.Logf("Group find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), mmb) + DebugLevel.Logf("Group find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), mmb) mmo := lc.ParseEntries(mmb) grp = append(grp, mmo["cn"]...) } } - njs_logger.DebugLevel.Logf("Groups find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp) + DebugLevel.Logf("Groups find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp) return grp, nil } //UserIsInGroup used to check if a given username is a group member of a list of reference group name -func (lc *HelperLDAP) UserIsInGroup(username string, groupname []string) (bool, error) { +func (lc *HelperLDAP) UserIsInGroup(username string, groupname []string) (bool, Error) { var ( - err error + err Error grpMmbr []string ) @@ -319,13 +323,14 @@ func (lc *HelperLDAP) UserIsInGroup(username string, groupname []string) (bool, username = usr["uid"][0] } - if grpMmbr, err = lc.UserMemberOf(username); err != nil { + grpMmbr, err = lc.UserMemberOf(username) + if err != nil { return false, err } for _, grpSrch := range groupname { for _, grpItem := range grpMmbr { - if strings.ToUpper(grpSrch) == strings.ToUpper(grpItem) { + if strings.EqualFold(grpSrch, grpItem) { return true, nil } } @@ -335,16 +340,17 @@ func (lc *HelperLDAP) UserIsInGroup(username string, groupname []string) (bool, } //UsersOfGroup used to retrieve the member list of a given group name -func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, error) { +func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, Error) { var ( - err error + err Error src *ldap.SearchResult grp []string ) grp = make([]string, 0) - if src, err = lc.runSearch(fmt.Sprintf(lc.config.FilterGroup, groupname), []string{"member"}); err != nil { + src, err = lc.runSearch(fmt.Sprintf(lc.config.FilterGroup, groupname), []string{"member"}) + if err != nil { return grp, err } @@ -355,7 +361,7 @@ func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, error) { } } - njs_logger.DebugLevel.Logf("Member of groups [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp) + DebugLevel.Logf("Member of groups [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grp) return grp, nil } diff --git a/njs-ldap/model.go b/ldap/model.go similarity index 99% rename from njs-ldap/model.go rename to ldap/model.go index 87b250e..e0f2fdc 100644 --- a/njs-ldap/model.go +++ b/ldap/model.go @@ -23,7 +23,7 @@ * */ -package njs_ldap +package ldap import ( "fmt" diff --git a/njs-logger/README.md b/logger/README.md similarity index 100% rename from njs-logger/README.md rename to logger/README.md diff --git a/njs-logger/formatter.go b/logger/formatter.go similarity index 99% rename from njs-logger/formatter.go rename to logger/formatter.go index 93f2d69..fcb3aa0 100644 --- a/njs-logger/formatter.go +++ b/logger/formatter.go @@ -22,12 +22,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_logger +package logger import ( - "github.com/sirupsen/logrus" "io" "strings" + + "github.com/sirupsen/logrus" ) // Format a uint8 type customized with function to manage the result logger format diff --git a/njs-logger/iowriter.go b/logger/iowriter.go similarity index 99% rename from njs-logger/iowriter.go rename to logger/iowriter.go index 9f04792..43b3d96 100644 --- a/njs-logger/iowriter.go +++ b/logger/iowriter.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_logger +package logger import ( "fmt" diff --git a/njs-logger/level.go b/logger/level.go similarity index 99% rename from njs-logger/level.go rename to logger/level.go index bd81657..4f09b6b 100644 --- a/njs-logger/level.go +++ b/logger/level.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_logger +package logger import ( "encoding/json" @@ -341,7 +341,7 @@ func (level Level) logDetails(message string, data interface{}, err error, field return } - var tags = make(map[string]interface{}, 0) + var tags = make(map[string]interface{}) if enableGID { tags[tagStack] = getGID() diff --git a/njs-logger/logger.go b/logger/logger.go similarity index 98% rename from njs-logger/logger.go rename to logger/logger.go index 4233718..9388fbc 100644 --- a/njs-logger/logger.go +++ b/logger/logger.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_logger +package logger import ( "log" @@ -38,9 +38,9 @@ import ( ) const ( - tagStack = "stack" - tagTime = "time" - tagLevel = "level" + tagStack = "stack" + tagTime = "time" + //tagLevel = "level" //unused tagCaller = "func" tagFile = "file" tagLine = "line" diff --git a/njs-errors/code.go b/njs-errors/code.go deleted file mode 100644 index b138392..0000000 --- a/njs-errors/code.go +++ /dev/null @@ -1,102 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Nicolas JUHEL - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -package njs_errors - -import ( - "fmt" - "path" - "runtime" - "strings" -) - -type ErrorCode interface { - Error() error - ErrorFull() error - - String() string - StringFull() string - - Code() string - Trace() runtime.Frame -} - -type errorCode struct { - code string - err ErrorType - ori error - trace runtime.Frame -} - -// Error return an error type of the current error code, with no code in reference -func (e errorCode) Error() error { - return e.err.Error(e.ori) -} - -// String return a string of the current error code, with no code in reference -func (e errorCode) String() string { - return e.err.String() -} - -// Code return a string of the current code, with no error in reference -func (e errorCode) Code() string { - return e.code -} - -// Trace return a runtime frame of the current error -func (e errorCode) Trace() runtime.Frame { - return e.trace -} - -// StringFull return a error type of the current code, with error and origin in reference -func (e errorCode) StringFull() string { - return e.ErrorFull().Error() -} - -// ErrorFull return a error type of the current code, with error and origin in reference -func (e errorCode) ErrorFull() error { - - if e.trace != getNilFrame() { - var t = make([]string, 0) - - if e.trace.File != "" { - t = append(t, path.Base(e.trace.File)) - } - - if e.trace.Function != "" { - t = append(t, e.trace.Function) - } - - if e.trace.Line > 0 { - t = append(t, fmt.Sprintf("%v", e.trace.Line)) - } - - if len(t) > 0 { - return fmt.Errorf("(%s) [%s] %v", e.code, strings.Join(t, "|"), e.Error()) - } - } - - return fmt.Errorf("(%s) %v", e.code, e.Error()) -} diff --git a/njs-errors/list.go b/njs-errors/list.go deleted file mode 100644 index 2d6cf93..0000000 --- a/njs-errors/list.go +++ /dev/null @@ -1,134 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 Nicolas JUHEL - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -package njs_errors - -import ( - "path" - "reflect" - "runtime" - "strings" -) - -var ( - currPkgs = path.Base(reflect.TypeOf(ERR_UNKNOWN).PkgPath()) - _listCodeErrors = make(map[string]ErrorType, 0) -) - -// SetErrorCode Register a new error with code and an error string as ErrorType -func SetErrorCode(code string, err ErrorType) { - if _listCodeErrors == nil || len(_listCodeErrors) < 1 { - _listCodeErrors = make(map[string]ErrorType, 0) - } - - _listCodeErrors[code] = err -} - -// SetErrorCodeString Register a new error with code and an error string as string -func SetErrorCodeString(code, err string) { - SetErrorCode(code, ErrorType(err)) -} - -// DelErrorCode Remove an error with code from the register list -func DelErrorCode(code string) { - var _lst = _listCodeErrors - - DelAllErrorCode() - - for k, v := range _lst { - if k != code { - _listCodeErrors[k] = v - } - } -} - -// DelAllErrorCode Clean the complete list of couple code - error -func DelAllErrorCode() { - _listCodeErrors = make(map[string]ErrorType, 0) -} - -// GetErrorCode return an ErrorCode interface mapped to code given in parameters. -// If the code is not found an 'ERR_UNKNOWN' will be used instead of the awaiting error -// If an origin error is given in params, this origin error will be used in the reference of generated error or string -func GetErrorCode(code string, origin error) ErrorCode { - return getErrorCode(code, origin, getNilFrame()) -} - -// GetTraceErrorCode return an ErrorCode interface mapped to given params code. -// If the code is not found an 'ERR_UNKNOWN' will be used instead of the awaiting error -// If an origin error is given in params, this origin error will be used in the reference of generated error or string -// This function add a trace of error generated -func GetTraceErrorCode(code string, origin error) ErrorCode { - return getErrorCode(code, origin, getFrame()) -} - -func getErrorCode(code string, origin error, trace runtime.Frame) ErrorCode { - var ( - e ErrorType - ok bool - ) - - if e, ok = _listCodeErrors[code]; !ok { - e = ERR_UNKNOWN - } - - return &errorCode{ - code: code, - err: e, - ori: origin, - trace: trace, - } -} - -func getFrame() runtime.Frame { - // Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need - programCounters := make([]uintptr, 0) - n := runtime.Callers(0, programCounters) - - if n > 0 { - frames := runtime.CallersFrames(programCounters[:n]) - more := true - - for more { - var ( - frame runtime.Frame - ) - - frame, more = frames.Next() - - if strings.Contains(frame.Function, currPkgs) { - continue - } - - return frame - } - } - - return getNilFrame() -} - -func getNilFrame() runtime.Frame { - return runtime.Frame{Function: "", File: "", Line: 0} -} diff --git a/njs-smtp/tools.go b/njs-smtp/tools.go deleted file mode 100644 index e3426b5..0000000 --- a/njs-smtp/tools.go +++ /dev/null @@ -1,71 +0,0 @@ -/* -MIT License - -Copyright (c) 2019 Nicolas JUHEL - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package njs_smtp - -import "strings" - -func cleanMergeSlice(str []string, args ...string) []string { - for _, s := range args { - if s != "" { - str = append(str, s) - } - } - - return str -} - -func unicSliceString(str []string) []string { - var new = make([]string, 0) - - for _, s := range str { - if !existSliceString(new, s) { - new = append(new, s) - } - } - - return new -} - -func existSliceString(slc []string, str string) bool { - for _, s := range slc { - if s == str { - return true - } - } - - return false -} - -func cleanJoin(str []string, glue string) string { - var new = make([]string, 0) - - for _, s := range str { - if s != "" { - new = append(new, s) - } - } - - return strings.Join(new, glue) -} diff --git a/njs-password/README.md b/password/README.md similarity index 100% rename from njs-password/README.md rename to password/README.md diff --git a/njs-password/password.go b/password/password.go similarity index 99% rename from njs-password/password.go rename to password/password.go index d830f49..4be50a8 100644 --- a/njs-password/password.go +++ b/password/password.go @@ -23,7 +23,7 @@ * */ -package njs_password +package password import ( "math/rand" diff --git a/njs-progress/bar.go b/progress/bar.go similarity index 89% rename from njs-progress/bar.go rename to progress/bar.go index 68f435a..c897913 100644 --- a/njs-progress/bar.go +++ b/progress/bar.go @@ -23,20 +23,23 @@ * */ -package njs_progress +package progress import ( "context" - njs_semaphore "github.com/nabbar/golib/njs-semaphore" "github.com/vbauerster/mpb/v5" + + . "github.com/nabbar/golib/errors" + + sem "github.com/nabbar/golib/semaphore" ) type bar struct { u bool t int64 b *mpb.Bar - s njs_semaphore.Sem + s sem.Sem } type Bar interface { @@ -45,19 +48,19 @@ type Bar interface { Increment(n int) Refill(amount int64) - NewWorker() error + NewWorker() Error NewWorkerTry() bool DeferWorker() DeferMain(dropBar bool) - WaitAll() error + WaitAll() Error Context() context.Context Cancel() GetBarMPB() *mpb.Bar } -func newBar(b *mpb.Bar, s njs_semaphore.Sem, total int64) Bar { +func newBar(b *mpb.Bar, s sem.Sem, total int64) Bar { return &bar{ u: total > 0, t: total, @@ -89,7 +92,7 @@ func (b *bar) Refill(amount int64) { b.b.SetRefill(amount) } -func (b *bar) NewWorker() error { +func (b *bar) NewWorker() Error { if !b.u { b.t++ b.b.SetTotal(b.t, false) @@ -112,7 +115,7 @@ func (b *bar) DeferMain(dropBar bool) { b.s.DeferMain() } -func (b *bar) WaitAll() error { +func (b *bar) WaitAll() Error { return b.s.WaitAll() } diff --git a/njs-progress/progress.go b/progress/progress.go similarity index 98% rename from njs-progress/progress.go rename to progress/progress.go index 2d86c60..369c599 100644 --- a/njs-progress/progress.go +++ b/progress/progress.go @@ -23,7 +23,7 @@ * */ -package njs_progress +package progress import ( "context" @@ -31,7 +31,7 @@ import ( "github.com/vbauerster/mpb/v5/decor" - njs_semaphore "github.com/nabbar/golib/njs-semaphore" + njs_semaphore "github.com/nabbar/golib/semaphore" "github.com/vbauerster/mpb/v5" ) diff --git a/njs-router/README.md b/router/README.md similarity index 100% rename from njs-router/README.md rename to router/README.md diff --git a/njs-router/auth.go b/router/auth.go similarity index 84% rename from njs-router/auth.go rename to router/auth.go index c81e9d9..7ecaf49 100644 --- a/njs-router/auth.go +++ b/router/auth.go @@ -23,15 +23,16 @@ * */ -package njs_router +package router import ( - "fmt" "net/http" "strings" "github.com/gin-gonic/gin" - njs_logger "github.com/nabbar/golib/njs-logger" + + . "github.com/nabbar/golib/errors" + . "github.com/nabbar/golib/logger" ) type AuthCode uint8 @@ -71,7 +72,7 @@ func AuthForbidden(c *gin.Context, err error) { } type authorization struct { - check func(AuthHeader string) (AuthCode, error) + check func(AuthHeader string) (AuthCode, Error) router []gin.HandlerFunc authType string } @@ -82,7 +83,7 @@ type Authorization interface { Append(router ...gin.HandlerFunc) } -func NewAuthorization(HeadAuthType string, authCheckFunc func(AuthHeader string) (AuthCode, error)) Authorization { +func NewAuthorization(HeadAuthType string, authCheckFunc func(AuthHeader string) (AuthCode, Error)) Authorization { return &authorization{ check: authCheckFunc, authType: HeadAuthType, @@ -104,7 +105,7 @@ func (a authorization) Handler(c *gin.Context) { auth := c.Request.Header.Get(HEAD_AUTH_SEND) if auth == "" { - AuthRequire(c, fmt.Errorf("header '%s' is missing", HEAD_AUTH_SEND)) + AuthRequire(c, HEADER_AUTH_MISSING.Error(nil).GetErrorFull("")) return } @@ -118,7 +119,7 @@ func (a authorization) Handler(c *gin.Context) { } if authValue == "" { - AuthRequire(c, fmt.Errorf("reading authorization error : auth string is empty")) + AuthRequire(c, HEADER_AUTH_EMPTY.Error(nil).GetErrorFull("")) return } else { code, err := a.check(authValue) @@ -126,17 +127,16 @@ func (a authorization) Handler(c *gin.Context) { switch code { case AUTH_CODE_SUCCESS: for _, r := range a.router { - njs_logger.DebugLevel.Logf("Calling router '%s=%s'", c.Request.Method, c.Request.URL.RawPath) + DebugLevel.Logf("Calling router '%s=%s'", c.Request.Method, c.Request.URL.RawPath) r(c) } case AUTH_CODE_REQUIRE: - AuthRequire(c, fmt.Errorf("authorization error : %v", err)) + AuthRequire(c, HEADER_AUTH_REQUIRE.Error(err).GetErrorFull("")) case AUTH_CODE_FORBIDDEN: - AuthForbidden(c, fmt.Errorf("authorization error : %v", err)) + AuthForbidden(c, HEADER_AUTH_FORBIDDEN.Error(err).GetErrorFull("")) default: - err := fmt.Errorf("auth response code is not valid") c.Errors = append(c.Errors, &gin.Error{ - Err: err, + Err: HEADER_AUTH_ERROR.Error(err).GetErrorFull(""), Type: gin.ErrorTypePrivate, }) c.AbortWithStatus(http.StatusInternalServerError) diff --git a/router/error.go b/router/error.go new file mode 100644 index 0000000..d90028c --- /dev/null +++ b/router/error.go @@ -0,0 +1,61 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package router + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Router + HEADER_AUTH_MISSING + HEADER_AUTH_EMPTY + HEADER_AUTH_REQUIRE + HEADER_AUTH_FORBIDDEN + HEADER_AUTH_ERROR +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case HEADER_AUTH_MISSING: + return "missing authorization header" + case HEADER_AUTH_EMPTY: + return "authorization header is empty" + case HEADER_AUTH_REQUIRE: + return "authorization check failed, authorization still require" + case HEADER_AUTH_FORBIDDEN: + return "authorization check success but unauthorized client" + case HEADER_AUTH_ERROR: + return "authorization check return an invalid response code" + } + + return "" +} diff --git a/njs-router/headers.go b/router/headers.go similarity index 94% rename from njs-router/headers.go rename to router/headers.go index 4a144c5..81f67b3 100644 --- a/njs-router/headers.go +++ b/router/headers.go @@ -23,7 +23,7 @@ * */ -package njs_router +package router import ( "net/http" @@ -50,7 +50,7 @@ type Headers interface { func NewHeaders() Headers { return &headers{ - head: make(http.Header, 0), + head: make(http.Header), } } @@ -96,7 +96,7 @@ func (h headers) Handler(c *gin.Context) { // It appends to any existing values associated with key. func (h *headers) Add(key, value string) { if h.head == nil { - h.head = make(http.Header, 0) + h.head = make(http.Header) } h.head.Add(key, value) @@ -107,7 +107,7 @@ func (h *headers) Add(key, value string) { // values associated with key. func (h *headers) Set(key, value string) { if h.head == nil { - h.head = make(http.Header, 0) + h.head = make(http.Header) } h.head.Set(key, value) @@ -121,7 +121,7 @@ func (h *headers) Set(key, value string) { // access the map directly. func (h headers) Get(key string) string { if h.head == nil { - h.head = make(http.Header, 0) + h.head = make(http.Header) } return h.head.Get(key) @@ -130,7 +130,7 @@ func (h headers) Get(key string) string { // Del deletes the values associated with key. func (h *headers) Del(key string) { if h.head == nil { - h.head = make(http.Header, 0) + h.head = make(http.Header) } h.head.Del(key) diff --git a/njs-router/register.go b/router/register.go similarity index 98% rename from njs-router/register.go rename to router/register.go index 64c0766..df1d7b3 100644 --- a/njs-router/register.go +++ b/router/register.go @@ -23,7 +23,7 @@ * */ -package njs_router +package router import ( "github.com/gin-gonic/gin" @@ -68,7 +68,7 @@ func RoutersHandler(engine *gin.Engine) { func NewRouterList() RouterList { return &routerList{ - list: make(map[string][]routerItem, 0), + list: make(map[string][]routerItem), } } diff --git a/njs-router/router.go b/router/router.go similarity index 84% rename from njs-router/router.go rename to router/router.go index f5db4f4..883a3c5 100644 --- a/njs-router/router.go +++ b/router/router.go @@ -23,7 +23,7 @@ * */ -package njs_router +package router import ( "net/http" @@ -38,16 +38,6 @@ func init() { } } -//Compatibility -// @TODO: clean this func - -// deprecated -// SetGinHnadler func that return given func as ginTonic HandlerFunc interface type -// use SetGinHandler instead of SetGinHnadler -func SetGinHnadler(fct func(c *gin.Context)) gin.HandlerFunc { - return SetGinHandler(fct) -} - // SetGinHandler func that return given func as ginTonic HandlerFunc interface type func SetGinHandler(fct func(c *gin.Context)) gin.HandlerFunc { return fct diff --git a/njs-semaphore/context.go b/semaphore/context.go similarity index 98% rename from njs-semaphore/context.go rename to semaphore/context.go index 9640365..26e7946 100644 --- a/njs-semaphore/context.go +++ b/semaphore/context.go @@ -23,7 +23,7 @@ * */ -package njs_semaphore +package semaphore import ( "context" diff --git a/njs-errors/errors.go b/semaphore/error.go similarity index 66% rename from njs-errors/errors.go rename to semaphore/error.go index 5798888..29d6b8f 100644 --- a/njs-errors/errors.go +++ b/semaphore/error.go @@ -1,7 +1,7 @@ /* * MIT License * - * Copyright (c) 2019 Nicolas JUHEL + * Copyright (c) 2020 Nicolas JUHEL * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,27 +21,32 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * + * */ -package njs_errors +package semaphore -import "fmt" +import errors "github.com/nabbar/golib/errors" -type ErrorType string +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Semaphore + NEW_WORKER + WAITALL +) -const ERR_UNKNOWN ErrorType = "unknown error" - -// String return the string form of the current ErrorType -func (e ErrorType) String() string { - return string(e) +func init() { + errors.RegisterFctMessage(getMessage) } -// Error return an error type of the current ErrorType -// If an origin error is given (and not nil), this origin error will be append of the string (comma separated) -func (e ErrorType) Error(origin error) error { - if origin != nil { - return fmt.Errorf("%s, %v", e.String(), origin) +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case NEW_WORKER: + return "error on acquire one new semaphore worker" + case WAITALL: + return "error on acquire to wait all pending thread" } - return fmt.Errorf("%s", e.String()) + return "" } diff --git a/njs-semaphore/semaphore.go b/semaphore/semaphore.go similarity index 86% rename from njs-semaphore/semaphore.go rename to semaphore/semaphore.go index a2441bb..c476897 100644 --- a/njs-semaphore/semaphore.go +++ b/semaphore/semaphore.go @@ -23,7 +23,7 @@ * */ -package njs_semaphore +package semaphore import ( "context" @@ -31,6 +31,8 @@ import ( "time" "golang.org/x/sync/semaphore" + + . "github.com/nabbar/golib/errors" ) type sem struct { @@ -41,12 +43,12 @@ type sem struct { } type Sem interface { - NewWorker() error + NewWorker() Error NewWorkerTry() bool DeferWorker() DeferMain() - WaitAll() error + WaitAll() Error Context() context.Context Cancel() } @@ -70,20 +72,18 @@ func NewSemaphore(maxSimultaneous int, timeout time.Duration, deadline time.Time } } -func (s *sem) NewWorker() error { - if e := s.s.Acquire(s.x, 1); e != nil { - return e - } - - return nil +func (s *sem) NewWorker() Error { + e := s.s.Acquire(s.x, 1) + return NEW_WORKER.Iferror(e) } func (s *sem) NewWorkerTry() bool { return s.s.TryAcquire(1) } -func (s *sem) WaitAll() error { - return s.s.Acquire(s.Context(), s.m) +func (s *sem) WaitAll() Error { + e := s.s.Acquire(s.Context(), s.m) + return WAITALL.Iferror(e) } func (s *sem) DeferWorker() { @@ -102,6 +102,7 @@ func (s *sem) Cancel() { func (s *sem) Context() context.Context { if s.x == nil { + s.x, s.c = GetContext(0, GetEmptyTime(), nil) } return s.x diff --git a/njs-smtp/address.go b/smtp/address.go similarity index 99% rename from njs-smtp/address.go rename to smtp/address.go index a6ca4f8..e537846 100644 --- a/njs-smtp/address.go +++ b/smtp/address.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_smtp +package smtp import ( "net/mail" diff --git a/njs-smtp/attachment.go b/smtp/attachment.go similarity index 94% rename from njs-smtp/attachment.go rename to smtp/attachment.go index 774d75a..aa9958a 100644 --- a/njs-smtp/attachment.go +++ b/smtp/attachment.go @@ -22,13 +22,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_smtp +package smtp import ( "bytes" "io/ioutil" "net/http" "os" + + . "github.com/nabbar/golib/errors" ) type attachment struct { @@ -86,15 +88,15 @@ func NewAttachment(name string) Attachment { } } -func NewAttachmentFile(name string, filepath string) (Attachment, error) { +func NewAttachmentFile(name string, filepath string) (Attachment, Error) { var b = bytes.NewBuffer([]byte{}) if _, e := os.Stat(filepath); e != nil { - return nil, e + return nil, FILE_STAT.ErrorParent(e) } if bb, e := ioutil.ReadFile(filepath); e != nil { - return nil, e + return nil, FILE_READ.ErrorParent(e) } else { b.Write(bb) } diff --git a/njs-smtp/config.go b/smtp/config.go similarity index 85% rename from njs-smtp/config.go rename to smtp/config.go index e47c5fb..abeddcf 100644 --- a/njs-smtp/config.go +++ b/smtp/config.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_smtp +package smtp import ( "bytes" @@ -34,8 +34,9 @@ import ( "strconv" "strings" - njs_certif "github.com/nabbar/golib/njs-certif" - . "github.com/nabbar/golib/njs-logger" + njs_certif "github.com/nabbar/golib/certificates" + + . "github.com/nabbar/golib/errors" ) type smtpConfig struct { @@ -58,9 +59,9 @@ type smtpClient struct { } type SMTP interface { - Client() (*smtp.Client, error) + Client() (*smtp.Client, Error) Close() - Check() error + Check() Error Clone() SMTP ForceHost(host string) @@ -141,7 +142,7 @@ func (n NETMode) string() string { } // ParseDSN parses the DSN string to a Config -func newSMTPConfig(dsn string) (*smtpConfig, error) { +func newSMTPConfig(dsn string) (*smtpConfig, Error) { var ( smtpcnf = &smtpConfig{ DSN: dsn, @@ -191,9 +192,9 @@ func newSMTPConfig(dsn string) (*smtpConfig, error) { // dsn[i-1] must be == ')' if an address is specified if dsn[i-1] != ')' { if strings.ContainsRune(dsn[k+1:i], ')') { - return nil, fmt.Errorf("invalid DSN: did you forget to escape a param value") + return nil, CONFIG_INVALID_DSN.Error(nil) } - return nil, fmt.Errorf("invalid DSN: network address not terminated (missing closing brace)") + return nil, CONFIG_INVALID_NETWORK.Error(nil) } if strings.ContainsRune(dsn[k+1:i-1], ':') { @@ -225,7 +226,7 @@ func newSMTPConfig(dsn string) (*smtpConfig, error) { if dsn[j] == '?' { if val, err := url.ParseQuery(dsn[j+1:]); err != nil { - return nil, err + return nil, CONFIG_INVALID_PARAMS.ErrorParent(err) } else { if val.Get("ServerName") != "" { @@ -250,7 +251,7 @@ func newSMTPConfig(dsn string) (*smtpConfig, error) { } if !foundSlash && len(dsn) > 0 { - return nil, fmt.Errorf("invalid DSN: missing the slash ending the host") + return nil, CONFIG_INVALID_HOST.Error(nil) } return smtpcnf, nil @@ -261,7 +262,7 @@ func newSMTPConfig(dsn string) (*smtpConfig, error) { // - params available are : ServerName (string), SkipVerify (boolean) // - tls mode acceptable are : starttls, tls, // - net aceeptable are : tcp4, tcp6, unix -func NewSMTP(dsn string, tlsConfig *tls.Config) (SMTP, error) { +func NewSMTP(dsn string, tlsConfig *tls.Config) (SMTP, Error) { if tlsConfig == nil { tlsConfig = njs_certif.GetTLSConfig("") } @@ -277,7 +278,7 @@ func NewSMTP(dsn string, tlsConfig *tls.Config) (SMTP, error) { } // Client Get SMTP Client interface -func (s *smtpClient) Client() (*smtp.Client, error) { +func (s *smtpClient) Client() (*smtp.Client, Error) { if s.cli == nil { var ( err error @@ -299,35 +300,34 @@ func (s *smtpClient) Client() (*smtp.Client, error) { if s.cfg.TLS == TLS_TLS { s.con, err = tls.Dial(s.cfg.Net.string(), addr, tlsc) - if ErrorLevel.LogErrorCtxf(DebugLevel, "trying to intialize SMTP '%s' over tls connection to '%s'", err, s.cfg.Net.string(), addr) { + if err != nil { s.cfg.TLS = TLS_STARTTLS - err = nil } } if s.cfg.TLS != TLS_TLS { s.con, err = net.Dial(s.cfg.Net.string(), addr) - if ErrorLevel.LogErrorCtxf(DebugLevel, "Dial initiated to server '%s' over '%s'", err, addr, s.cfg.Net.string()) { - return nil, err + if err != nil { + return nil, SMTP_DIAL.ErrorParent(err) } } s.cli, err = smtp.NewClient(s.con, addr) - if ErrorLevel.LogErrorCtxf(DebugLevel, "SMTP Client initiated to server '%s' over '%s'", err, addr, s.cfg.Net.string()) { - return nil, err + if err != nil { + return nil, SMTP_CLIENT_INIT.ErrorParent(err) } if s.cfg.TLS == TLS_STARTTLS { err = s.cli.StartTLS(tlsc) - if ErrorLevel.LogErrorCtxf(DebugLevel, "SMTP Client STARTTLS initiated to server '%s' over '%s'", err, addr, s.cfg.Net.string()) { - return nil, err + if err != nil { + return nil, SMTP_CLIENT_STARTTLS.ErrorParent(err) } } if s.cfg.User != "" || s.cfg.Pass != "" { err = s.cli.Auth(smtp.PlainAuth("", s.cfg.User, s.cfg.Pass, addr)) - if ErrorLevel.LogErrorCtxf(DebugLevel, "SMTP Client authentificate user '%s' with server '%s' over '%s'", err, s.cfg.User, addr, s.cfg.Net.string()) { - return nil, err + if err != nil { + return nil, SMTP_CLIENT_AUTH.ErrorParent(err) } } @@ -341,25 +341,25 @@ func (s *smtpClient) Client() (*smtp.Client, error) { func (s *smtpClient) Close() { if s.cli != nil { if e := s.cli.Quit(); e != nil { - s.cli.Close() + _ = s.cli.Close() } s.cli = nil } if s.con != nil { - s.con.Close() + _ = s.con.Close() s.con = nil } } // Check Try to initiate SMTP dial and negotiation and try to close connection -func (s *smtpClient) Check() error { +func (s *smtpClient) Check() Error { defer s.Close() if c, e := s.Client(); e != nil { return e - } else if e = c.Noop(); e != nil { - return e + } else if e := c.Noop(); e != nil { + return SMTP_CLIENT_NOOP.ErrorParent(e) } return nil diff --git a/smtp/error.go b/smtp/error.go new file mode 100644 index 0000000..a8dc8bb --- /dev/null +++ b/smtp/error.go @@ -0,0 +1,145 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package smtp + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_SMTP + FILE_STAT + FILE_READ + CONFIG_INVALID_DSN + CONFIG_INVALID_NETWORK + CONFIG_INVALID_PARAMS + CONFIG_INVALID_HOST + SMTP_DIAL + SMTP_SEND + SMTP_CLIENT_INIT + SMTP_CLIENT_STARTTLS + SMTP_CLIENT_AUTH + SMTP_CLIENT_NOOP + SMTP_CLIENT_MAIL + SMTP_CLIENT_RCPT + SMTP_CLIENT_DATA + SMTP_CLIENT_EMPTY + SMTP_CLIENT_SEND_RECOVERED + SMTP_CLIENT_FROM_EMPTY + SMTP_CLIENT_TO_EMPTY + SMTP_CLIENT_SUBJECT_EMPTY + SMTP_CLIENT_MAILER_EMPTY + RAND_READER + BUFFER_EMPTY + BUFFER_WRITE_STRING + BUFFER_WRITE_BYTES + IO_WRITER_MISSING + IO_WRITER_ERROR + EMPTY_HTML + EMPTY_CONTENTS + TEMPLATE_PARSING + TEMPLATE_EXECUTE + TEMPLATE_CLONE + TEMPLATE_HTML2TEXT +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case FILE_STAT: + return "error occurs on getting stat of file" + case FILE_READ: + return "error occurs on reading file" + case CONFIG_INVALID_DSN: + return "invalid DSN: did you forget to escape a param value" + case CONFIG_INVALID_NETWORK: + return "invalid DSN: network address not terminated (missing closing brace)" + case CONFIG_INVALID_PARAMS: + return "invalid DSN: parsing uri parameters occurs an error" + case CONFIG_INVALID_HOST: + return "invalid DSN: missing the slash ending the host" + case SMTP_DIAL: + return "error while trying to dial with SMTP server" + case SMTP_SEND: + return "error while sending mail to SMTP server" + case SMTP_CLIENT_INIT: + return "error while trying to initialize new client for dial connection to SMTP Server" + case SMTP_CLIENT_STARTTLS: + return "error while trying to starttls on SMTP server" + case SMTP_CLIENT_AUTH: + return "error while trying to authenticate to SMTP server" + case SMTP_CLIENT_NOOP: + return "error on sending noop command to check connection with SMTP server" + case SMTP_CLIENT_MAIL: + return "error on sending mail command to initialize new mail transaction with SMTP server" + case SMTP_CLIENT_RCPT: + return "error on sending rcpt command to specify add recipient email for the new mail" + case SMTP_CLIENT_DATA: + return "error on opening io writer to send data on client" + case SMTP_CLIENT_EMPTY: + return "cannot send email without any attachment and contents" + case SMTP_CLIENT_SEND_RECOVERED: + return "recovered error while client sending mail" + case SMTP_CLIENT_FROM_EMPTY: + return "sender From address cannot be empty" + case SMTP_CLIENT_TO_EMPTY: + return "list of recipient To address cannot be empty" + case SMTP_CLIENT_SUBJECT_EMPTY: + return "subject of the new mail cannot be empty" + case SMTP_CLIENT_MAILER_EMPTY: + return "mailer of the new mail cannot be empty" + case RAND_READER: + return "error on reading on random reader io" + case BUFFER_EMPTY: + return "buffer is empty" + case BUFFER_WRITE_STRING: + return "error on write string into buffer" + case BUFFER_WRITE_BYTES: + return "error on write bytes into buffer" + case IO_WRITER_MISSING: + return "io writer is not defined" + case IO_WRITER_ERROR: + return "error occur on write on io writer" + case EMPTY_HTML: + return "text/html content is empty" + case EMPTY_CONTENTS: + return "mail content is empty" + case TEMPLATE_PARSING: + return "error occur on parsing template" + case TEMPLATE_EXECUTE: + return "error occur on execute template" + case TEMPLATE_CLONE: + return "error occur while cloning template" + case TEMPLATE_HTML2TEXT: + return "error occur on reading io reader html and convert it to text" + } + + return "" +} diff --git a/njs-smtp/iodata.go b/smtp/iodata.go similarity index 79% rename from njs-smtp/iodata.go rename to smtp/iodata.go index 184ca61..bbe51cc 100644 --- a/njs-smtp/iodata.go +++ b/smtp/iodata.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_smtp +package smtp import ( "bytes" @@ -31,6 +31,8 @@ import ( "fmt" "io" "net/smtp" + + . "github.com/nabbar/golib/errors" ) type ContentType uint8 @@ -63,14 +65,14 @@ type ioData struct { b string } -func (i *ioData) getBoundary() (string, error) { +func (i *ioData) getBoundary() (string, Error) { if i.b == "" { var buf [30]byte _, err := io.ReadFull(rand.Reader, buf[:]) if err != nil { - return "", err + return "", RAND_READER.ErrorParent(err) } bnd := fmt.Sprintf("%x", buf[:]) @@ -85,11 +87,11 @@ func (i ioData) GetBuffer() *bytes.Buffer { return i.p } -func (i *ioData) CRLF() error { +func (i *ioData) CRLF() Error { return i.String("\r\n") } -func (i *ioData) ContentType(ct ContentType, charset string) error { +func (i *ioData) ContentType(ct ContentType, charset string) Error { if charset != "" { return i.Header("Content-Type", fmt.Sprintf("\"%s\"; charset=%s", ct.String(), charset)) } else { @@ -97,7 +99,7 @@ func (i *ioData) ContentType(ct ContentType, charset string) error { } } -func (i *ioData) BoundaryStart(ct ContentType) error { +func (i *ioData) BoundaryStart(ct ContentType) Error { if b, err := i.getBoundary(); err != nil { return err } else if err = i.Header("Content-Type", fmt.Sprintf("%s; boundary=\"%s\"", ct.String(), b)); err != nil { @@ -107,7 +109,7 @@ func (i *ioData) BoundaryStart(ct ContentType) error { } } -func (i *ioData) BoundaryPart() error { +func (i *ioData) BoundaryPart() Error { if i.b == "" { return nil } @@ -121,7 +123,7 @@ func (i *ioData) BoundaryPart() error { } } -func (i *ioData) BoundaryEnd() error { +func (i *ioData) BoundaryEnd() Error { if b, err := i.getBoundary(); err != nil { return err } else if err = i.CRLF(); err != nil { @@ -133,23 +135,23 @@ func (i *ioData) BoundaryEnd() error { } } -func (i *ioData) Header(key, value string) error { +func (i *ioData) Header(key, value string) Error { return i.String(fmt.Sprintf("%s: %s\r\n", key, value)) } -func (i *ioData) String(value string) error { +func (i *ioData) String(value string) Error { if i.p == nil { i.p = bytes.NewBuffer(make([]byte, 0)) } if _, e := i.p.WriteString(value); e != nil { - return e + return BUFFER_WRITE_STRING.ErrorParent(e) } return nil } -func (i *ioData) Bytes(value []byte) error { +func (i *ioData) Bytes(value []byte) Error { if i.p == nil { i.p = bytes.NewBuffer(make([]byte, 0)) } @@ -161,7 +163,7 @@ func (i *ioData) Bytes(value []byte) error { if (n+1)%76 == 0 { if _, e := i.p.Write(tmp); e != nil { - return e + return BUFFER_WRITE_BYTES.ErrorParent(e) } else if e := i.CRLF(); e != nil { return e } @@ -172,7 +174,7 @@ func (i *ioData) Bytes(value []byte) error { if len(tmp) != 0 { if _, e := i.p.Write(tmp); e != nil { - return e + return BUFFER_WRITE_BYTES.ErrorParent(e) } else if e := i.CRLF(); e != nil { return e } @@ -181,28 +183,27 @@ func (i *ioData) Bytes(value []byte) error { return nil } -func (i *ioData) Send() error { +func (i *ioData) Send() Error { if i.w == nil { - return fmt.Errorf("empty writer") + return IO_WRITER_MISSING.Error(nil) } if i.p == nil || i.p.Len() < 1 { - return fmt.Errorf("empty buffer") + return BUFFER_EMPTY.Error(nil) } if _, e := i.w.Write(i.p.Bytes()); e != nil { - return e + return IO_WRITER_ERROR.ErrorParent(e) } return nil } -func (i *ioData) AttachmentStart(c ContentType) error { +func (i *ioData) AttachmentStart(c ContentType) Error { return i.BoundaryStart(c) } -func (i *ioData) AttachmentAddFile(contentType, attachmentName string, attachment *bytes.Buffer) error { +func (i *ioData) AttachmentAddFile(contentType, attachmentName string, attachment *bytes.Buffer) Error { var ( - e error c = make([]byte, base64.StdEncoding.EncodedLen(attachment.Len())) ) @@ -210,10 +211,10 @@ func (i *ioData) AttachmentAddFile(contentType, attachmentName string, attachmen base64.StdEncoding.Encode(c, attachment.Bytes()) if len(c) < 1 { - return fmt.Errorf("encoded buffer is empty") + return BUFFER_EMPTY.Error(nil) } - if e = i.BoundaryPart(); e != nil { + if e := i.BoundaryPart(); e != nil { return e } else if e = i.Header("Content-Type", contentType); e != nil { return e @@ -234,14 +235,14 @@ func (i *ioData) AttachmentAddFile(contentType, attachmentName string, attachmen return nil } -func (i *ioData) AttachmentAddBody(m MailTemplate, ct ContentType) error { +func (i *ioData) AttachmentAddBody(m MailTemplate, ct ContentType) Error { var ( - e error + e Error p *bytes.Buffer ) if m.IsEmpty() { - return fmt.Errorf("text/html content is empty") + return EMPTY_HTML.Error(nil) } switch ct { @@ -280,7 +281,7 @@ func (i *ioData) AttachmentAddBody(m MailTemplate, ct ContentType) error { return nil } -func (i *ioData) AttachmentEnd() error { +func (i *ioData) AttachmentEnd() Error { if e := i.BoundaryEnd(); e != nil { return e } else if e = i.BoundaryEnd(); e != nil { @@ -291,24 +292,24 @@ func (i *ioData) AttachmentEnd() error { } type IOData interface { - ContentType(ct ContentType, charset string) error - Header(key, value string) error - String(value string) error - Bytes(value []byte) error - CRLF() error + ContentType(ct ContentType, charset string) Error + Header(key, value string) Error + String(value string) Error + Bytes(value []byte) Error + CRLF() Error - Send() error + Send() Error GetBuffer() *bytes.Buffer - AttachmentStart(c ContentType) error - AttachmentAddFile(contentType, attachmentName string, attachment *bytes.Buffer) error - AttachmentAddBody(m MailTemplate, ct ContentType) error - AttachmentEnd() error + AttachmentStart(c ContentType) Error + AttachmentAddFile(contentType, attachmentName string, attachment *bytes.Buffer) Error + AttachmentAddBody(m MailTemplate, ct ContentType) Error + AttachmentEnd() Error } -func NewIOData(cli *smtp.Client) (IOData, error) { +func NewIOData(cli *smtp.Client) (IOData, Error) { if w, e := cli.Data(); e != nil { - return nil, e + return nil, SMTP_CLIENT_DATA.ErrorParent(e) } else { return &ioData{ w: w, diff --git a/njs-smtp/listAddress.go b/smtp/listAddress.go similarity index 97% rename from njs-smtp/listAddress.go rename to smtp/listAddress.go index 3b2635d..1aaec09 100644 --- a/njs-smtp/listAddress.go +++ b/smtp/listAddress.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_smtp +package smtp import "strings" @@ -99,7 +99,7 @@ func (lst listMailAddress) String() string { } func (lst listMailAddress) Clone() ListMailAddress { - var l = make(listMailAddress, 0) + var l = make(listMailAddress) for _, a := range lst { l.Add(a.Clone()) @@ -125,5 +125,5 @@ type ListMailAddress interface { } func NewListMailAddress() ListMailAddress { - return make(listMailAddress, 0) + return make(listMailAddress) } diff --git a/njs-smtp/mail.go b/smtp/mail.go similarity index 77% rename from njs-smtp/mail.go rename to smtp/mail.go index d722fb1..147cbf2 100644 --- a/njs-smtp/mail.go +++ b/smtp/mail.go @@ -1,4 +1,4 @@ -package njs_smtp +package smtp import ( "bytes" @@ -6,9 +6,10 @@ import ( "io/ioutil" "os" + "github.com/jaytaylor/html2text" "github.com/olekukonko/tablewriter" - "github.com/jaytaylor/html2text" + . "github.com/nabbar/golib/errors" ) type mailTemplate struct { @@ -34,7 +35,7 @@ func (m mailTemplate) GetTextOption() html2text.Options { return m.opt } -func (m mailTemplate) GetBufferHtml(data interface{}) (*bytes.Buffer, error) { +func (m mailTemplate) GetBufferHtml(data interface{}) (*bytes.Buffer, Error) { var res = bytes.NewBuffer(make([]byte, 0)) if data == nil { @@ -42,30 +43,31 @@ func (m mailTemplate) GetBufferHtml(data interface{}) (*bytes.Buffer, error) { } if err := m.tpl.Execute(res, data); err != nil { - return nil, err + return nil, TEMPLATE_EXECUTE.ErrorParent(err) } return res, nil } -func (m mailTemplate) GetBufferText(data interface{}) (*bytes.Buffer, error) { +func (m mailTemplate) GetBufferText(data interface{}) (*bytes.Buffer, Error) { var ( res = bytes.NewBuffer(make([]byte, 0)) str string + e error ) if buf, err := m.GetBufferHtml(data); err != nil { return nil, err - } else if str, err = html2text.FromReader(buf, m.opt); err != nil { - return nil, err - } else if _, err = res.WriteString(str); err != nil { - return nil, err + } else if str, e = html2text.FromReader(buf, m.opt); e != nil { + return nil, TEMPLATE_HTML2TEXT.ErrorParent(e) + } else if _, e = res.WriteString(str); e != nil { + return nil, BUFFER_WRITE_STRING.ErrorParent(e) } return res, nil } -func (m mailTemplate) GetBufferRich(data interface{}) (*bytes.Buffer, error) { +func (m mailTemplate) GetBufferRich(data interface{}) (*bytes.Buffer, Error) { panic("implement me") } @@ -85,7 +87,7 @@ func (m mailTemplate) IsEmpty() bool { return false } -func (m mailTemplate) Clone() (MailTemplate, error) { +func (m mailTemplate) Clone() (MailTemplate, Error) { res := &mailTemplate{ data: nil, char: m.char, @@ -94,7 +96,7 @@ func (m mailTemplate) Clone() (MailTemplate, error) { } if tpl, err := m.tpl.Clone(); err != nil { - return nil, err + return nil, TEMPLATE_CLONE.ErrorParent(err) } else { res.tpl = tpl } @@ -103,7 +105,7 @@ func (m mailTemplate) Clone() (MailTemplate, error) { } type MailTemplate interface { - Clone() (MailTemplate, error) + Clone() (MailTemplate, Error) IsEmpty() bool @@ -113,14 +115,14 @@ type MailTemplate interface { SetTextOption(opt html2text.Options) GetTextOption() html2text.Options - GetBufferHtml(data interface{}) (*bytes.Buffer, error) - GetBufferText(data interface{}) (*bytes.Buffer, error) - GetBufferRich(data interface{}) (*bytes.Buffer, error) + GetBufferHtml(data interface{}) (*bytes.Buffer, Error) + GetBufferText(data interface{}) (*bytes.Buffer, Error) + GetBufferRich(data interface{}) (*bytes.Buffer, Error) RegisterData(data interface{}) } -func NewMailTemplate(name, tpl string, isFile bool) (MailTemplate, error) { +func NewMailTemplate(name, tpl string, isFile bool) (MailTemplate, Error) { var ( err error res = &mailTemplate{ @@ -154,17 +156,17 @@ func NewMailTemplate(name, tpl string, isFile bool) (MailTemplate, error) { if isFile { var fs []byte if _, err = os.Stat(tpl); err != nil { - return nil, err + return nil, FILE_STAT.ErrorParent(err) } else if fs, err = ioutil.ReadFile(tpl); err != nil { - return nil, err + return nil, FILE_READ.ErrorParent(err) } tpl = string(fs) } if res.tpl, err = res.tpl.Parse(tpl); err != nil { - return nil, err + return nil, TEMPLATE_PARSING.ErrorParent(err) } - return res, err + return res, nil } diff --git a/njs-smtp/sendmail.go b/smtp/sendmail.go similarity index 83% rename from njs-smtp/sendmail.go rename to smtp/sendmail.go index 9e5f960..3753860 100644 --- a/njs-smtp/sendmail.go +++ b/smtp/sendmail.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_smtp +package smtp import ( "bytes" @@ -31,7 +31,9 @@ import ( "net/smtp" "time" - njs_version "github.com/nabbar/golib/njs-version" + vers "github.com/nabbar/golib/version" + + . "github.com/nabbar/golib/errors" ) type sendmail struct { @@ -136,7 +138,7 @@ func (s *sendmail) SetMailer(mailer string) { s.mailer = mailer } -func (s *sendmail) NJSMailer(version njs_version.Version) { +func (s *sendmail) NJSMailer(version vers.Version) { s.mailer = version.GetHeader() } @@ -144,7 +146,7 @@ func (s *sendmail) SetTestMode(enable bool) { s.testMode = enable } -func (s sendmail) Clone() (SendMail, error) { +func (s sendmail) Clone() (SendMail, Error) { var ( la = make([]Attachment, 0) ) @@ -208,42 +210,43 @@ func (s sendmail) Clone() (SendMail, error) { return res, nil } -func (s sendmail) SendSMTP(cli SMTP) (err error, buff *bytes.Buffer) { - var c *smtp.Client +func (s sendmail) SendSMTP(cli SMTP) (err Error, buff *bytes.Buffer) { + var ( + e error + c *smtp.Client + ) defer func(cli *smtp.Client) { if cli != nil { - cli.Quit() - cli.Close() + _ = cli.Quit() + _ = cli.Close() } }(c) if c, err = cli.Client(); err != nil { return - } else if err, buff = s.Send(c); err != nil { - c.Reset() - return err, buff + } else if e, buff = s.Send(c); e != nil { + _ = c.Reset() + return SMTP_SEND.ErrorParent(e), buff } else { return } } -func (s sendmail) Send(cli *smtp.Client) (err error, buff *bytes.Buffer) { +func (s sendmail) Send(cli *smtp.Client) (err Error, buff *bytes.Buffer) { var ( iod IOData ) defer func() { - if r := recover(); r != nil && err != nil { - err = fmt.Errorf("%v, %v", err, r) - } else if r != nil { - err = fmt.Errorf("%v", r) + if r := recover(); r != nil { + err = SMTP_CLIENT_SEND_RECOVERED.ErrorParent(err, fmt.Errorf("%v", r)) } if cli != nil { - cli.Reset() - cli.Quit() - cli.Close() + _ = cli.Reset() + _ = cli.Quit() + _ = cli.Close() } }() @@ -260,38 +263,44 @@ func (s sendmail) Send(cli *smtp.Client) (err error, buff *bytes.Buffer) { } else if s.msgText.Len() > 0 { ctBody = CONTENTTYPE_TEXT } else { - return fmt.Errorf("no attachment & no contents"), nil + return SMTP_CLIENT_EMPTY.Error(nil), nil } if len(s.from.AddressOnly()) < 7 { - return fmt.Errorf("from address is empty"), nil + return SMTP_CLIENT_FROM_EMPTY.Error(nil), nil } - if err = cli.Noop(); err != nil { + if e := cli.Noop(); e != nil { + err = SMTP_CLIENT_NOOP.ErrorParent(e) return } - if err = cli.Mail(s.from.String()); err != nil { + if e := cli.Mail(s.from.String()); e != nil { + err = SMTP_CLIENT_MAIL.ErrorParent(e) return } if s.testMode { - if err = cli.Rcpt(s.from.String()); err != nil { + if e := cli.Rcpt(s.from.String()); e != nil { + err = SMTP_CLIENT_RCPT.ErrorParent(e) return } } else { for _, a := range s.to.Slice() { - if err = cli.Rcpt(a.String()); err != nil { + if e := cli.Rcpt(a.String()); e != nil { + err = SMTP_CLIENT_RCPT.ErrorParent(e) return } } for _, a := range s.cc.Slice() { - if err = cli.Rcpt(a.String()); err != nil { + if e := cli.Rcpt(a.String()); e != nil { + err = SMTP_CLIENT_RCPT.ErrorParent(e) return } } for _, a := range s.bcc.Slice() { - if err = cli.Rcpt(a.String()); err != nil { + if e := cli.Rcpt(a.String()); e != nil { + err = SMTP_CLIENT_RCPT.ErrorParent(e) return } } @@ -306,7 +315,7 @@ func (s sendmail) Send(cli *smtp.Client) (err error, buff *bytes.Buffer) { } if s.to.IsEmpty() { - return fmt.Errorf("to address is empty"), nil + return SMTP_CLIENT_TO_EMPTY.Error(nil), nil } else if err = iod.Header("To", s.to.String()); err != nil { return } @@ -334,7 +343,7 @@ func (s sendmail) Send(cli *smtp.Client) (err error, buff *bytes.Buffer) { } if len(s.subject) < 1 { - return fmt.Errorf("subjetc is empty"), nil + return SMTP_CLIENT_SUBJECT_EMPTY.Error(nil), nil } else { var ( b = []byte(s.subject) @@ -349,7 +358,7 @@ func (s sendmail) Send(cli *smtp.Client) (err error, buff *bytes.Buffer) { } if len(s.mailer) < 1 { - return fmt.Errorf("mailer is empty"), nil + return SMTP_CLIENT_MAILER_EMPTY.Error(nil), nil } else { if err = iod.Header("X-Mailer", s.mailer); err != nil { return @@ -376,13 +385,13 @@ func (s sendmail) Send(cli *smtp.Client) (err error, buff *bytes.Buffer) { return } } else if s.msgHtml.IsEmpty() { - return fmt.Errorf("empty content mail"), nil + return EMPTY_CONTENTS.Error(nil), nil } else if err = iod.AttachmentAddBody(s.msgHtml, CONTENTTYPE_TEXT); err != nil { return } } else if ctBody == CONTENTTYPE_HTML { if s.msgHtml.IsEmpty() { - return fmt.Errorf("empty content mail"), nil + return EMPTY_CONTENTS.Error(nil), nil } else if err = iod.AttachmentAddBody(s.msgHtml, CONTENTTYPE_HTML); err != nil { return } @@ -442,13 +451,13 @@ type SendMail interface { SetMessageId(id string) SetMailer(mailer string) - NJSMailer(version njs_version.Version) + NJSMailer(version vers.Version) SetTestMode(enable bool) - Clone() (SendMail, error) - Send(cli *smtp.Client) (err error, buff *bytes.Buffer) - SendSMTP(cli SMTP) (err error, buff *bytes.Buffer) + Clone() (SendMail, Error) + Send(cli *smtp.Client) (err Error, buff *bytes.Buffer) + SendSMTP(cli SMTP) (err Error, buff *bytes.Buffer) } func NewSendMail() SendMail { diff --git a/njs-static/README.md b/static/README.md similarity index 100% rename from njs-static/README.md rename to static/README.md diff --git a/static/error.go b/static/error.go new file mode 100644 index 0000000..18c7e46 --- /dev/null +++ b/static/error.go @@ -0,0 +1,58 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package static + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Static + EMPTY_PACKED + INDEX_NOT_FOUND + INDEX_REQUESTED_NOT_SET + FILE_NOT_FOUND +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case EMPTY_PACKED: + return "packed file is empty" + case INDEX_NOT_FOUND: + return "mode index is defined but index.(html|htm) is not found" + case INDEX_REQUESTED_NOT_SET: + return "request call index but mode index is false" + case FILE_NOT_FOUND: + return "requested packed file is not found" + } + + return "" +} diff --git a/njs-static/static.go b/static/static.go similarity index 87% rename from njs-static/static.go rename to static/static.go index 1439db0..920a76e 100644 --- a/njs-static/static.go +++ b/static/static.go @@ -23,7 +23,7 @@ * */ -package njs_static +package static import ( "bytes" @@ -33,14 +33,14 @@ import ( "path/filepath" "strings" - njs_router "github.com/nabbar/golib/njs-router" - - "github.com/gin-gonic/gin/render" - - njs_logger "github.com/nabbar/golib/njs-logger" - "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/render" "github.com/gobuffalo/packr" + + . "github.com/nabbar/golib/errors" + . "github.com/nabbar/golib/logger" + + njs_router "github.com/nabbar/golib/router" ) const ( @@ -64,11 +64,11 @@ type Static interface { SetDownloadAll() SetDownload(file string) IsDownload(file string) bool - + Has(file string) bool Find(file string) ([]byte, error) - Health() error + Health() Error Get(c *gin.Context) } @@ -119,21 +119,21 @@ func (s staticHandler) print() { } for _, f := range s.box.List() { - njs_logger.DebugLevel.Logf("Embedded file : %s", f) + DebugLevel.Logf("Embedded file : %s", f) } s.debug = true } -func (s staticHandler) Health() error { +func (s staticHandler) Health() Error { s.print() if len(s.box.List()) < 1 { - return fmt.Errorf("empty packed file stored") + return EMPTY_PACKED.Error(nil) } if s.index && !s.box.Has("index.html") && !s.box.Has("index.htm") { - return fmt.Errorf("cannot find 'index.html' file") + return INDEX_NOT_FOUND.Error(nil) } return nil @@ -160,12 +160,12 @@ func (s staticHandler) Get(c *gin.Context) { calledFile = FileIndex requestPath = FileIndex } else { - c.Abort() + _ = c.AbortWithError(http.StatusNotFound, INDEX_REQUESTED_NOT_SET.Error(nil)) return } } - if obj, err := s.box.Find(requestPath); !njs_logger.ErrorLevel.LogErrorCtxf(njs_logger.NilLevel, "find file '%s' error for request '%s%s' :", err, calledFile, s.prefix, requestPath) { + if obj, err := s.box.Find(requestPath); !ErrorLevel.LogErrorCtxf(DebugLevel, "find file '%s' error for request '%s%s' :", err, calledFile, s.prefix, requestPath) { head := s.head() if s.allDwnld || s.IsDownload(requestPath) { @@ -179,7 +179,7 @@ func (s staticHandler) Get(c *gin.Context) { Reader: bytes.NewReader(obj), }) } else { - c.Abort() + _ = c.AbortWithError(http.StatusNotFound, FILE_NOT_FOUND.Error(nil)) } } diff --git a/njs-status/README.md b/status/README.md similarity index 100% rename from njs-status/README.md rename to status/README.md diff --git a/njs-status/status.go b/status/status.go similarity index 73% rename from njs-status/status.go rename to status/status.go index a344c0a..332b89e 100644 --- a/njs-status/status.go +++ b/status/status.go @@ -23,7 +23,7 @@ * */ -package njs_status +package status import ( "fmt" @@ -31,13 +31,15 @@ import ( "path" "strings" - njs_router "github.com/nabbar/golib/njs-router" + njs_router "github.com/nabbar/golib/router" - njs_version "github.com/nabbar/golib/njs-version" + njs_version "github.com/nabbar/golib/version" "github.com/gin-gonic/gin" ) +// @TODO : see compliant with https://tools.ietf.org/html/draft-inadarei-api-health-check-02 + type StatusItemResponse struct { Name string Status string @@ -48,7 +50,7 @@ type StatusItemResponse struct { type StatusResponse struct { StatusItemResponse - Partner []StatusItemResponse + Component []StatusItemResponse } const statusOK = "OK" @@ -63,7 +65,7 @@ type statusItem struct { release string } -type statusPartner struct { +type statusComponent struct { statusItem WarnIfErr bool later *initLater @@ -71,8 +73,8 @@ type statusPartner struct { type mainPackage struct { statusItem - ptn []statusPartner - header func(c *gin.Context) + cpt []statusComponent + header gin.HandlerFunc later *initLater init bool } @@ -87,18 +89,18 @@ type initLater struct { type Status interface { Register(prefix string, register njs_router.RegisterRouter) - AddPartner(name, msgOK, msgKO, release, build string, WarnIfError bool, health func() error) - AddVersionPartner(vers njs_version.Version, msgOK, msgKO string, WarnIfError bool, health func() error) + AddComponent(name, msgOK, msgKO, release, build string, WarnIfError bool, health func() error) + AddVersionComponent(vers njs_version.Version, msgOK, msgKO string, WarnIfError bool, health func() error) - LaterAddPartner(info func() (name, release, build string), msg func() (ok string, ko string), health func() error, WarnIfError bool) - LaterAddVersionPartner(vers func() njs_version.Version, msg func() (ok string, ko string), health func() error, WarnIfError bool) + LaterAddComponent(info func() (name, release, build string), msg func() (ok string, ko string), health func() error, WarnIfError bool) + LaterAddVersionComponent(vers func() njs_version.Version, msg func() (ok string, ko string), health func() error, WarnIfError bool) Get(c *gin.Context) } -func NewStatusLater(info func() (name, release, build string), msg func() (ok string, ko string), health func() error, Header func(c *gin.Context)) Status { +func NewStatusLater(info func() (name, release, build string), msg func() (ok string, ko string), health func() error, Header gin.HandlerFunc) Status { return &mainPackage{ - ptn: make([]statusPartner, 0), + cpt: make([]statusComponent, 0), header: Header, later: &initLater{ version: nil, @@ -110,19 +112,19 @@ func NewStatusLater(info func() (name, release, build string), msg func() (ok st } } -func NewStatus(name, msgOK, msgKO, release, build string, health func() error, Header func(c *gin.Context)) Status { +func NewStatus(name, msgOK, msgKO, release, build string, health func() error, Header gin.HandlerFunc) Status { return &mainPackage{ statusItem: newItem(name, msgOK, msgKO, release, build, health), - ptn: make([]statusPartner, 0), + cpt: make([]statusComponent, 0), header: Header, later: nil, init: false, } } -func NewVersionStatusLater(vers func() njs_version.Version, msg func() (ok string, ko string), health func() error, Header func(c *gin.Context)) Status { +func NewVersionStatusLater(vers func() njs_version.Version, msg func() (ok string, ko string), health func() error, Header gin.HandlerFunc) Status { return &mainPackage{ - ptn: make([]statusPartner, 0), + cpt: make([]statusComponent, 0), header: Header, later: &initLater{ version: vers, @@ -134,7 +136,7 @@ func NewVersionStatusLater(vers func() njs_version.Version, msg func() (ok strin } } -func NewVersionStatus(vers njs_version.Version, msgOK, msgKO string, health func() error, Header func(c *gin.Context)) Status { +func NewVersionStatus(vers njs_version.Version, msgOK, msgKO string, health func() error, Header gin.HandlerFunc) Status { return NewStatus(vers.GetPackage(), msgOK, msgKO, vers.GetRelease(), vers.GetBuild(), health, Header) } @@ -149,16 +151,16 @@ func newItem(name, msgOK, msgKO, release, build string, health func() error) sta } } -func (p *mainPackage) AddPartner(name, msgOK, msgKO, release, build string, WarnIfError bool, health func() error) { - p.ptn = append(p.ptn, statusPartner{ +func (p *mainPackage) AddComponent(name, msgOK, msgKO, release, build string, WarnIfError bool, health func() error) { + p.cpt = append(p.cpt, statusComponent{ statusItem: newItem(name, msgOK, msgKO, release, build, health), WarnIfErr: WarnIfError, later: nil, }) } -func (p *mainPackage) LaterAddPartner(info func() (name, release, build string), msg func() (ok string, ko string), health func() error, WarnIfError bool) { - p.ptn = append(p.ptn, statusPartner{ +func (p *mainPackage) LaterAddComponent(info func() (name, release, build string), msg func() (ok string, ko string), health func() error, WarnIfError bool) { + p.cpt = append(p.cpt, statusComponent{ WarnIfErr: WarnIfError, later: &initLater{ version: nil, @@ -169,12 +171,12 @@ func (p *mainPackage) LaterAddPartner(info func() (name, release, build string), }) } -func (p *mainPackage) AddVersionPartner(vers njs_version.Version, msgOK, msgKO string, WarnIfError bool, health func() error) { - p.AddPartner(vers.GetPackage(), msgOK, msgKO, vers.GetRelease(), vers.GetBuild(), WarnIfError, health) +func (p *mainPackage) AddVersionComponent(vers njs_version.Version, msgOK, msgKO string, WarnIfError bool, health func() error) { + p.AddComponent(vers.GetPackage(), msgOK, msgKO, vers.GetRelease(), vers.GetBuild(), WarnIfError, health) } -func (p *mainPackage) LaterAddVersionPartner(vers func() njs_version.Version, msg func() (ok string, ko string), health func() error, WarnIfError bool) { - p.ptn = append(p.ptn, statusPartner{ +func (p *mainPackage) LaterAddVersionComponent(vers func() njs_version.Version, msg func() (ok string, ko string), health func() error, WarnIfError bool) { + p.cpt = append(p.cpt, statusComponent{ WarnIfErr: WarnIfError, later: &initLater{ version: vers, @@ -204,14 +206,14 @@ func (p *mainPackage) initStatus() { p.later = nil } - var ptn = make([]statusPartner, 0) + var cpt = make([]statusComponent, 0) - for _, part := range p.ptn { + for _, part := range p.cpt { if part.later != nil { if part.later.info != nil { name, release, build := part.later.info() ok, ko := part.later.msg() - part = statusPartner{ + part = statusComponent{ statusItem: newItem(name, ok, ko, release, build, part.health), WarnIfErr: part.WarnIfErr, later: nil, @@ -219,7 +221,7 @@ func (p *mainPackage) initStatus() { } else if p.later.version != nil { v := p.later.version() ok, ko := p.later.msg() - part = statusPartner{ + part = statusComponent{ statusItem: newItem(v.GetPackage(), ok, ko, v.GetRelease(), v.GetBuild(), part.health), WarnIfErr: part.WarnIfErr, later: nil, @@ -231,11 +233,11 @@ func (p *mainPackage) initStatus() { } } - ptn = append(ptn, part) + cpt = append(cpt, part) } p.init = true - p.ptn = ptn + p.cpt = cpt } func (p *mainPackage) cleanPrefix(prefix string) string { @@ -302,20 +304,20 @@ func (p *mainPackage) Get(c *gin.Context) { make([]StatusItemResponse, 0), } - for _, pkg := range p.ptn { + for _, pkg := range p.cpt { pres := pkg.GetStatusResponse(c) if res.Status == statusOK && pres.Status == statusKO && !pkg.WarnIfErr { res.Status = statusKO } else if pres.Status == statusKO { hasError = true } - res.Partner = append(res.Partner, pres) + res.Component = append(res.Component, pres) } if res.Status != statusOK { c.AbortWithStatusJSON(http.StatusInternalServerError, &res) } else if hasError { - c.JSON(http.StatusMultiStatus, &res) + c.JSON(http.StatusAccepted, &res) } else { c.JSON(http.StatusOK, &res) } diff --git a/test/test-archive/main.go b/test/test-archive/main.go index c9399a7..1645635 100644 --- a/test/test-archive/main.go +++ b/test/test-archive/main.go @@ -30,16 +30,16 @@ import ( "io/ioutil" "os" - njs_archive "github.com/nabbar/golib/njs-archive" + njs_archive "github.com/nabbar/golib/archive" - iou "github.com/nabbar/golib/njs-ioutils" + iou "github.com/nabbar/golib/ioutils" ) // git archive --format=tar --output=git.tar HEAD //const fileName = "./git.tar" const fileName = "./vendor.zip" -//const contain = "njs-version/license_mit.go" +//const contain = "version/license_mit.go" const contain = "vendor/github.com/gin-gonic/gin/internal/json/json.go" //const regex = "" @@ -57,13 +57,17 @@ func main() { panic(err) } - defer src.Close() + defer func() { + _ = src.Close() + }() if tmp, err = iou.NewTempFile(); err != nil { panic(err) } - defer iou.DelTempFile(tmp, true) + defer func() { + _ = iou.DelTempFile(tmp) + }() if _, err = io.Copy(tmp, src); err != nil { panic(err) @@ -73,7 +77,9 @@ func main() { panic(err) } - defer rio.Close() + defer func() { + _ = rio.Close() + }() if _, err = rio.Seek(0, 0); err != nil { panic(err) diff --git a/test/test-progressbar/main.go b/test/test-progressbar/main.go index 0cd1e7f..c5973a1 100644 --- a/test/test-progressbar/main.go +++ b/test/test-progressbar/main.go @@ -29,21 +29,21 @@ import ( "math/rand" "time" - njs_progress "github.com/nabbar/golib/njs-progress" + npb "github.com/nabbar/golib/progress" "github.com/vbauerster/mpb/v5" ) var ( - pb njs_progress.ProgressBar - br njs_progress.Bar + pb npb.ProgressBar + br npb.Bar ) func main() { println("Starting...") - pb = njs_progress.NewProgressBar(0, time.Time{}, nil, mpb.WithWidth(64)) + pb = npb.NewProgressBar(0, time.Time{}, nil, mpb.WithWidth(64)) pb.SetSemaphoreOption(0, 0) - br = pb.NewBarSimple("test bar") + br = pb.NewBarSimpleETA("test bar") defer br.DeferMain(false) diff --git a/test/test-smtp/main.go b/test/test-smtp/main.go new file mode 100644 index 0000000..2a2f9b6 --- /dev/null +++ b/test/test-smtp/main.go @@ -0,0 +1,101 @@ +package main + +import ( + "bytes" + "crypto/tls" + "fmt" + + "github.com/jaytaylor/html2text" + "github.com/olekukonko/tablewriter" + + "github.com/nabbar/golib/logger" + "github.com/nabbar/golib/smtp" +) + +const ( + CONFIG_SMTP_DSN = "user@example.com:test_password@tcp4(mail.example.com:25)/starttls?ServerName=mail.example.com" + CONFIG_EMAIL_FROM = "sender@example.com" + CONFIG_EMAIL_TO = "recipient@example.com" + CONFIG_MAILER = "Nabbar SMTP Tester" + CONFIG_SUBJECT = "Testing Send Mail" + CONFIG_TESTMODE = false + CONFIG_TEMPLATE_TEST = `Hello {{.Name}}, this is a test e-mail sent by Go with package nabbar/golib/smtp.` +) + +func main() { + var ( + cfg smtp.SMTP + tpl smtp.MailTemplate + snd smtp.SendMail + err error + buff = bytes.NewBuffer(make([]byte, 0)) + ) + + logger.EnableColor() + logger.AddGID(true) + logger.FileTrace(true) + logger.SetFormat(logger.TextFormat) + logger.SetLevel(logger.DebugLevel) + + tpl, err = smtp.NewMailTemplate("mail", CONFIG_TEMPLATE_TEST, false) + logger.FatalLevel.LogErrorCtxf(logger.InfoLevel, "mail template parsing", err) + tpl.SetCharset("utf-8") + tpl.RegisterData(struct { + Name string + }{Name: "éloïse"}) + tpl.SetTextOption(html2text.Options{ + PrettyTables: true, + PrettyTablesOptions: &html2text.PrettyTablesOptions{ + AutoFormatHeader: true, + AutoWrapText: true, + ReflowDuringAutoWrap: true, + ColWidth: tablewriter.MAX_ROW_WIDTH, + ColumnSeparator: tablewriter.COLUMN, + RowSeparator: tablewriter.ROW, + CenterSeparator: tablewriter.CENTER, + HeaderAlignment: tablewriter.ALIGN_DEFAULT, + FooterAlignment: tablewriter.ALIGN_DEFAULT, + Alignment: tablewriter.ALIGN_DEFAULT, + ColumnAlignment: []int{}, + NewLine: tablewriter.NEWLINE, + HeaderLine: true, + RowLine: false, + AutoMergeCells: false, + Borders: tablewriter.Border{Left: true, Right: true, Bottom: true, Top: true}, + }, + OmitLinks: true, + }) + + if p, e := tpl.GetBufferHtml(nil); e == nil { + fmt.Printf("\n\n\n\t >> HTML Mail : \n") + print(p.String()) + fmt.Printf("\n\n") + } + + if p, e := tpl.GetBufferText(nil); e == nil { + fmt.Printf("\n\n\n\t >> Text Mail : \n") + print(p.String()) + fmt.Printf("\n\n") + } + + snd = smtp.NewSendMail() + snd.SetTo(smtp.MailAddressParser(CONFIG_EMAIL_TO)) + snd.SetFrom(smtp.MailAddressParser(CONFIG_EMAIL_FROM)) + snd.SetMailer(CONFIG_MAILER) + snd.SetSubject(CONFIG_SUBJECT) + snd.SetTestMode(CONFIG_TESTMODE) + snd.SetForceOnly(smtp.CONTENTTYPE_HTML) + snd.SetHtml(tpl) + + cfg, err = smtp.NewSMTP(CONFIG_SMTP_DSN, &tls.Config{}) + logger.FatalLevel.LogErrorCtxf(logger.InfoLevel, "smtp config parsing", err) + logger.FatalLevel.LogErrorCtxf(logger.InfoLevel, "smtp checking working", cfg.Check()) + + err, buff = snd.SendSMTP(cfg) + logger.FatalLevel.LogErrorCtxf(logger.InfoLevel, "Sending Mail", err) + + fmt.Printf("\n\n\n\t >> Buff Mail : \n") + print(buff.String()) + fmt.Printf("\n\n") + +} diff --git a/test/test-win-max-nofile/main.go b/test/test-win-max-nofile/main.go index e3ff568..ba751c0 100644 --- a/test/test-win-max-nofile/main.go +++ b/test/test-win-max-nofile/main.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - njs_ioutils "github.com/nabbar/golib/njs-ioutils" + njs_ioutils "github.com/nabbar/golib/ioutils" ) func main() { diff --git a/njs-version/README.md b/version/README.md similarity index 100% rename from njs-version/README.md rename to version/README.md diff --git a/version/error.go b/version/error.go new file mode 100644 index 0000000..2dd1051 --- /dev/null +++ b/version/error.go @@ -0,0 +1,55 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package version + +import errors "github.com/nabbar/golib/errors" + +const ( + EMPTY_PARAMS errors.CodeError = iota + errors.MIN_PKG_Version + GOVERSION_INIT + GOVERSION_RUNTIME + GOVERSION_CONTRAINT +) + +func init() { + errors.RegisterFctMessage(getMessage) +} + +func getMessage(code errors.CodeError) (message string) { + switch code { + case EMPTY_PARAMS: + return "given parameters is empty" + case GOVERSION_INIT: + return "init GoVersion contraint error" + case GOVERSION_RUNTIME: + return "extract GoVersion runtime error" + case GOVERSION_CONTRAINT: + return "current binary is build with a non-compatible version of Go" + } + + return "" +} diff --git a/njs-version/license.go b/version/license.go similarity index 99% rename from njs-version/license.go rename to version/license.go index b5b9d48..62ff77d 100644 --- a/njs-version/license.go +++ b/version/license.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version import "fmt" diff --git a/njs-version/license_agpl_v3.go b/version/license_agpl_v3.go similarity index 99% rename from njs-version/license_agpl_v3.go rename to version/license_agpl_v3.go index 98563fe..1149c02 100644 --- a/njs-version/license_agpl_v3.go +++ b/version/license_agpl_v3.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func licence_agpl_v3() string { return ` diff --git a/njs-version/license_apache2.go b/version/license_apache2.go similarity index 99% rename from njs-version/license_apache2.go rename to version/license_apache2.go index f20bdb6..622707c 100644 --- a/njs-version/license_apache2.go +++ b/version/license_apache2.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func licence_apache2() string { return ` diff --git a/njs-version/license_cc-by-4.go b/version/license_cc-by-4.go similarity index 99% rename from njs-version/license_cc-by-4.go rename to version/license_cc-by-4.go index 4f4834e..7645c7e 100644 --- a/njs-version/license_cc-by-4.go +++ b/version/license_cc-by-4.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func license_cc_by_4() string { return ` diff --git a/njs-version/license_cc-sa-4.go b/version/license_cc-sa-4.go similarity index 99% rename from njs-version/license_cc-sa-4.go rename to version/license_cc-sa-4.go index 3e8a135..ea3dbdf 100644 --- a/njs-version/license_cc-sa-4.go +++ b/version/license_cc-sa-4.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func license_cc_sa_4() string { return ` diff --git a/njs-version/license_cc0-v1.go b/version/license_cc0-v1.go similarity index 99% rename from njs-version/license_cc0-v1.go rename to version/license_cc0-v1.go index 44e9d4c..fa8cd5d 100644 --- a/njs-version/license_cc0-v1.go +++ b/version/license_cc0-v1.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func licence_cc0_v1() string { return ` diff --git a/njs-version/license_gpl_v3.go b/version/license_gpl_v3.go similarity index 99% rename from njs-version/license_gpl_v3.go rename to version/license_gpl_v3.go index eb3eb69..b316826 100644 --- a/njs-version/license_gpl_v3.go +++ b/version/license_gpl_v3.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func licence_gpl_v3() string { return ` diff --git a/njs-version/license_lgpl_v3.go b/version/license_lgpl_v3.go similarity index 99% rename from njs-version/license_lgpl_v3.go rename to version/license_lgpl_v3.go index 6252b7d..e4cb9e6 100644 --- a/njs-version/license_lgpl_v3.go +++ b/version/license_lgpl_v3.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func licence_lgpl_v3() string { return ` diff --git a/njs-version/license_mit.go b/version/license_mit.go similarity index 99% rename from njs-version/license_mit.go rename to version/license_mit.go index 5a74745..d3cf44d 100644 --- a/njs-version/license_mit.go +++ b/version/license_mit.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func license_mit() string { return ` diff --git a/njs-version/license_mozilla_v2.go b/version/license_mozilla_v2.go similarity index 99% rename from njs-version/license_mozilla_v2.go rename to version/license_mozilla_v2.go index 4d58ef9..92eca41 100644 --- a/njs-version/license_mozilla_v2.go +++ b/version/license_mozilla_v2.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func license_mozilla_v2() string { return ` diff --git a/njs-version/license_sil_v11.go b/version/license_sil_v11.go similarity index 99% rename from njs-version/license_sil_v11.go rename to version/license_sil_v11.go index 5cf1733..89f3d68 100644 --- a/njs-version/license_sil_v11.go +++ b/version/license_sil_v11.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version func license_sil_ofl_v11() string { return ` diff --git a/njs-version/version.go b/version/version.go similarity index 94% rename from njs-version/version.go rename to version/version.go index 7cb5332..bf5c476 100644 --- a/njs-version/version.go +++ b/version/version.go @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package njs_version +package version import ( "bytes" @@ -35,6 +35,7 @@ import ( "strings" govers "github.com/hashicorp/go-version" + . "github.com/nabbar/golib/errors" ) type versionModel struct { @@ -50,7 +51,7 @@ type versionModel struct { } type Version interface { - CheckGo(RequireGoVersion, RequireGoContraint string) error + CheckGo(RequireGoVersion, RequireGoContraint string) Error GetAppId() string GetAuthor() string @@ -97,19 +98,19 @@ func NewVersion(License license, Package, Description, Date, Build, Release, Aut } } -func (vers versionModel) CheckGo(RequireGoVersion, RequireGoContraint string) error { +func (vers versionModel) CheckGo(RequireGoVersion, RequireGoContraint string) Error { constraint, err := govers.NewConstraint(RequireGoContraint + RequireGoVersion) if err != nil { - return fmt.Errorf("cannot init GoVersion contraint : %v", err) + return GOVERSION_INIT.ErrorParent(err) } goVersion, err := govers.NewVersion(runtime.Version()[2:]) if err != nil { - return fmt.Errorf("cannot extract GoVersion runtime : %v", err) + return GOVERSION_RUNTIME.ErrorParent(err) } if !constraint.Check(goVersion) { - return fmt.Errorf("%s is not compiled with Go %s, please use Go %s to recompile", vers.versionPackage, goVersion, RequireGoVersion) + return GOVERSION_CONTRAINT.ErrorParent(fmt.Errorf("must be compiled with Go version %s (instead of %s)", RequireGoVersion, goVersion)) } return nil