- Fix issue #94

- Fix linter
- Remove useless code/deadcode
This commit is contained in:
Nicolas JUHEL
2021-04-13 13:08:49 +02:00
parent 499b5ee613
commit dbb443eb65
48 changed files with 673 additions and 1418 deletions

View File

@@ -20,13 +20,14 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: ^1.14 go-version: ^1.16
id: go id: go
- name: Check out code into the Go module directory - name: Check out code into the Go module directory
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Link workspace with GOPATH - name: Link workspace with GOPATH
continue-on-error: false
run: | run: |
sudo mkdir -vp $(dirname ${GOPATH}/src/github.com/${GITHUB_REPOSITORY}) sudo mkdir -vp $(dirname ${GOPATH}/src/github.com/${GITHUB_REPOSITORY})
sudo chown -R ${USER}:users $(dirname ${GOPATH}/src/github.com/${GITHUB_REPOSITORY}) sudo chown -R ${USER}:users $(dirname ${GOPATH}/src/github.com/${GITHUB_REPOSITORY})
@@ -34,17 +35,19 @@ jobs:
sudo ln -svf $(pwd) ${GOPATH}/src/github.com/${GITHUB_REPOSITORY} sudo ln -svf $(pwd) ${GOPATH}/src/github.com/${GITHUB_REPOSITORY}
- name: Check out tools into the Go module directory - name: Check out tools into the Go module directory
continue-on-error: false
run: | run: |
git clone https://github.com/nabbar/gotools.git scripts git clone https://github.com/nabbar/gotools.git scripts
./scripts/prepare ./scripts/prepare
- name: Update vendor or dependancies
continue-on-error: false
run: ./scripts/ci_depend
- name: Check goFmt & goImport - name: Check goFmt & goImport
continue-on-error: false continue-on-error: false
run: ./scripts/ci_format run: ./scripts/ci_format
- name: Update vendor or dependancies
run: ./scripts/ci_depend
- name: Check Missing License - name: Check Missing License
continue-on-error: false continue-on-error: false
run: ./scripts/ci_license run: ./scripts/ci_license

View File

@@ -1,23 +1,88 @@
# This file contains all available configuration options linters-settings:
# with their default values. dupl:
threshold: 100
funlen:
lines: 250
statements: 200
gci:
local-prefixes: github.com/golangci/golangci-lint
goconst:
min-len: 2
min-occurrences: 2
gocyclo:
min-complexity: 50
goimports:
local-prefixes: github.com/golangci/golangci-lint
gomnd:
settings:
mnd:
# don't include the "operation" and "assign"
checks: argument,case,condition,return
govet:
check-shadowing: true
settings:
printf:
funcs:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
lll:
line-length: 140
maligned:
suggest-new: true
misspell:
locale: US
linters:
# please, do not use `enable-all`: it's deprecated and will be removed soon.
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
disable-all: true
enable:
- bodyclose
- deadcode
- dogsled
- dupl
- errcheck
- exportloopref
- exhaustive
- funlen
- goconst
- gocyclo
- gofmt
- goimports
- gomnd
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- lll
- misspell
- nakedret
- noctx
- rowserrcheck
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
# options for analysis running
run: run:
# default concurrency is a available CPU number # default concurrency is a available CPU number
concurrency: 4 #concurrency: 4
# timeout for analysis, e.g. 30s, 5m, default is 1m # timeout for analysis, e.g. 30s, 5m, default is 1m
timeout: 30m timeout: 10m
# exit code when at least one issue was found, default is 1 # exit code when at least one issue was found, default is 1
issues-exit-code: 0 issues-exit-code: 1
# include test files or not, default is true # include test files or not, default is true
tests: true tests: false
# list of build tags, all linters use it. Default is empty list. # list of build tags, all linters use it. Default is empty list.
build-tags: [] #build-tags:
# - mytag
# which dirs to skip: issues from them won't be reported; # which dirs to skip: issues from them won't be reported;
# can use regexp here: generated.*, regexp is applied on full path; # can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but default dirs are skipped independently # default value is empty list, but default dirs are skipped independently
@@ -25,22 +90,21 @@ run:
# "/" will be replaced by current OS file path separator to properly work # "/" will be replaced by current OS file path separator to properly work
# on Windows. # on Windows.
skip-dirs: skip-dirs:
- vendor - test/
- test - vendor/
- .*
# default is true. Enables skipping of directories: # default is true. Enables skipping of directories:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs-use-default: true #skip-dirs-use-default: true
# which files to skip: they will be analyzed, but issues from them # which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is # won't be reported. Default value is empty list, but there is
# no need to include all autogenerated files, we confidently recognize # no need to include all autogenerated files, we confidently recognize
# autogenerated files. If it's not please let us know. # autogenerated files. If it's not please let us know.
# "/" will be replaced by current OS file path separator to properly work # "/" will be replaced by current OS file path separator to properly work
# on Windows. # on Windows.
skip-files: #skip-files:
- ".*\\.my\\.go$" # - ".*\\.my\\.go$"
# - lib/bad.go
# by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules":
# If invoked with -mod=readonly, the go command is disallowed from the implicit # If invoked with -mod=readonly, the go command is disallowed from the implicit
# automatic updating of go.mod described above. Instead, it fails when any changes # automatic updating of go.mod described above. Instead, it fails when any changes
@@ -49,401 +113,20 @@ run:
# If invoked with -mod=vendor, the go command assumes that the vendor # If invoked with -mod=vendor, the go command assumes that the vendor
# directory holds the correct copies of dependencies and ignores # directory holds the correct copies of dependencies and ignores
# the dependency descriptions in go.mod. # the dependency descriptions in go.mod.
#modules-download-mode: readonly|release|vendor modules-download-mode: vendor
# Allow multiple parallel golangci-lint instances running. # Allow multiple parallel golangci-lint instances running.
# If false (default) - golangci-lint acquires file lock on start. # If false (default) - golangci-lint acquires file lock on start.
allow-parallel-runners: false allow-parallel-runners: true
# output configuration options # output configuration options
output: output:
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
format: colored-line-number format: colored-line-number
# print lines of code with issue, default is true # print lines of code with issue, default is true
print-issued-lines: true print-issued-lines: true
# print linter name in the end of issue text, default is true # print linter name in the end of issue text, default is true
print-linter-name: true print-linter-name: true
# make issues output unique by line, default is true # make issues output unique by line, default is true
uniq-by-line: true uniq-by-line: true
# add a prefix to the output file references; default is no prefix # add a prefix to the output file references; default is no prefix
path-prefix: "" path-prefix: ""
# all available settings of specific linters
linters-settings:
dogsled:
# checks assignments with too many blank identifiers; default is 2
max-blank-identifiers: 2
dupl:
# tokens count to trigger issue, 150 by default
threshold: 100
errcheck:
# report about not checking of errors in type assertions: `a := b.(MyStruct)`;
# default is false: such cases aren't reported by default.
check-type-assertions: false
# report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
# default is false: such cases aren't reported by default.
check-blank: false
# [deprecated] comma-separated list of pairs of the form pkg:regex
# the regex is used to ignore names within pkg. (default "fmt:.*").
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
ignore: fmt:.*,io/ioutil:^Read.*
# path to a file containing a list of functions to exclude from checking
# see https://github.com/kisielk/errcheck#excluding-functions for details
# exclude: /path/to/file.txt
exhaustive:
# indicates that switch statements are to be considered exhaustive if a
# 'default' case is present, even if all enum members aren't listed in the
# switch
default-signifies-exhaustive: false
funlen:
lines: 1000
statements: 100
gocognit:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 50
nestif:
# minimal complexity of if statements to report, 5 by default
min-complexity: 4
goconst:
# minimal length of string constant, 3 by default
min-len: 3
# minimal occurrences count to trigger, 3 by default
min-occurrences: 3
gocritic:
# Which checks should be enabled; can't be combined with 'disabled-checks';
# See https://go-critic.github.io/overview#checks-overview
# To check which checks are enabled run `GL_DEBUG=gocritic golangci-lint run`
# By default list of stable checks is used.
# enabled-checks:
# - rangeValCopy
# Which checks should be disabled; can't be combined with 'enabled-checks'; default is empty
disabled-checks:
- regexpMust
# Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint run` to see all tags and checks.
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
enabled-tags:
- performance
disabled-tags:
- experimental
settings: # settings passed to gocritic
captLocal: # must be valid enabled check name
paramsOnly: true
rangeValCopy:
sizeThreshold: 32
gocyclo:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 50
godot:
# check all top-level comments, not only declarations
check-all: false
godox:
# report any comments starting with keywords, this is useful for TODO or FIXME comments that
# might be left in the code accidentally and should be resolved before merging
keywords: # default keywords are TODO, BUG, and FIXME, these can be overwritten by this setting
- NOTE
- OPTIMIZE # marks code that should be optimized before merging
- HACK # marks hack-arounds that should be removed before merging
gofmt:
# simplify code: gofmt with `-s` option, true by default
simplify: true
goheader:
values:
const:
# define here const type values in format k:v, for example:
# YEAR: 2020
# COMPANY: MY COMPANY
regexp:
# define here regexp type values, for example
# AUTHOR: .*@mycompany\.com
template:
# put here copyright header template for source code files, for example:
# {{ AUTHOR }} {{ COMPANY }} {{ YEAR }}
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
template-path:
# also as alternative of directive 'template' you may put the path to file with the template source
goimports:
# put imports beginning with prefix after 3rd-party packages;
# it's a comma-separated list of prefixes
local-prefixes: github.com/org/project
golint:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
gomnd:
settings:
mnd:
# the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description.
checks: argument,case,condition,operation,return,assign
gomodguard:
allowed:
modules: # List of allowed modules
# - gopkg.in/yaml.v2
domains: # List of allowed module domains
# - golang.org
blocked:
modules: # List of blocked modules
# - github.com/uudashr/go-module: # Blocked module
# recommendations: # Recommended modules that should be used instead (Optional)
# - golang.org/x/mod
# reason: "`mod` is the official go.mod parser library." # Reason why the recommended module should be used (Optional)
versions: # List of blocked module version constraints
# - github.com/mitchellh/go-homedir: # Blocked module with version constraint
# version: "< 1.1.0" # Version constraint, see https://github.com/Masterminds/semver#basic-comparisons
# reason: "testing if blocked version constraint works." # Reason why the version constraint exists. (Optional)
govet:
# report about shadowed variables
check-shadowing: true
# settings per analyzer
settings:
printf: # analyzer name, run `go tool vet help` to see all analyzers
funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
# enable or disable analyzers by name
enable:
- atomicalign
enable-all: false
disable:
- shadow
disable-all: false
depguard:
list-type: blacklist
include-go-root: false
packages:
# - github.com/sirupsen/logrus
packages-with-error-message:
# specify an error message to output when a blacklisted package is used
# - github.com/sirupsen/logrus: "logging is allowed only by logutils.Log"
lll:
# max line length, lines longer will be reported. Default is 120.
# '\t' is counted as 1 character by default, and can be changed with the tab-width option
line-length: 240
# tab width in spaces. Default to 1.
tab-width: 1
maligned:
# print struct with more effective memory layout or not, false by default
suggest-new: true
misspell:
# Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: US
ignore-words:
- someword
nakedret:
# make an issue if func has more lines of code than this setting and it has naked returns; default is 30
max-func-lines: 30
prealloc:
# XXX: we don't recommend using this linter before doing performance profiling.
# For most programs usage of prealloc will be a premature optimization.
# Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.
# True by default.
simple: true
range-loops: true # Report preallocation suggestions on range loops, true by default
for-loops: false # Report preallocation suggestions on for loops, false by default
nolintlint:
# Enable to ensure that nolint directives are all used. Default is true.
allow-unused: false
# Disable to ensure that nolint directives don't have a leading space. Default is true.
allow-leading-space: true
# Exclude following linters from requiring an explanation. Default is [].
allow-no-explanation: []
# Enable to require an explanation of nonzero length after each nolint directive. Default is false.
require-explanation: true
# Enable to require nolint directives to mention the specific linter being suppressed. Default is false.
require-specific: true
rowserrcheck:
packages:
- github.com/jmoiron/sqlx
testpackage:
# regexp pattern to skip files
skip-regexp: (export|internal)_test\.go
unparam:
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
unused:
# treat code as a program (not a library) and report unused exported identifiers; default is false.
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
whitespace:
multi-if: false # Enforces newlines (or comments) after every multi-line if statement
multi-func: false # Enforces newlines (or comments) after every multi-line function signature
wsl:
# If true append is only allowed to be cuddled if appending value is
# matching variables, fields or types on line above. Default is true.
strict-append: true
# Allow calls and assignments to be cuddled as long as the lines have any
# matching variables, fields or types. Default is true.
allow-assign-and-call: true
# Allow multiline assignments to be cuddled. Default is true.
allow-multiline-assign: true
# Allow declarations (var) to be cuddled.
allow-cuddle-declarations: true
# Allow trailing comments in ending of blocks
allow-trailing-comment: false
# Force newlines in end of case at this limit (0 = never).
force-case-trailing-whitespace: 0
# Force cuddling of err checks with err var assignment
force-err-cuddling: false
# Allow leading comments to be separated with empty liens
allow-separated-leading-comment: false
gofumpt:
# Choose whether or not to use the extra rules that are disabled
# by default
extra-rules: false
# The custom section can be used to define linter plugins to be loaded at runtime. See README doc
# for more info.
#custom:
# Each custom linter should have a unique name.
#example:
# The path to the plugin *.so. Can be absolute or local. Required for each custom linter
#path: /path/to/example.so
# The description of the linter. Optional, just for documentation purposes.
#description: This is an example usage of a plugin linter.
# Intended to point to the repo location of the linter. Optional, just for documentation purposes.
#original-url: github.com/golangci/example-linter
linters:
fast: false
enable-all: true
disable:
- gochecknoinits
- gochecknoglobals
- wsl
- golint
- gocritic
- stylecheck
- whitespace
- gofumpt
- nestif
- nolintlint
- nlreturn
issues:
# List of regexps of issue texts to exclude, empty list by default.
# But independently from this option we use default exclude patterns,
# it can be disabled by `exclude-use-default: false`. To list all
# excluded by default patterns execute `golangci-lint run --help`
exclude:
- .*test.*\.go
# Excluding configuration per-path, per-linter, per-text and per-source
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
# Exclude known linters from partially hard-vendored code,
# which is impossible to exclude via "nolint" comments.
- path: internal/hmac/
text: "weak cryptographic primitive"
linters:
- gosec
# Exclude some staticcheck messages
- linters:
- staticcheck
text: "SA9003:"
# Exclude lll issues for long lines with go:generate
- linters:
- lll
source: "^//go:generate "
# Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`.
# Default value for this option is true.
exclude-use-default: false
# The default value is false. If set to true exclude and exclude-rules
# regular expressions become case sensitive.
exclude-case-sensitive: false
# The list of ids of default excludes to include or disable. By default it's empty.
include:
- EXC0002 # disable excluding of issues about comments from golint
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
max-issues-per-linter: 0
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
max-same-issues: 0
# Show only new issues: if there are unstaged changes or untracked files,
# only those changes are analyzed, else only changes in HEAD~ are analyzed.
# It's a super-useful option for integration of golangci-lint into existing
# large codebase. It's not practical to fix all existing issues at the moment
# of integration: much better don't allow issues in new code.
# Default is false.
new: false
# Show only new issues created after git revision `REV`
#new-from-rev: REV
# Show only new issues created in git patch with set file path.
#new-from-patch: path/to/patch/file
severity:
# Default value is empty string.
# Set the default severity for issues. If severity rules are defined and the issues
# do not match or no severity is provided to the rule this will be the default
# severity applied. Severities should match the supported severity names of the
# selected out format.
# - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity
# - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity
# - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message
default-severity: error
# The default value is false.
# If set to true severity-rules regular expressions become case sensitive.
case-sensitive: false
# Default value is empty list.
# When a list of severity rules are provided, severity information will be added to lint
# issues. Severity rules have the same filtering capability as exclude rules except you
# are allowed to specify one matcher per severity rule.
# Only affects out formats that support setting severity information.
rules:
- linters:
- dupl
severity: info

View File

@@ -43,11 +43,9 @@ import (
type ArchiveType uint8 type ArchiveType uint8
const ( const (
ArchiveTypeUnknown = iota TypeTar = iota + 1
ArchiveTypeZip TypeTarGzip
ArchiveTypeTar TypeGzip
ArchiveTypeTarGzip
ArchiveTypeGzip
) )
func ExtractFile(src, dst libiot.FileProgress, fileNameContain, fileNameRegex string) liberr.Error { func ExtractFile(src, dst libiot.FileProgress, fileNameContain, fileNameRegex string) liberr.Error {
@@ -204,15 +202,16 @@ func ExtractAll(src libiot.FileProgress, originalName, outputPath string, defaul
func CreateArchive(archiveType ArchiveType, archive libiot.FileProgress, pathContent ...string) (created bool, err liberr.Error) { func CreateArchive(archiveType ArchiveType, archive libiot.FileProgress, pathContent ...string) (created bool, err liberr.Error) {
//@TODO: make function //@TODO: make function
if len(pathContent) < 1 { if len(pathContent) < 1 {
//nolint #goerr113
return false, ErrorParamsEmpty.ErrorParent(fmt.Errorf("pathContent is empty")) return false, ErrorParamsEmpty.ErrorParent(fmt.Errorf("pathContent is empty"))
} }
switch archiveType { switch archiveType {
case ArchiveTypeGzip: case TypeGzip:
return libgzp.Create(archive, pathContent...) return libgzp.Create(archive, pathContent...)
case ArchiveTypeTar: case TypeTar:
return libtar.Create(archive, pathContent...) return libtar.Create(archive, pathContent...)
case ArchiveTypeTarGzip: case TypeTarGzip:
return libtar.CreateGzip(archive, pathContent...) return libtar.CreateGzip(archive, pathContent...)
} }

View File

@@ -34,10 +34,9 @@ import (
"os" "os"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
libiot "github.com/nabbar/golib/ioutils"
) )
func Create(archive libiot.FileProgress, content ...string) (bool, liberr.Error) { func Create(archive io.WriteSeeker, content ...string) (bool, liberr.Error) {
var ( var (
w *gzip.Writer w *gzip.Writer
f *os.File f *os.File
@@ -46,6 +45,7 @@ func Create(archive libiot.FileProgress, content ...string) (bool, liberr.Error)
) )
if len(content) != 1 { if len(content) != 1 {
//nolint #goerr113
return false, ErrorParamsMismatching.ErrorParent(fmt.Errorf("content path must be limited to strictly one contents")) return false, ErrorParamsMismatching.ErrorParent(fmt.Errorf("content path must be limited to strictly one contents"))
} }

View File

@@ -36,185 +36,125 @@ import (
"path/filepath" "path/filepath"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
libiot "github.com/nabbar/golib/ioutils"
) )
func Create(archive libiot.FileProgress, content ...string) (bool, liberr.Error) { func Create(archive io.WriteSeeker, content ...string) (bool, liberr.Error) {
var ( if _, err := archive.Seek(0, io.SeekStart); err != nil {
t *tar.Writer
n int64
err error
lEr = ErrorTarCreateAddFile.Error(nil)
)
if _, err = archive.Seek(0, io.SeekStart); err != nil {
return false, ErrorFileSeek.ErrorParent(err) return false, ErrorFileSeek.ErrorParent(err)
} }
t = tar.NewWriter(archive) if ok, err := createTar(archive, content...); err != nil || !ok {
return ok, err
for i := 0; i < len(content); i++ {
if content[i] == "" {
continue
}
err = filepath.Walk(content[i], func(file string, inf os.FileInfo, err error) error {
var (
e error
h *tar.Header
f *os.File
)
// generate tar header
h, e = tar.FileInfoHeader(inf, file)
if e != nil {
return e
}
// must provide real name
// (see https://golang.org/src/archive/tar/common.go?#L626)
h.Name = filepath.ToSlash(file)
// write header
if e = t.WriteHeader(h); err != nil {
return err
}
// if not a dir, write file content
if !inf.IsDir() {
f, e = os.Open(file)
if e != nil {
return e
}
if _, e = io.Copy(t, f); e != nil {
return e
}
}
n++
return nil
})
if err != nil {
lEr.AddParent(err)
continue
}
} }
if n < 1 { if _, err := archive.Seek(0, io.SeekStart); err != nil {
if lEr.HasParent() {
return false, lEr
}
return false, ErrorTarCreate.ErrorParent(fmt.Errorf("no file to add in archive"))
} else if !lEr.HasParent() {
lEr = nil
}
if err = t.Close(); err != nil {
return false, ErrorTarCreate.ErrorParent(err)
}
if _, err = archive.Seek(0, io.SeekStart); err != nil {
return false, ErrorFileSeek.ErrorParent(err) return false, ErrorFileSeek.ErrorParent(err)
} }
return true, lEr return true, nil
} }
func CreateGzip(archive libiot.FileProgress, content ...string) (bool, liberr.Error) { func CreateGzip(archive io.WriteSeeker, content ...string) (bool, liberr.Error) {
var ( if _, err := archive.Seek(0, io.SeekStart); err != nil {
z *gzip.Writer
t *tar.Writer
n int64
err error
lEr = ErrorTarCreateAddFile.Error(nil)
)
if _, err = archive.Seek(0, io.SeekStart); err != nil {
return false, ErrorFileSeek.ErrorParent(err) return false, ErrorFileSeek.ErrorParent(err)
} }
z = gzip.NewWriter(archive) z := gzip.NewWriter(archive)
t = tar.NewWriter(z)
for i := 0; i < len(content); i++ { if ok, err := createTar(z, content...); err != nil || !ok {
if content[i] == "" { return ok, err
continue
}
err = filepath.Walk(content[i], func(file string, inf os.FileInfo, err error) error {
var (
e error
h *tar.Header
f *os.File
)
// generate tar header
h, e = tar.FileInfoHeader(inf, file)
if e != nil {
return e
}
// must provide real name
// (see https://golang.org/src/archive/tar/common.go?#L626)
h.Name = filepath.ToSlash(file)
// write header
if e = t.WriteHeader(h); err != nil {
return err
}
// if not a dir, write file content
if !inf.IsDir() {
f, e = os.Open(file)
if e != nil {
return e
}
if _, e = io.Copy(t, f); e != nil {
return e
}
}
n++
return nil
})
if err != nil {
lEr.AddParent(err)
continue
}
} }
if n < 1 { if err := z.Close(); err != nil {
if lEr.HasParent() {
return false, lEr
}
return false, ErrorTarCreate.ErrorParent(fmt.Errorf("no file to add in archive"))
} else if !lEr.HasParent() {
lEr = nil
}
if err = t.Close(); err != nil {
return false, ErrorTarCreate.ErrorParent(err)
}
if err = z.Close(); err != nil {
return false, ErrorGzipCreate.ErrorParent(err) return false, ErrorGzipCreate.ErrorParent(err)
} }
if _, err = archive.Seek(0, io.SeekStart); err != nil { if _, err := archive.Seek(0, io.SeekStart); err != nil {
return false, ErrorFileSeek.ErrorParent(err) return false, ErrorFileSeek.ErrorParent(err)
} }
return true, nil
}
func createTar(w io.Writer, content ...string) (bool, liberr.Error) {
var (
t *tar.Writer
n int64
err error
lEr = ErrorTarCreateAddFile.Error(nil)
)
t = tar.NewWriter(w)
for i := 0; i < len(content); i++ {
if content[i] == "" {
continue
}
err = filepath.Walk(content[i], func(file string, inf os.FileInfo, err error) error {
var (
e error
h *tar.Header
f *os.File
)
// generate tar header
h, e = tar.FileInfoHeader(inf, file)
if e != nil {
return e
}
// must provide real name
// (see https://golang.org/src/archive/tar/common.go?#L626)
h.Name = filepath.ToSlash(file)
// write header
if e = t.WriteHeader(h); e != nil {
return e
}
// if not a dir, write file content
if !inf.IsDir() {
//nolint #gosec
/* #nosec */
f, e = os.Open(file)
if e != nil {
return e
}
if _, e = io.Copy(t, f); e != nil {
return e
}
}
n++
return nil
})
if err != nil {
lEr.AddParent(err)
continue
}
}
if n < 1 {
if lEr.HasParent() {
return false, lEr
}
//nolint #goerr113
return false, ErrorTarCreate.ErrorParent(fmt.Errorf("no file to add in archive"))
} else if !lEr.HasParent() {
lEr = nil
}
if err = t.Close(); err != nil {
return false, ErrorTarCreate.ErrorParent(err)
}
return true, lEr return true, lEr
} }

View File

@@ -107,23 +107,14 @@ func (a *artifactoryModel) request(uri string, bodyResponse interface{}) liberr.
u *url.URL u *url.URL
) )
//ctx, cnl = context.WithTimeout(a.ctx, libhtc.TIMEOUT_5_SEC)
ctx, cnl = context.WithCancel(a.ctx)
defer func() { defer func() {
if cnl != nil { if cnl != nil {
cnl() cnl()
} }
if rsp != nil && rsp.Body != nil {
_ = rsp.Body.Close()
}
if req != nil && req.Body != nil {
_ = req.Body.Close()
}
}() }()
//ctx, cnl = context.WithTimeout(a.ctx, libhtc.TIMEOUT_5_SEC)
ctx, cnl = context.WithCancel(a.ctx)
u = &url.URL{ u = &url.URL{
Scheme: a.endpoint.Scheme, Scheme: a.endpoint.Scheme,
Opaque: a.endpoint.Opaque, Opaque: a.endpoint.Opaque,
@@ -149,15 +140,29 @@ func (a *artifactoryModel) request(uri string, bodyResponse interface{}) liberr.
return ErrorRequestInit.ErrorParent(e) return ErrorRequestInit.ErrorParent(e)
} }
defer func() {
if req != nil && req.Body != nil {
_ = req.Body.Close()
}
}()
if rsp, e = a.Do(req); e != nil { if rsp, e = a.Do(req); e != nil {
return ErrorRequestDo.ErrorParent(e) return ErrorRequestDo.ErrorParent(e)
} }
if rsp.StatusCode >= 400 { defer func() {
if rsp != nil && rsp.Body != nil {
_ = rsp.Body.Close()
}
}()
if rsp.StatusCode >= http.StatusBadRequest {
//nolint #goerr113
return ErrorRequestResponse.ErrorParent(fmt.Errorf("status: %v", rsp.Status)) return ErrorRequestResponse.ErrorParent(fmt.Errorf("status: %v", rsp.Status))
} }
if rsp.Body == nil { if rsp.Body == nil {
//nolint #goerr113
return ErrorRequestResponseBodyEmpty.ErrorParent(fmt.Errorf("status: %v", rsp.Status)) return ErrorRequestResponseBodyEmpty.ErrorParent(fmt.Errorf("status: %v", rsp.Status))
} }
@@ -181,10 +186,12 @@ func (a *artifactoryModel) getStorageList() (sto []ResponseStorage, err liberr.E
) )
if a.regex == "" { if a.regex == "" {
//nolint #goerr113
return nil, ErrorParamsEmpty.ErrorParent(fmt.Errorf("regex is empty: %s", a.regex)) return nil, ErrorParamsEmpty.ErrorParent(fmt.Errorf("regex is empty: %s", a.regex))
} }
if a.group < 1 { if a.group < 1 {
//nolint #goerr113
return nil, ErrorParamsEmpty.ErrorParent(fmt.Errorf("group extracted from regex is empty: %s - %v", a.regex, a.group)) return nil, ErrorParamsEmpty.ErrorParent(fmt.Errorf("group extracted from regex is empty: %s - %v", a.regex, a.group))
} }
@@ -342,9 +349,11 @@ func (a *artifactoryModel) Download(dst libiot.FileProgress, containName string,
return ErrorRequestInit.ErrorParent(e) return ErrorRequestInit.ErrorParent(e)
} else if rsp, e = a.Do(req); e != nil { } else if rsp, e = a.Do(req); e != nil {
return ErrorRequestDo.ErrorParent(e) return ErrorRequestDo.ErrorParent(e)
} else if rsp.StatusCode >= 400 { } else if rsp.StatusCode >= http.StatusBadRequest {
//nolint #goerr113
return ErrorRequestResponse.ErrorParent(fmt.Errorf("status: %v", rsp.Status)) return ErrorRequestResponse.ErrorParent(fmt.Errorf("status: %v", rsp.Status))
} else if rsp.Body == nil { } else if rsp.Body == nil {
//nolint #goerr113
return ErrorRequestResponseBodyEmpty.ErrorParent(fmt.Errorf("status: %v", rsp.Status)) return ErrorRequestResponseBodyEmpty.ErrorParent(fmt.Errorf("status: %v", rsp.Status))
} else if _, e := dst.ReadFrom(rsp.Body); e != nil { } else if _, e := dst.ReadFrom(rsp.Body); e != nil {
return ErrorArtifactoryDownload.ErrorParent(e) return ErrorArtifactoryDownload.ErrorParent(e)

View File

@@ -71,8 +71,6 @@ func TestGolibAwsHelper(t *testing.T) {
RunSpecs(t, "Aws Helper Suite") RunSpecs(t, "Aws Helper Suite")
} }
const testRegion = "us-east-1"
var _ = BeforeSuite(func() { var _ = BeforeSuite(func() {
var ( var (
err error err error

View File

@@ -226,7 +226,7 @@ func (c *awsModel) ResolveEndpoint(service, region string) (sdkaws.Endpoint, err
}, nil }, nil
} }
logger.DebugLevel.Logf("Called ResolveEndpoint for service / region '%s' with nil endpoint", service, region) logger.DebugLevel.Logf("Called ResolveEndpoint for service '%s' / region '%s' with nil endpoint", service, region)
return sdkaws.Endpoint{}, ErrorEndpointInvalid.Error(nil) return sdkaws.Endpoint{}, ErrorEndpointInvalid.Error(nil)
} }

View File

@@ -26,10 +26,13 @@
package object package object
import ( import (
//nolint #nosec
/* #nosec */ /* #nosec */
"crypto/md5" "crypto/md5"
"encoding/base64" "encoding/base64"
"io" "io"
//nolint #gci
"os" "os"
sdkaws "github.com/aws/aws-sdk-go-v2/aws" sdkaws "github.com/aws/aws-sdk-go-v2/aws"
@@ -101,8 +104,8 @@ func (cli *client) MultipartPutCustom(partSize libhlp.PartSize, object string, b
/* #nosec */ /* #nosec */
h := md5.New() h := md5.New()
if _, err := tmp.WriteTo(h); err != nil { if _, e := tmp.WriteTo(h); e != nil {
return cli.multipartCancel(err, upl.UploadId, object) return cli.multipartCancel(e, upl.UploadId, object)
} }
_, err = tmp.Seek(0, io.SeekStart) _, err = tmp.Seek(0, io.SeekStart)

View File

@@ -42,6 +42,7 @@ const maxItemList int32 = 1000
func (cli *client) VersionList(arn string, maxItem int32) (map[string]string, liberr.Error) { func (cli *client) VersionList(arn string, maxItem int32) (map[string]string, liberr.Error) {
if arn == "" { if arn == "" {
//nolint #goerr113
return nil, libhlp.ErrorParamsEmpty.ErrorParent(fmt.Errorf("arn is empty")) return nil, libhlp.ErrorParamsEmpty.ErrorParent(fmt.Errorf("arn is empty"))
} }
@@ -51,7 +52,7 @@ func (cli *client) VersionList(arn string, maxItem int32) (map[string]string, li
var ( var (
marker = "" marker = ""
res = make(map[string]string, 0) res = make(map[string]string)
) )
for { for {

View File

@@ -39,12 +39,6 @@ type Certif struct {
} }
type Config struct { type Config struct {
InheritDefault bool `mapstructure:"inheritDefault" json:"inheritDefault" yaml:"inheritDefault" toml:"inheritDefault"`
VersionMin string `mapstructure:"versionMin" json:"versionMin" yaml:"versionMin" toml:"versionMin"`
VersionMax string `mapstructure:"versionMax" json:"versionMax" yaml:"versionMax" toml:"versionMax"`
DynmaicSizingDisable bool `mapstructure:"dynamicSizingDisable" json:"dynamicSizingDisable" yaml:"dynamicSizingDisable" toml:"dynamicSizingDisable"`
SessionTicketDisable bool `mapstructure:"sessionTicketDisable" json:"sessionTicketDisable" yaml:"sessionTicketDisable" toml:"sessionTicketDisable"`
AuthClient string `mapstructure:"authClient" json:"authClient" yaml:"authClient" toml:"authClient"`
CurveList []string `mapstructure:"curveList" json:"curveList" yaml:"curveList" toml:"curveList"` CurveList []string `mapstructure:"curveList" json:"curveList" yaml:"curveList" toml:"curveList"`
CipherList []string `mapstructure:"cipherList" json:"cipherList" yaml:"cipherList" toml:"cipherList"` CipherList []string `mapstructure:"cipherList" json:"cipherList" yaml:"cipherList" toml:"cipherList"`
RootCAString []string `mapstructure:"rootCA" json:"rootCA" yaml:"rootCA" toml:"rootCA"` RootCAString []string `mapstructure:"rootCA" json:"rootCA" yaml:"rootCA" toml:"rootCA"`
@@ -53,6 +47,12 @@ type Config struct {
ClientCAFiles []string `mapstructure:"clientCAFiles" json:"clientCAFiles" yaml:"clientCAFiles" toml:"clientCAFiles"` ClientCAFiles []string `mapstructure:"clientCAFiles" json:"clientCAFiles" yaml:"clientCAFiles" toml:"clientCAFiles"`
CertPairString []Certif `mapstructure:"certPair" json:"certPair" yaml:"certPair" toml:"certPair"` CertPairString []Certif `mapstructure:"certPair" json:"certPair" yaml:"certPair" toml:"certPair"`
CertPairFile []Certif `mapstructure:"certPairFiles" json:"certPairFiles" yaml:"certPairFiles" toml:"certPairFiles"` CertPairFile []Certif `mapstructure:"certPairFiles" json:"certPairFiles" yaml:"certPairFiles" toml:"certPairFiles"`
VersionMin string `mapstructure:"versionMin" json:"versionMin" yaml:"versionMin" toml:"versionMin"`
VersionMax string `mapstructure:"versionMax" json:"versionMax" yaml:"versionMax" toml:"versionMax"`
AuthClient string `mapstructure:"authClient" json:"authClient" yaml:"authClient" toml:"authClient"`
InheritDefault bool `mapstructure:"inheritDefault" json:"inheritDefault" yaml:"inheritDefault" toml:"inheritDefault"`
DynamicSizingDisable bool `mapstructure:"dynamicSizingDisable" json:"dynamicSizingDisable" yaml:"dynamicSizingDisable" toml:"dynamicSizingDisable"`
SessionTicketDisable bool `mapstructure:"sessionTicketDisable" json:"sessionTicketDisable" yaml:"sessionTicketDisable" toml:"sessionTicketDisable"`
} }
func (c *Config) Validate() liberr.Error { func (c *Config) Validate() liberr.Error {
@@ -64,6 +64,7 @@ func (c *Config) Validate() liberr.Error {
} }
for _, err := range err.(valid.ValidationErrors) { for _, err := range err.(valid.ValidationErrors) {
//nolint #goerr113
e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", err.StructNamespace(), err.ActualTag())) e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", err.StructNamespace(), err.ActualTag()))
} }
} }
@@ -83,6 +84,7 @@ func (c *Config) New() (TLSConfig, liberr.Error) {
} }
} }
//nolint #gocognit
func (c *Config) NewFrom(cfg TLSConfig) (TLSConfig, liberr.Error) { func (c *Config) NewFrom(cfg TLSConfig) (TLSConfig, liberr.Error) {
var t *config var t *config
@@ -103,7 +105,7 @@ func (c *Config) NewFrom(cfg TLSConfig) (TLSConfig, liberr.Error) {
t.tlsMaxVersion = StringToTlsVersion(c.VersionMax) t.tlsMaxVersion = StringToTlsVersion(c.VersionMax)
} }
if c.DynmaicSizingDisable { if c.DynamicSizingDisable {
t.dynSizingDisabled = true t.dynSizingDisabled = true
} }

View File

@@ -80,47 +80,47 @@ func New() TLSConfig {
} }
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func AddRootCAContents(rootContent string) bool { func AddRootCAContents(rootContent string) bool {
return Default.AddRootCAString(rootContent) return Default.AddRootCAString(rootContent)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func AddRootCAFile(rootFile string) liberr.Error { func AddRootCAFile(rootFile string) liberr.Error {
return Default.AddRootCAFile(rootFile) return Default.AddRootCAFile(rootFile)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func AddCACertificateContents(caContent string) bool { func AddCACertificateContents(caContent string) bool {
return Default.AddClientCAString(caContent) return Default.AddClientCAString(caContent)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func AddCACertificateFile(caFile string) liberr.Error { func AddCACertificateFile(caFile string) liberr.Error {
return Default.AddClientCAFile(caFile) return Default.AddClientCAFile(caFile)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func AddCertificatePairString(key, crt string) liberr.Error { func AddCertificatePairString(key, crt string) liberr.Error {
return Default.AddCertificatePairString(key, crt) return Default.AddCertificatePairString(key, crt)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func AddCertificatePairFile(keyFile, crtFile string) liberr.Error { func AddCertificatePairFile(keyFile, crtFile string) liberr.Error {
return Default.AddCertificatePairFile(keyFile, crtFile) return Default.AddCertificatePairFile(keyFile, crtFile)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func CheckCertificates() bool { func CheckCertificates() bool {
return Default.LenCertificatePair() > 0 return Default.LenCertificatePair() > 0
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func GetCertificates() []tls.Certificate { func GetCertificates() []tls.Certificate {
return Default.GetCertificatePair() return Default.GetCertificatePair()
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func AppendCertificates(cert []tls.Certificate) []tls.Certificate { func AppendCertificates(cert []tls.Certificate) []tls.Certificate {
if !CheckCertificates() { if !CheckCertificates() {
return cert return cert
@@ -129,67 +129,67 @@ func AppendCertificates(cert []tls.Certificate) []tls.Certificate {
return append(cert, GetCertificates()...) return append(cert, GetCertificates()...)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func GetRootCA() *x509.CertPool { func GetRootCA() *x509.CertPool {
return Default.GetRootCA() return Default.GetRootCA()
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func GetClientCA() *x509.CertPool { func GetClientCA() *x509.CertPool {
return Default.GetClientCA() return Default.GetClientCA()
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func SetVersionMin(vers uint16) { func SetVersionMin(vers uint16) {
Default.SetVersionMin(vers) Default.SetVersionMin(vers)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func SetVersionMax(vers uint16) { func SetVersionMax(vers uint16) {
Default.SetVersionMax(vers) Default.SetVersionMax(vers)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func SetClientAuth(auth string) { func SetClientAuth(auth string) {
Default.SetClientAuth(StringToClientAuth(auth)) Default.SetClientAuth(StringToClientAuth(auth))
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func SetCipherList(cipher []uint16) { func SetCipherList(cipher []uint16) {
Default.SetCipherList(cipher) Default.SetCipherList(cipher)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func SetCurve(curves []tls.CurveID) { func SetCurve(curves []tls.CurveID) {
Default.SetCurveList(curves) Default.SetCurveList(curves)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func SetDynamicSizing(enable bool) { func SetDynamicSizing(enable bool) {
Default.SetDynamicSizingDisabled(!enable) Default.SetDynamicSizingDisabled(!enable)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func SetSessionTicket(enable bool) { func SetSessionTicket(enable bool) {
Default.SetSessionTicketDisabled(!enable) Default.SetSessionTicketDisabled(!enable)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func GetTLSConfig(serverName string) *tls.Config { func GetTLSConfig(serverName string) *tls.Config {
return Default.TlsConfig(serverName) return Default.TlsConfig(serverName)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func GetTlsConfigCertificates() *tls.Config { func GetTlsConfigCertificates() *tls.Config {
return Default.TlsConfig("") return Default.TlsConfig("")
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func AddCertificateContents(keyContents, certContents string) liberr.Error { func AddCertificateContents(keyContents, certContents string) liberr.Error {
return Default.AddCertificatePairString(keyContents, certContents) return Default.AddCertificatePairString(keyContents, certContents)
} }
// Deprecated: use local config and no more globals default config // Deprecated: use local config and no more globals default config.
func AddCertificateFile(keyFile, certFile string) liberr.Error { func AddCertificateFile(keyFile, certFile string) liberr.Error {
return Default.AddCertificatePairFile(keyFile, certFile) return Default.AddCertificatePairFile(keyFile, certFile)
} }

View File

@@ -38,20 +38,16 @@ import (
) )
type config struct { type config struct {
caRoot *x509.CertPool cert []tls.Certificate
cert []tls.Certificate cipherList []uint16
curveList []tls.CurveID
tlsMinVersion uint16 caRoot *x509.CertPool
tlsMaxVersion uint16 clientAuth tls.ClientAuthType
clientCA *x509.CertPool
cipherList []uint16 tlsMinVersion uint16
curveList []tls.CurveID tlsMaxVersion uint16
dynSizingDisabled bool dynSizingDisabled bool
ticketSessionDisabled bool ticketSessionDisabled bool
clientAuth tls.ClientAuthType
clientCA *x509.CertPool
} }
func (c *config) checkFile(pemFiles ...string) liberr.Error { func (c *config) checkFile(pemFiles ...string) liberr.Error {
@@ -248,12 +244,7 @@ func (c *config) cloneCipherList() []uint16 {
return nil return nil
} }
list := make([]uint16, 0) return append(make([]uint16, 0), c.cipherList...)
for _, v := range c.cipherList {
list = append(list, v)
}
return list
} }
func (c *config) cloneCurveList() []tls.CurveID { func (c *config) cloneCurveList() []tls.CurveID {
@@ -261,12 +252,7 @@ func (c *config) cloneCurveList() []tls.CurveID {
return nil return nil
} }
list := make([]tls.CurveID, 0) return append(make([]tls.CurveID, 0), c.curveList...)
for _, v := range c.curveList {
list = append(list, v)
}
return list
} }
func (c *config) cloneCertificates() []tls.Certificate { func (c *config) cloneCertificates() []tls.Certificate {
@@ -274,12 +260,7 @@ func (c *config) cloneCertificates() []tls.Certificate {
return nil return nil
} }
list := make([]tls.Certificate, 0) return append(make([]tls.Certificate, 0), c.cert...)
for _, v := range c.cert {
list = append(list, v)
}
return list
} }
func (c *config) cloneRootCA() *x509.CertPool { func (c *config) cloneRootCA() *x509.CertPool {

View File

@@ -33,12 +33,12 @@ import (
"strings" "strings"
) )
// Deprecated: use StringToCipherKey // Deprecated: use StringToCipherKey.
func GetCipherKey(cipher string) uint16 { func GetCipherKey(cipher string) uint16 {
return StringToCipherKey(cipher) return StringToCipherKey(cipher)
} }
// Deprecated: use StringToCurveID // Deprecated: use StringToCurveID.
func GetCurveID(curveRef string) tls.CurveID { func GetCurveID(curveRef string) tls.CurveID {
return StringToCurveID(curveRef) return StringToCurveID(curveRef)
} }

View File

@@ -223,6 +223,7 @@ func (c ConfigCluster) GetDGBConfigCluster() dgbcfg.Config {
d.Quiesce = true d.Quiesce = true
} }
//nolint #exhaustive
switch c.SnapshotCompressionType { switch c.SnapshotCompressionType {
case dgbcfg.Snappy: case dgbcfg.Snappy:
d.SnapshotCompressionType = dgbcfg.Snappy d.SnapshotCompressionType = dgbcfg.Snappy
@@ -230,6 +231,7 @@ func (c ConfigCluster) GetDGBConfigCluster() dgbcfg.Config {
d.SnapshotCompressionType = dgbcfg.NoCompression d.SnapshotCompressionType = dgbcfg.NoCompression
} }
//nolint #exhaustive
switch c.EntryCompressionType { switch c.EntryCompressionType {
case dgbcfg.Snappy: case dgbcfg.Snappy:
d.EntryCompressionType = dgbcfg.Snappy d.EntryCompressionType = dgbcfg.Snappy

View File

@@ -33,7 +33,7 @@ import (
"strconv" "strconv"
"syscall" "syscall"
"golang.org/x/crypto/ssh/terminal" "golang.org/x/term"
) )
func printPrompt(text string) { func printPrompt(text string) {
@@ -87,7 +87,7 @@ func PromptBool(text string) (bool, error) {
func PromptPassword(text string) (string, error) { func PromptPassword(text string) (string, error) {
printPrompt(text) printPrompt(text)
//nolint #unconvert //nolint #unconvert
res, err := terminal.ReadPassword(int(syscall.Stdin)) res, err := term.ReadPassword(int(syscall.Stdin))
fmt.Printf("\n") fmt.Printf("\n")
return string(res), err return string(res), err

View File

@@ -36,39 +36,43 @@ type Config interface {
Store(key string, cfg interface{}) Store(key string, cfg interface{})
Load(key string) interface{} Load(key string) interface{}
ObjectStore(key string, obj interface{})
ObjectLoad(key string) interface{}
} }
func NewConfig(ctx context.Context) Config { func NewConfig(ctx context.Context) Config {
return &configContext{ return &configContext{
Context: ctx, Context: ctx,
cfg: &atomic.Value{}, cfg: new(atomic.Value),
obj: &atomic.Value{},
} }
} }
type configContext struct { type configContext struct {
context.Context context.Context
cfg *atomic.Value cfg *atomic.Value
obj *atomic.Value
} }
func (c *configContext) Store(key string, cfg interface{}) { func (c configContext) getMap() map[string]*atomic.Value {
var ( var (
v interface{} v interface{}
s map[string]*atomic.Value s map[string]*atomic.Value
ok bool ok bool
) )
if v = c.cfg.Load(); v == nil { if c.cfg == nil {
s = make(map[string]*atomic.Value, 0) c.cfg = new(atomic.Value)
} else if v = c.cfg.Load(); v == nil {
s = make(map[string]*atomic.Value)
} else if s, ok = v.(map[string]*atomic.Value); !ok { } else if s, ok = v.(map[string]*atomic.Value); !ok {
s = make(map[string]*atomic.Value, 0) s = make(map[string]*atomic.Value)
} }
if _, ok = s[key]; !ok { return s
}
func (c *configContext) Store(key string, cfg interface{}) {
s := c.getMap()
if _, ok := s[key]; !ok {
s[key] = &atomic.Value{} s[key] = &atomic.Value{}
} }
@@ -77,17 +81,9 @@ func (c *configContext) Store(key string, cfg interface{}) {
} }
func (c *configContext) Load(key string) interface{} { func (c *configContext) Load(key string) interface{} {
var ( s := c.getMap()
v interface{}
s map[string]*atomic.Value
ok bool
)
if v = c.cfg.Load(); v == nil { if _, ok := s[key]; !ok {
return nil
} else if s, ok = v.(map[string]*atomic.Value); !ok {
return nil
} else if _, ok = s[key]; !ok {
return nil return nil
} else { } else {
return s[key].Load() return s[key].Load()
@@ -97,10 +93,6 @@ func (c *configContext) Load(key string) interface{} {
func (c *configContext) Merge(cfg Config) bool { func (c *configContext) Merge(cfg Config) bool {
var ( var (
x *configContext x *configContext
vx interface{}
ix interface{}
sc map[string]*atomic.Value
sx map[string]*atomic.Value
ok bool ok bool
) )
@@ -108,68 +100,32 @@ func (c *configContext) Merge(cfg Config) bool {
return false return false
} }
sc = make(map[string]*atomic.Value, 0) s := c.getMap()
if vx = x.cfg.Load(); vx == nil { for k, v := range x.getMap() {
sx = make(map[string]*atomic.Value, 0)
} else if sx, ok = vx.(map[string]*atomic.Value); !ok {
sx = make(map[string]*atomic.Value, 0)
}
for k, v := range sx {
if k == "" || v == nil { if k == "" || v == nil {
continue continue
} }
ix = v.Load() if i := v.Load(); i == nil {
if ix == nil {
continue continue
} else {
s[k] = &atomic.Value{}
s[k].Store(i)
} }
sc[k] = &atomic.Value{}
sc[k].Store(ix)
} }
c.cfg.Store(sc) c.cfg.Store(s)
return true return true
} }
//Deprecated: use Store.
func (c *configContext) ObjectStore(key string, obj interface{}) { func (c *configContext) ObjectStore(key string, obj interface{}) {
var ( c.Store(key, obj)
v interface{}
s map[string]*atomic.Value
ok bool
)
if v = c.obj.Load(); v == nil {
s = make(map[string]*atomic.Value, 0)
} else if s, ok = v.(map[string]*atomic.Value); !ok {
s = make(map[string]*atomic.Value, 0)
}
if _, ok = s[key]; !ok {
s[key] = &atomic.Value{}
}
s[key].Store(obj)
c.obj.Store(s)
} }
//Deprecated: use Load.
func (c *configContext) ObjectLoad(key string) interface{} { func (c *configContext) ObjectLoad(key string) interface{} {
var ( return c.Load(key)
v interface{}
s map[string]*atomic.Value
ok bool
)
if v = c.obj.Load(); v == nil {
return nil
} else if s, ok = v.(map[string]*atomic.Value); !ok {
return nil
} else if _, ok = s[key]; !ok {
return nil
} else {
return s[key].Load()
}
} }

View File

@@ -27,6 +27,7 @@ package context
import "context" import "context"
func IsolateParent(parent context.Context) context.Context { func IsolateParent(parent context.Context) context.Context {
//nolint #govet
x, _ := context.WithCancel(parent) x, _ := context.WithCancel(parent)
return x return x
} }

View File

@@ -30,9 +30,8 @@ import (
"os/signal" "os/signal"
"time" "time"
"github.com/nabbar/golib/logger"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
liblog "github.com/nabbar/golib/logger"
) )
type GinTonic interface { type GinTonic interface {
@@ -102,11 +101,11 @@ func (c *ctxGinTonic) CancelOnSignal(s ...os.Signal) {
select { select {
case <-sc: case <-sc:
logger.InfoLevel.Logf("Os Signal recieved, calling context cancel !") liblog.InfoLevel.Logf("Os Signal received, calling context cancel !")
c.c() c.c()
return return
case <-c.Done(): case <-c.Done():
logger.InfoLevel.Logf("Context has been closed...") liblog.InfoLevel.Logf("Context has been closed...")
return return
} }
}() }()

View File

@@ -91,7 +91,7 @@ type Error interface {
IsCodeError(code CodeError) bool IsCodeError(code CodeError) bool
//HasCodeError check if current error or parent has the given error code //HasCodeError check if current error or parent has the given error code
HasCodeError(code CodeError) bool HasCodeError(code CodeError) bool
//GetCodeError return the CodeError value of the curent error //GetCodeError return the CodeError value of the current error
GetCodeError() CodeError GetCodeError() CodeError
//GetCodeErrorParent return a slice of CodeError value of all parent Error and the code of the current Error //GetCodeErrorParent return a slice of CodeError value of all parent Error and the code of the current Error
GetCodeErrorParent() []CodeError GetCodeErrorParent() []CodeError

View File

@@ -60,7 +60,7 @@ func (r *DefaultReturn) SetError(code int, msg string, file string, line int) {
} }
func (r *DefaultReturn) AddParent(code int, msg string, file string, line int) { func (r *DefaultReturn) AddParent(code int, msg string, file string, line int) {
return // nothing
} }
func (r DefaultReturn) JSON() []byte { func (r DefaultReturn) JSON() []byte {
@@ -89,6 +89,7 @@ func (r DefaultReturn) GinTonicErrorAbort(ctx *gin.Context, httpCode int) {
} }
ctx.Errors = append(ctx.Errors, &gin.Error{ ctx.Errors = append(ctx.Errors, &gin.Error{
//nolint #goerr113
Err: goErr.New(r.Message), Err: goErr.New(r.Message),
Type: gin.ErrorTypeAny, Type: gin.ErrorTypeAny,
}) })

58
go.mod
View File

@@ -3,37 +3,93 @@ module github.com/nabbar/golib
go 1.16 go 1.16
require ( require (
github.com/DataDog/zstd v1.4.8 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/PuerkitoBio/goquery v1.6.1 // indirect
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
github.com/VictoriaMetrics/metrics v1.17.2 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/aokoli/goutils v1.1.1 // indirect
github.com/armon/go-metrics v0.3.6 // indirect
github.com/aws/aws-sdk-go-v2 v1.3.2 github.com/aws/aws-sdk-go-v2 v1.3.2
github.com/aws/aws-sdk-go-v2/config v1.1.5 github.com/aws/aws-sdk-go-v2/config v1.1.5
github.com/aws/aws-sdk-go-v2/credentials v1.1.5 github.com/aws/aws-sdk-go-v2/credentials v1.1.5
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.6 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.3.1 github.com/aws/aws-sdk-go-v2/service/iam v1.3.1
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.0.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.6 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.2.2 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.5.0 github.com/aws/aws-sdk-go-v2/service/s3 v1.5.0
github.com/aws/aws-sdk-go-v2/service/sso v1.1.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.2.2 // indirect
github.com/cockroachdb/errors v1.8.3 // indirect
github.com/cockroachdb/pebble v0.0.0-20210406003833-3d4c32f510a8 // indirect
github.com/cockroachdb/redact v1.0.9 // indirect
github.com/fatih/color v1.10.0 github.com/fatih/color v1.10.0
github.com/fxamacker/cbor/v2 v2.2.0 github.com/fxamacker/cbor/v2 v2.2.0
github.com/gin-gonic/gin v1.7.1 github.com/gin-gonic/gin v1.7.1
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
github.com/go-ldap/ldap/v3 v3.3.0 github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-ole/go-ole v1.2.5 // indirect github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-playground/validator/v10 v10.5.0 github.com/go-playground/validator/v10 v10.5.0
github.com/gobuffalo/envy v1.9.0 // indirect
github.com/gobuffalo/packd v1.0.0 // indirect
github.com/gobuffalo/packr v1.30.1 github.com/gobuffalo/packr v1.30.1
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/go-github/v33 v33.0.0 github.com/google/go-github/v33 v33.0.0
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
github.com/hashicorp/go-msgpack v1.1.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.6.8 github.com/hashicorp/go-retryablehttp v0.6.8
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
github.com/hashicorp/go-uuid v1.0.2 github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.3.0 github.com/hashicorp/go-version v1.3.0
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/memberlist v0.2.3 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 // indirect
github.com/json-iterator/go v1.1.10 // indirect
github.com/klauspost/compress v1.11.13 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lni/dragonboat/v3 v3.3.2 github.com/lni/dragonboat/v3 v3.3.2
github.com/matcornic/hermes/v2 v2.1.0 github.com/matcornic/hermes/v2 v2.1.0
github.com/mattn/go-runewidth v0.0.12 // indirect
github.com/miekg/dns v1.1.41 // indirect
github.com/mitchellh/copystructure v1.1.2 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.1 github.com/onsi/ginkgo v1.16.1
github.com/onsi/gomega v1.11.0 github.com/onsi/gomega v1.11.0
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.3+incompatible github.com/shirou/gopsutil v3.21.3+incompatible
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/jwalterweatherman v1.1.0
github.com/ugorji/go v1.2.5 // indirect
github.com/vanng822/go-premailer v1.20.1 // indirect
github.com/vbauerster/mpb/v5 v5.4.0 github.com/vbauerster/mpb/v5 v5.4.0
github.com/xanzy/go-gitlab v0.48.0 github.com/xanzy/go-gitlab v0.48.0
github.com/xhit/go-simple-mail v2.2.2+incompatible github.com/xhit/go-simple-mail v2.2.2+incompatible
github.com/xujiajun/nutsdb v0.6.0 github.com/xujiajun/nutsdb v0.6.0
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
golang.org/x/exp v0.0.0-20210405174845-4513512abef3 // indirect
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750 // indirect
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
google.golang.org/appengine v1.6.7 // indirect
) )

View File

@@ -64,7 +64,8 @@ func GetClientTimeout(serverName string, http2Tr bool, GlobalTimeout time.Durati
Proxy: http.ProxyFromEnvironment, Proxy: http.ProxyFromEnvironment,
DialContext: dl.DialContext, DialContext: dl.DialContext,
DisableCompression: true, DisableCompression: true,
TLSClientConfig: certificates.GetTLSConfig(serverName), //nolint #staticcheck
TLSClientConfig: certificates.GetTLSConfig(serverName),
} }
return getclient(tr, http2Tr, GlobalTimeout) return getclient(tr, http2Tr, GlobalTimeout)

View File

@@ -35,7 +35,6 @@ import (
"time" "time"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
) )
@@ -129,10 +128,37 @@ func (p PoolServerConfig) MapRun(f MapRunPoolServerConfig) PoolServerConfig {
return r return r
} }
//nolint #maligned
type ServerConfig struct { type ServerConfig struct {
getTLSDefault func() libtls.TLSConfig
// Name is the name of the current server
// the configuration allow multipke server, which each one must be identify by a name
// If not defined, will use the listen address
Name string `mapstructure:"name" json:"name" yaml:"name" toml:"name" validate:"required"`
// Listen is the local address (ip, hostname, unix socket, ...) with a port
// The server will bind with this address only and listen for the port defined
Listen string `mapstructure:"listen" json:"listen" yaml:"listen" toml:"listen" validate:"required,hostname_port"`
// Expose is the address use to call this server. This can be allow to use a single fqdn to multiple server"
Expose string `mapstructure:"expose" json:"expose" yaml:"expose" toml:"expose" validate:"required,url"`
// HandlerKeys is an options to associate current server with a specifc handler defined by the key
// This allow to defined multiple server in only one config for different handler to start multiple api
HandlerKeys string `mapstructure:"handler_keys" json:"handler_keys" yaml:"handler_keys" toml:"handler_keys"`
//private
getTLSDefault func() libtls.TLSConfig
//private
getParentContext func() context.Context getParentContext func() context.Context
// TimeoutCacheInfo defined the validity time of cache for info (name, version, hash)
TimeoutCacheInfo time.Duration `mapstructure:"timeout_cache_info" json:"timeout_cache_info" yaml:"timeout_cache_info" toml:"timeout_cache_info"`
// TimeoutCacheHealth defined the validity time of cache for healthcheck of this server
TimeoutCacheHealth time.Duration `mapstructure:"timeout_cache_health" json:"timeout_cache_health" yaml:"timeout_cache_health" toml:"timeout_cache_health"`
// Enabled allow to disable a server without clean his configuration // Enabled allow to disable a server without clean his configuration
Disabled bool `mapstructure:"disabled" json:"disabled" yaml:"disabled" toml:"disabled"` Disabled bool `mapstructure:"disabled" json:"disabled" yaml:"disabled" toml:"disabled"`
@@ -140,11 +166,13 @@ type ServerConfig struct {
// y defined if the component for status is mandatory or not // y defined if the component for status is mandatory or not
Mandatory bool `mapstructure:"mandatory" json:"mandatory" yaml:"mandatory" toml:"mandatory"` Mandatory bool `mapstructure:"mandatory" json:"mandatory" yaml:"mandatory" toml:"mandatory"`
// TimeoutCacheInfo defined the validity time of cache for info (name, version, hash) // TLSMandatory is a flag to defined that TLS must be valid to start current server.
TimeoutCacheInfo time.Duration `mapstructure:"timeout_cache_info" json:"timeout_cache_info" yaml:"timeout_cache_info" toml:"timeout_cache_info"` TLSMandatory bool `mapstructure:"tls_mandatory" json:"tls_mandatory" yaml:"tls_mandatory" toml:"tls_mandatory"`
// TimeoutCacheHealth defined the validity time of cache for healthcheck of this server // TLS is the tls configuration for this server.
TimeoutCacheHealth time.Duration `mapstructure:"timeout_cache_health" json:"timeout_cache_health" yaml:"timeout_cache_health" toml:"timeout_cache_health"` // To allow tls on this server, at least the TLS Config option InheritDefault must be at true and the default TLS config must be set.
// If you don't want any tls config, just omit or set an empty struct.
TLS libtls.Config `mapstructure:"tls" json:"tls" yaml:"tls" toml:"tls"`
/*** http options ***/ /*** http options ***/
@@ -220,30 +248,6 @@ type ServerConfig struct {
// be larger than 2^32-1. If the value is zero or larger than the // be larger than 2^32-1. If the value is zero or larger than the
// maximum, a default value will be used instead. // maximum, a default value will be used instead.
MaxUploadBufferPerStream int32 `json:"max_upload_buffer_per_stream" json:"max_upload_buffer_per_stream" yaml:"max_upload_buffer_per_stream" toml:"max_upload_buffer_per_stream"` MaxUploadBufferPerStream int32 `json:"max_upload_buffer_per_stream" json:"max_upload_buffer_per_stream" yaml:"max_upload_buffer_per_stream" toml:"max_upload_buffer_per_stream"`
// Name is the name of the current server
// the configuration allow multipke server, which each one must be identify by a name
// If not defined, will use the listen address
Name string `mapstructure:"name" json:"name" yaml:"name" toml:"name" validate:"required"`
// Listen is the local address (ip, hostname, unix socket, ...) with a port
// The server will bind with this address only and listen for the port defined
Listen string `mapstructure:"listen" json:"listen" yaml:"listen" toml:"listen" validate:"required,hostname_port"`
// Expose is the address use to call this server. This can be allow to use a single fqdn to multiple server"
Expose string `mapstructure:"expose" json:"expose" yaml:"expose" toml:"expose" validate:"required,url"`
// HandlerKeys is an options to associate current server with a specifc handler defined by the key
// This allow to defined multiple server in only one config for different handler to start multiple api
HandlerKeys string `mapstructure:"handler_keys" json:"handler_keys" yaml:"handler_keys" toml:"handler_keys"`
// TLSMandatory is a flag to defined that TLS must be valid to start current server.
TLSMandatory bool `mapstructure:"tls_mandatory" json:"tls_mandatory" yaml:"tls_mandatory" toml:"tls_mandatory"`
// TLS is the tls configuration for this server.
// To allow tls on this server, at least the TLS Config option InheritDefault must be at true and the default TLS config must be set.
// If you don't want any tls config, just omit or set an empty struct.
TLS libtls.Config `mapstructure:"tls" json:"tls" yaml:"tls" toml:"tls"`
} }
func (c *ServerConfig) Clone() ServerConfig { func (c *ServerConfig) Clone() ServerConfig {
@@ -319,7 +323,7 @@ func (c ServerConfig) GetListen() *url.URL {
if c.Listen != "" { if c.Listen != "" {
if add, err = url.Parse(c.Listen); err != nil { if add, err = url.Parse(c.Listen); err != nil {
if host, prt, err := net.SplitHostPort(c.Listen); err == nil { if host, prt, e := net.SplitHostPort(c.Listen); e == nil {
add = &url.URL{ add = &url.URL{
Host: fmt.Sprintf("%s:%s", host, prt), Host: fmt.Sprintf("%s:%s", host, prt),
} }

View File

@@ -36,13 +36,10 @@ import (
"strings" "strings"
"syscall" "syscall"
"github.com/nabbar/golib/status"
"github.com/nabbar/golib/logger"
"github.com/nabbar/golib/semaphore"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger"
libsem "github.com/nabbar/golib/semaphore"
libsts "github.com/nabbar/golib/status"
) )
type FieldType uint8 type FieldType uint8
@@ -82,7 +79,7 @@ type PoolServer interface {
StatusInfo(bindAddress string) (name string, release string, hash string) StatusInfo(bindAddress string) (name string, release string, hash string)
StatusHealth(bindAddress string) error StatusHealth(bindAddress string) error
StatusRoute(prefix string, fctMessage status.FctMessage, sts status.RouteStatus) StatusRoute(prefix string, fctMessage libsts.FctMessage, sts libsts.RouteStatus)
} }
func NewPool(srv ...Server) PoolServer { func NewPool(srv ...Server) PoolServer {
@@ -353,7 +350,7 @@ func (p pool) ListenMultiHandler(handler map[string]http.Handler) liberr.Error {
var e liberr.Error var e liberr.Error
e = ErrorPoolListen.Error(nil) e = ErrorPoolListen.Error(nil)
logger.InfoLevel.Log("Calling listen for All Servers") liblog.InfoLevel.Log("Calling listen for All Servers")
p.MapRun(func(srv Server) { p.MapRun(func(srv Server) {
if len(handler) < 1 { if len(handler) < 1 {
@@ -371,7 +368,7 @@ func (p pool) ListenMultiHandler(handler map[string]http.Handler) liberr.Error {
} }
}) })
logger.InfoLevel.Log("End of Calling listen for All Servers") liblog.InfoLevel.Log("End of Calling listen for All Servers")
if !e.HasParent() { if !e.HasParent() {
e = nil e = nil
@@ -380,64 +377,66 @@ func (p pool) ListenMultiHandler(handler map[string]http.Handler) liberr.Error {
return e return e
} }
func (p pool) Restart() { func (p pool) runMapCommand(f func(sem libsem.Sem, srv Server)) {
if p.Len() < 1 { if p.Len() < 1 {
return return
} }
var ( var (
s semaphore.Sem s libsem.Sem
x context.Context x context.Context
c context.CancelFunc c context.CancelFunc
) )
x, c = context.WithTimeout(context.Background(), timeoutShutdown)
defer func() { defer func() {
c() c()
s.DeferMain() s.DeferMain()
}() }()
x, c = context.WithTimeout(context.Background(), timeoutRestart) s = libsem.NewSemaphoreWithContext(x, 0)
s = semaphore.NewSemaphoreWithContext(x, 0)
p.MapRun(func(srv Server) { p.MapRun(func(srv Server) {
_ = s.NewWorker() _ = s.NewWorker()
go func() { go func(sem libsem.Sem, srv Server) {
defer s.DeferWorker() f(sem, srv)
srv.Restart() }(s, srv)
}()
}) })
_ = s.WaitAll() _ = s.WaitAll()
} }
func (p pool) Shutdown() { func (p pool) runMapRestart(sem libsem.Sem, srv Server) {
if p.Len() < 1 {
return
}
var (
s semaphore.Sem
x context.Context
c context.CancelFunc
)
defer func() { defer func() {
c() if sem != nil {
s.DeferMain() sem.DeferWorker()
}
}() }()
x, c = context.WithTimeout(context.Background(), timeoutShutdown) if srv != nil {
s = semaphore.NewSemaphoreWithContext(x, 0) srv.Restart()
}
}
p.MapRun(func(srv Server) { func (p pool) runMapShutdown(sem libsem.Sem, srv Server) {
_ = s.NewWorker() defer func() {
go func() { if sem != nil {
defer s.DeferWorker() sem.DeferWorker()
srv.Shutdown() }
}() }()
})
_ = s.WaitAll() if srv != nil {
srv.Shutdown()
}
}
func (p pool) Restart() {
p.runMapCommand(p.runMapRestart)
}
func (p pool) Shutdown() {
p.runMapCommand(p.runMapShutdown)
} }
func (p pool) StatusInfo(bindAddress string) (name string, release string, hash string) { func (p pool) StatusInfo(bindAddress string) (name string, release string, hash string) {
@@ -453,10 +452,11 @@ func (p pool) StatusHealth(bindAddress string) error {
return s.StatusHealth() return s.StatusHealth()
} }
//nolint #goerr113
return fmt.Errorf("missing server '%s'", bindAddress) return fmt.Errorf("missing server '%s'", bindAddress)
} }
func (p pool) StatusRoute(keyPrefix string, fctMessage status.FctMessage, sts status.RouteStatus) { func (p pool) StatusRoute(keyPrefix string, fctMessage libsts.FctMessage, sts libsts.RouteStatus) {
p.MapRun(func(srv Server) { p.MapRun(func(srv Server) {
bind := srv.GetBindable() bind := srv.GetBindable()
sts.ComponentNew(fmt.Sprintf("%s-%s", keyPrefix, bind), srv.StatusComponent(fctMessage)) sts.ComponentNew(fmt.Sprintf("%s-%s", keyPrefix, bind), srv.StatusComponent(fctMessage))

View File

@@ -45,6 +45,8 @@ import (
"golang.org/x/net/http2" "golang.org/x/net/http2"
) )
const _TimeoutWaitingPortFreeing = 500 * time.Microsecond
type srvRun struct { type srvRun struct {
err *atomic.Value err *atomic.Value
run *atomic.Value run *atomic.Value
@@ -109,6 +111,7 @@ func (s *srvRun) setErr(e error) {
if e != nil { if e != nil {
s.err.Store(e) s.err.Store(e)
} else { } else {
//nolint #goerr113
s.err.Store(errors.New("")) s.err.Store(errors.New(""))
} }
} }
@@ -141,6 +144,7 @@ func (s *srvRun) Merge(srv Server) bool {
panic("implement me") panic("implement me")
} }
//nolint #gocognit
func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error { func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
ssl, err := cfg.GetTLS() ssl, err := cfg.GetTLS()
if err != nil { if err != nil {
@@ -263,6 +267,7 @@ func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
s.setRunning(true) s.setRunning(true)
err = s.srv.ListenAndServeTLS("", "") err = s.srv.ListenAndServeTLS("", "")
} else if tlsMandatory { } else if tlsMandatory {
//nolint #goerr113
err = fmt.Errorf("missing valid server certificates") err = fmt.Errorf("missing valid server certificates")
} else { } else {
liblog.InfoLevel.Logf("Server '%s' is starting with bindable: %s", name, host) liblog.InfoLevel.Logf("Server '%s' is starting with bindable: %s", name, host)
@@ -333,7 +338,7 @@ func (s *srvRun) PortInUse(listen string) liberr.Error {
} }
}() }()
ctx, cnl = context.WithTimeout(context.TODO(), 2*time.Second) ctx, cnl = context.WithTimeout(context.TODO(), _TimeoutWaitingPortFreeing)
con, err = dia.DialContext(ctx, "tcp", listen) con, err = dia.DialContext(ctx, "tcp", listen)
if con != nil { if con != nil {

View File

@@ -34,24 +34,22 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/nabbar/golib/status"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
libsts "github.com/nabbar/golib/status"
) )
const ( const (
timeoutShutdown = 10 * time.Second timeoutShutdown = 10 * time.Second
timeoutRestart = 30 * time.Second
) )
type server struct { type server struct {
run *atomic.Value run *atomic.Value
cfg ServerConfig cfg *atomic.Value
} }
type Server interface { type Server interface {
GetConfig() *ServerConfig GetConfig() *ServerConfig
SetConfig(cfg *ServerConfig) SetConfig(cfg *ServerConfig) bool
GetName() string GetName() string
GetBindable() string GetBindable() string
@@ -69,16 +67,50 @@ type Server interface {
StatusInfo() (name string, release string, hash string) StatusInfo() (name string, release string, hash string)
StatusHealth() error StatusHealth() error
StatusComponent(message status.FctMessage) status.Component StatusComponent(message libsts.FctMessage) libsts.Component
} }
func NewServer(cfg *ServerConfig) Server { func NewServer(cfg *ServerConfig) Server {
c := new(atomic.Value)
c.Store(cfg.Clone())
return &server{ return &server{
cfg: cfg.Clone(), cfg: c,
run: new(atomic.Value), run: new(atomic.Value),
} }
} }
func (s *server) GetConfig() *ServerConfig {
if s.cfg == nil {
return nil
} else if i := s.cfg.Load(); i == nil {
return nil
} else if c, ok := i.(ServerConfig); !ok {
return nil
} else {
return &c
}
}
func (s *server) SetConfig(cfg *ServerConfig) bool {
if cfg == nil {
return false
}
if s.cfg == nil {
s.cfg = new(atomic.Value)
}
c := cfg.Clone()
if c.Name == "" {
c.Name = c.GetListen().Host
}
s.cfg.Store(cfg.Clone())
return true
}
func (s *server) getRun() run { func (s *server) getRun() run {
if s.run == nil { if s.run == nil {
return newRun() return newRun()
@@ -103,32 +135,20 @@ func (s *server) getErr() error {
} }
} }
func (s *server) GetConfig() *ServerConfig {
return &s.cfg
}
func (s *server) SetConfig(cfg *ServerConfig) {
s.cfg = cfg.Clone()
}
func (s server) GetName() string { func (s server) GetName() string {
if s.cfg.Name == "" { return s.GetConfig().Name
s.cfg.Name = s.GetBindable()
}
return s.cfg.Name
} }
func (s *server) GetBindable() string { func (s *server) GetBindable() string {
return s.cfg.GetListen().Host return s.GetConfig().GetListen().Host
} }
func (s *server) GetExpose() string { func (s *server) GetExpose() string {
return s.cfg.GetExpose().String() return s.GetConfig().GetExpose().String()
} }
func (s *server) GetHandlerKey() string { func (s *server) GetHandlerKey() string {
return s.cfg.GetHandlerKey() return s.GetConfig().GetHandlerKey()
} }
func (s *server) IsRunning() bool { func (s *server) IsRunning() bool {
@@ -136,12 +156,12 @@ func (s *server) IsRunning() bool {
} }
func (s *server) IsTLS() bool { func (s *server) IsTLS() bool {
return s.cfg.IsTLS() return s.GetConfig().IsTLS()
} }
func (s *server) Listen(handler http.Handler) liberr.Error { func (s *server) Listen(handler http.Handler) liberr.Error {
r := s.getRun() r := s.getRun()
e := r.Listen(&s.cfg, handler) e := r.Listen(s.GetConfig(), handler)
s.setRun(r) s.setRun(r)
return e return e
@@ -163,12 +183,11 @@ func (s *server) Shutdown() {
} }
func (s *server) Merge(srv Server) bool { func (s *server) Merge(srv Server) bool {
if x, ok := srv.(*server); ok { if x, ok := srv.(*server); !ok {
s.cfg = x.cfg return false
return true } else {
return s.SetConfig(x.GetConfig())
} }
return false
} }
func (s *server) StatusInfo() (name string, release string, hash string) { func (s *server) StatusInfo() (name string, release string, hash string) {
@@ -180,17 +199,20 @@ func (s *server) StatusInfo() (name string, release string, hash string) {
} }
func (s *server) StatusHealth() error { func (s *server) StatusHealth() error {
if !s.cfg.Disabled && s.IsRunning() { c := s.GetConfig()
if !c.Disabled && s.IsRunning() {
return nil return nil
} else if s.cfg.Disabled { } else if c.Disabled {
//nolint #goerr113
return fmt.Errorf("server disabled") return fmt.Errorf("server disabled")
} else if e := s.getErr(); e != nil { } else if e := s.getErr(); e != nil {
return e return e
} else { } else {
//nolint #goerr113
return fmt.Errorf("server is offline -- missing error") return fmt.Errorf("server is offline -- missing error")
} }
} }
func (s *server) StatusComponent(message status.FctMessage) status.Component { func (s *server) StatusComponent(message libsts.FctMessage) libsts.Component {
return status.NewComponent(s.cfg.Mandatory, s.StatusInfo, s.StatusHealth, message, s.cfg.TimeoutCacheInfo, s.cfg.TimeoutCacheHealth) return libsts.NewComponent(s.GetConfig().Mandatory, s.StatusInfo, s.StatusHealth, message, s.GetConfig().TimeoutCacheInfo, s.GetConfig().TimeoutCacheHealth)
} }

View File

@@ -59,10 +59,11 @@ func NewLDAP(ctx context.Context, cnf *Config, attributes []string) (*HelperLDAP
return &HelperLDAP{ return &HelperLDAP{
Attributes: attributes, Attributes: attributes,
tlsConfig: libcrt.GetTLSConfig(cnf.Uri), //nolint #staticcheck
tlsMode: tlsmode_init, tlsConfig: libcrt.GetTLSConfig(cnf.Uri),
config: cnf.Clone(), tlsMode: _TLSModeInit,
ctx: libctx.IsolateParent(ctx), config: cnf.Clone(),
ctx: libctx.IsolateParent(ctx),
}, nil }, nil
} }
@@ -83,15 +84,15 @@ func (lc *HelperLDAP) ForceTLSMode(tlsMode TLSMode, tlsConfig *tls.Config) {
} }
switch tlsMode { switch tlsMode {
case TLSMODE_TLS: case TLSModeTLS:
lc.tlsMode = TLSMODE_TLS lc.tlsMode = TLSModeTLS
case TLSMODE_STARTTLS: case TLSModeStarttls:
lc.tlsMode = TLSMODE_STARTTLS lc.tlsMode = TLSModeStarttls
case TLSMODE_NONE: case TLSModeNone:
lc.tlsConfig = nil lc.tlsConfig = nil
lc.tlsMode = TLSMODE_NONE lc.tlsMode = TLSModeNone
case tlsmode_init: case _TLSModeInit:
lc.tlsMode = tlsmode_init lc.tlsMode = _TLSModeInit
} }
} }
@@ -175,7 +176,7 @@ func (lc *HelperLDAP) starttls(l *ldap.Conn) liberr.Error {
func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) { func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) {
if lc == nil { if lc == nil {
return TLSMODE_NONE, ErrorEmptyParams.Error(nil) return TLSModeNone, ErrorEmptyParams.Error(nil)
} }
var ( var (
@@ -192,32 +193,32 @@ func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) {
if lc.config.Portldaps != 0 { if lc.config.Portldaps != 0 {
l, err = lc.dialTLS() l, err = lc.dialTLS()
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_TLS.String()) liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSModeTLS.String())
if err == nil { if err == nil {
return TLSMODE_TLS, nil return TLSModeTLS, nil
} }
} }
if lc.config.PortLdap == 0 { if lc.config.PortLdap == 0 {
return tlsmode_init, ErrorLDAPServerConfig.Error(nil) return _TLSModeInit, ErrorLDAPServerConfig.Error(nil)
} }
l, err = lc.dial() l, err = lc.dial()
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_NONE.String()) liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSModeNone.String())
if err != nil { if err != nil {
return tlsmode_init, err return _TLSModeInit, err
} }
err = lc.starttls(l) err = lc.starttls(l)
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSMODE_STARTTLS.String()) liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSModeStarttls.String())
if err == nil { if err == nil {
return TLSMODE_STARTTLS, nil return TLSModeStarttls, nil
} }
return TLSMODE_NONE, nil return TLSModeNone, nil
} }
func (lc *HelperLDAP) connect() liberr.Error { func (lc *HelperLDAP) connect() liberr.Error {
@@ -235,7 +236,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
err liberr.Error err liberr.Error
) )
if lc.tlsMode == tlsmode_init { if lc.tlsMode == _TLSModeInit {
m, e := lc.tryConnect() m, e := lc.tryConnect()
if e != nil { if e != nil {
@@ -245,7 +246,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
lc.tlsMode = m lc.tlsMode = m
} }
if lc.tlsMode == TLSMODE_TLS { if lc.tlsMode == TLSModeTLS {
l, err = lc.dialTLS() l, err = lc.dialTLS()
if err != nil { if err != nil {
if l != nil { if l != nil {
@@ -255,7 +256,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
} }
} }
if lc.tlsMode == TLSMODE_NONE || lc.tlsMode == TLSMODE_STARTTLS { if lc.tlsMode == TLSModeNone || lc.tlsMode == TLSModeStarttls {
l, err = lc.dial() l, err = lc.dial()
if err != nil { if err != nil {
if l != nil { if l != nil {
@@ -265,7 +266,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
} }
} }
if lc.tlsMode == TLSMODE_STARTTLS { if lc.tlsMode == TLSModeStarttls {
err = lc.starttls(l) err = lc.starttls(l)
if err != nil { if err != nil {
if l != nil { if l != nil {
@@ -346,7 +347,7 @@ func (lc *HelperLDAP) Connect() liberr.Error {
return err return err
} }
liblog.DebugLevel.Logf("Bind success on LDAP server %s with tls mode '%s'", lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String()) liblog.DebugLevel.Logf("Bind success on LDAP server %s with tls mode '%s'", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String())
return nil return nil
} }
@@ -376,7 +377,7 @@ func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.Searc
return nil, ErrorLDAPSearch.ErrorParent(err) return nil, ErrorLDAPSearch.ErrorParent(err)
} }
liblog.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) liblog.DebugLevel.Logf("Search success on server '%s' with tls mode '%s', with filter [%s] and attribute %v", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), filter, attributes)
return src, nil return src, nil
} }
@@ -405,46 +406,10 @@ func (lc *HelperLDAP) getUserName(username string) (string, liberr.Error) {
//UserInfo used to retrieve the information of a given username. //UserInfo used to retrieve the information of a given username.
func (lc *HelperLDAP) UserInfo(username string) (map[string]string, liberr.Error) { func (lc *HelperLDAP) UserInfo(username string) (map[string]string, liberr.Error) {
var ( return lc.UserInfoByField(username, userFieldUid)
err liberr.Error
src *ldap.SearchResult
userRes map[string]string
)
if username, err = lc.getUserName(username); err != nil {
return nil, err
}
userRes = make(map[string]string)
attributes := append(lc.Attributes, "cn")
src, err = lc.runSearch(fmt.Sprintf(lc.config.FilterUser, userFieldUid, username), attributes)
if err != nil {
return userRes, err
}
if len(src.Entries) != 1 {
if len(src.Entries) > 1 {
return userRes, ErrorLDAPUserNotUniq.Error(nil)
} else {
return userRes, ErrorLDAPUserNotFound.Error(nil)
}
}
for _, attr := range attributes {
userRes[attr] = src.Entries[0].GetAttributeValue(attr)
}
if _, ok := userRes["DN"]; !ok {
userRes["DN"] = src.Entries[0].DN
}
liblog.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
} }
//UserInfo used to retrieve the information of a given username. //UserInfoByField used to retrieve the information of a given username but use a given field to make the search.
func (lc *HelperLDAP) UserInfoByField(username string, fieldOfUnicValue string) (map[string]string, liberr.Error) { func (lc *HelperLDAP) UserInfoByField(username string, fieldOfUnicValue string) (map[string]string, liberr.Error) {
var ( var (
err liberr.Error err liberr.Error
@@ -481,39 +446,16 @@ func (lc *HelperLDAP) UserInfoByField(username string, fieldOfUnicValue string)
userRes["DN"] = src.Entries[0].DN userRes["DN"] = src.Entries[0].DN
} }
liblog.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) liblog.DebugLevel.Logf("Map info retrieve in ldap server '%s' with tls mode '%s' about user [%s] : %v", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), username, userRes)
return userRes, nil return userRes, nil
} }
//GroupInfo used to retrieve the information of a given group cn. //GroupInfo used to retrieve the information of a given group cn.
func (lc *HelperLDAP) GroupInfo(groupname string) (map[string]interface{}, liberr.Error) { func (lc *HelperLDAP) GroupInfo(groupname string) (map[string]interface{}, liberr.Error) {
var ( return lc.GroupInfoByField(groupname, groupFieldCN)
err liberr.Error
src *ldap.SearchResult
grpInfo map[string]interface{}
)
src, err = lc.runSearch(fmt.Sprintf(lc.config.FilterGroup, groupFieldCN, groupname), []string{})
if err != nil {
return grpInfo, err
}
if len(src.Entries) == 0 {
return nil, ErrorLDAPGroupNotFound.Error(nil)
}
grpInfo = make(map[string]interface{}, len(src.Entries[0].Attributes))
for _, entry := range src.Entries {
for _, entryAttribute := range entry.Attributes {
grpInfo[entryAttribute.Name] = entryAttribute.Values
}
}
liblog.DebugLevel.Logf("Info for group [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grpInfo)
return grpInfo, nil
} }
//GroupInfo used to retrieve the information of a given group cn. //GroupInfoByField used to retrieve the information of a given group cn, but use a given field to make the search.
func (lc *HelperLDAP) GroupInfoByField(groupname string, fieldForUnicValue string) (map[string]interface{}, liberr.Error) { func (lc *HelperLDAP) GroupInfoByField(groupname string, fieldForUnicValue string) (map[string]interface{}, liberr.Error) {
var ( var (
err liberr.Error err liberr.Error
@@ -537,7 +479,7 @@ func (lc *HelperLDAP) GroupInfoByField(groupname string, fieldForUnicValue strin
} }
} }
liblog.DebugLevel.Logf("Info for group [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSMODE_TLS), lc.tlsMode.String(), grpInfo) liblog.DebugLevel.Logf("Info for group [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), grpInfo)
return grpInfo, nil return grpInfo, nil
} }
@@ -562,13 +504,13 @@ func (lc *HelperLDAP) UserMemberOf(username string) ([]string, liberr.Error) {
for _, entry := range src.Entries { for _, entry := range src.Entries {
for _, mmb := range entry.GetAttributeValues("memberOf") { for _, mmb := range entry.GetAttributeValues("memberOf") {
liblog.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) liblog.DebugLevel.Logf("Group find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), mmb)
mmo := lc.ParseEntries(mmb) mmo := lc.ParseEntries(mmb)
grp = append(grp, mmo["cn"]...) grp = append(grp, mmo["cn"]...)
} }
} }
liblog.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) liblog.DebugLevel.Logf("Groups find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), grp)
return grp, nil return grp, nil
} }
@@ -618,7 +560,7 @@ func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, liberr.Error) {
} }
} }
liblog.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) liblog.DebugLevel.Logf("Member of groups [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), grp)
return grp, nil return grp, nil
} }

View File

@@ -35,13 +35,13 @@ import (
type TLSMode uint8 type TLSMode uint8
const ( const (
tlsmode_init TLSMode = iota _TLSModeInit TLSMode = iota
//TLSModeNone no tls connection. //TLSModeNone no tls connection.
TLSMODE_NONE TLSMode = iota + 1 TLSModeNone TLSMode = iota + 1
//TLSModeTLS strict tls connection. //TLSModeTLS strict tls connection.
TLSMODE_TLS TLSModeTLS
//TLSModeStartTLS starttls connection (tls into a no tls connection). //TLSModeStarttls starttls connection (tls into a no tls connection).
TLSMODE_STARTTLS TLSModeStarttls
) )
const ( const (
@@ -51,17 +51,17 @@ const (
func (m TLSMode) String() string { func (m TLSMode) String() string {
switch m { switch m {
case TLSMODE_STARTTLS: case TLSModeStarttls:
return "starttls" return "starttls"
case TLSMODE_TLS: case TLSModeTLS:
return "tls" return "tls"
case TLSMODE_NONE: case TLSModeNone:
return "none" return "none"
case tlsmode_init: case _TLSModeInit:
return "not defined" return "not defined"
} }
return tlsmode_init.String() return _TLSModeInit.String()
} }
func GetDefaultAttributes() []string { func GetDefaultAttributes() []string {
@@ -123,6 +123,7 @@ func (cnf Config) Validate() errors.Error {
} }
for _, err := range err.(validator.ValidationErrors) { for _, err := range err.(validator.ValidationErrors) {
//nolint #goerr113
e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", err.StructNamespace(), err.ActualTag())) e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", err.StructNamespace(), err.ActualTag()))
} }
} }

View File

@@ -1,66 +0,0 @@
/*
* 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 mail
import "io"
const maxLineChars = 76
type base64LineWrap struct {
writer io.Writer
numLineChars int
}
func (e *base64LineWrap) Write(p []byte) (n int, err error) {
n = 0
// while we have more chars than are allowed
for len(p)+e.numLineChars > maxLineChars {
numCharsToWrite := maxLineChars - e.numLineChars
// write the chars we can
/* #nosec */
//nolint #nosec
_, _ = e.writer.Write(p[:numCharsToWrite])
// write a line break
/* #nosec */
//nolint #nosec
_, _ = e.writer.Write([]byte("\r\n"))
// reset the line count
e.numLineChars = 0
// remove the chars that have been written
p = p[numCharsToWrite:]
// set the num of chars written
n += numCharsToWrite
}
// write what is left
/* #nosec */
//nolint #nosec
_, _ = e.writer.Write(p)
e.numLineChars += len(p)
n += len(p)
return
}

View File

@@ -28,9 +28,9 @@ package mail
type ContentType uint8 type ContentType uint8
const ( const (
// TextPlain sets body type to text/plain in message body // ContentPlainText sets body type to text/plain in message body.
ContentPlainText ContentType = iota ContentPlainText ContentType = iota
// TextHTML sets body type to text/html in message body // ContentHTML sets body type to text/html in message body.
ContentHTML ContentHTML
) )
@@ -44,14 +44,3 @@ func (c ContentType) String() string {
return ContentPlainText.String() return ContentPlainText.String()
} }
func (c ContentType) getContentType() string {
switch c {
case ContentPlainText:
return "text/plain"
case ContentHTML:
return "text/html"
}
return ContentPlainText.getContentType()
}

View File

@@ -1,200 +0,0 @@
/*
* 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 mail
import (
"bufio"
"bytes"
"fmt"
"io"
"strings"
"unicode/utf8"
)
type encoder struct {
w *bufio.Writer
charset string
usedChars int
}
// newEncoder returns a new mime header encoder that writes to w. The c
// parameter specifies the name of the character set of the text that will be
// encoded. The u parameter indicates how many characters have been used
// already.
func newEncoder(w io.Writer, c string, u int) *encoder {
return &encoder{bufio.NewWriter(w), strings.ToUpper(c), u}
}
// encode encodes p using the "Q" encoding and writes it to the underlying
// io.Writer. It limits line length to 75 characters.
func (e *encoder) encode(p []byte) (n int, err error) {
var output bytes.Buffer
allPrintable := true
// some lines we encode end in "
//maxLineLength := 75 - 1
maxLineLength := 76
// prevent header injection
p = e.secureHeader(p)
// check to see if we have all printable characters
for _, c := range p {
if !e.isVchar(c) && !e.isWSP(c) {
allPrintable = false
break
}
}
// all characters are printable. just do line folding
if allPrintable {
text := string(p)
words := strings.Split(text, " ")
lineBuffer := ""
firstWord := true
// split the line where necessary
for _, word := range words {
newWord := ""
if !firstWord {
newWord += " "
}
newWord += word
// check line length
if (e.usedChars+len(lineBuffer)+len(newWord) /*+len(" ")+len(word)*/) > maxLineLength && (lineBuffer != "" || e.usedChars != 0) {
output.WriteString(lineBuffer + "\r\n")
// first word on newline needs a space in front
if !firstWord {
lineBuffer = ""
} else {
lineBuffer = " "
}
// reset since not on the first line anymore
e.usedChars = 0
}
lineBuffer += newWord /*word*/
firstWord = false
}
output.WriteString(lineBuffer)
} else {
firstLine := true
// A single encoded word can not be longer than 75 characters
if e.usedChars == 0 {
maxLineLength = 75
}
wordBegin := "=?" + e.charset + "?Q?"
wordEnd := "?="
lineBuffer := wordBegin
for i := 0; i < len(p); {
// encode the character
encodedChar, runeLength := e.encodeChar(p, i)
// Check line length
if len(lineBuffer)+e.usedChars+len(encodedChar) > (maxLineLength - len(wordEnd)) {
output.WriteString(lineBuffer + wordEnd + "\r\n")
lineBuffer = " " + wordBegin
firstLine = false
}
lineBuffer += encodedChar
i = i + runeLength
// reset since not on the first line anymore
if !firstLine {
e.usedChars = 0
maxLineLength = 76
}
}
output.WriteString(lineBuffer + wordEnd)
}
_, _ = e.w.Write(output.Bytes())
_ = e.w.Flush()
n = output.Len()
return n, nil
}
// encode takes a string and position in that string and encodes one utf-8
// character. It then returns the encoded string and number of runes in the
// character.
func (e *encoder) encodeChar(text []byte, i int) (encodedString string, runeLength int) {
started := false
for ; i < len(text) && (!utf8.RuneStart(text[i]) || !started); i++ {
switch c := text[i]; {
case c == ' ':
encodedString += "_"
case e.isVchar(c) && c != '=' && c != '?' && c != '_':
encodedString += string(c)
default:
encodedString += fmt.Sprintf("=%02X", c)
}
runeLength++
started = true
}
return
}
// secureHeader removes all unnecessary values to prevent
// header injection
func (e *encoder) secureHeader(text []byte) []byte {
secureValue := strings.TrimSpace(string(text))
secureValue = strings.Replace(secureValue, "\r", "", -1)
secureValue = strings.Replace(secureValue, "\n", "", -1)
secureValue = strings.Replace(secureValue, "\t", "", -1)
return []byte(secureValue)
}
// isVchar returns true if c is an RFC 5322 VCHAR character.
func (e *encoder) isVchar(c byte) bool {
// Visible (printing) characters.
return '!' <= c && c <= '~'
}
// isWSP returns true if c is a WSP (white space).
// WSP is a space or horizontal tab (RFC5234 Appendix B).
func (e *encoder) isWSP(c byte) bool {
return c == ' ' || c == '\t'
}

View File

@@ -28,16 +28,16 @@ package mail
type Encoding uint8 type Encoding uint8
const ( const (
// EncodingNone turns off encoding on the message body // EncodingNone turns off encoding on the message body.
EncodingNone Encoding = iota EncodingNone Encoding = iota
// EncodingBinary is equal to EncodingNone, but string is set to binrary instead of none // EncodingBinary is equal to EncodingNone, but string is set to binary instead of none.
EncodingBinary EncodingBinary
// EncodingBase64 sets the message body encoding to base64 // EncodingBase64 sets the message body encoding to base64.
EncodingBase64 EncodingBase64
// EncodingQuotedPrintable sets the message body encoding to quoted-printable // EncodingQuotedPrintable sets the message body encoding to quoted-printable.
EncodingQuotedPrintable EncodingQuotedPrintable
) )
@@ -54,16 +54,3 @@ func (e Encoding) String() string {
} }
return EncodingNone.String() return EncodingNone.String()
} }
func (e Encoding) getEncoding() string {
switch e {
case EncodingNone, EncodingBinary:
return "binary"
case EncodingBase64:
return "base64"
case EncodingQuotedPrintable:
return "quoted-printable"
}
return EncodingNone.getEncoding()
}

View File

@@ -36,7 +36,7 @@ import (
) )
const ( const (
MailDateTimeLayout = time.RFC1123Z DateTimeLayout = time.RFC1123Z
headerMimeVersion = "MIME-Version" headerMimeVersion = "MIME-Version"
headerDate = "Date" headerDate = "Date"
@@ -44,17 +44,16 @@ const (
) )
type mail struct { type mail struct {
headers textproto.MIMEHeader
charset string
encoding Encoding
date time.Time date time.Time
attach []File
inline []File
body []Body
charset string
subject string subject string
headers textproto.MIMEHeader
address *email
encoding Encoding
priority Priority priority Priority
address *email
attach []File
inline []File
body []Body
} }
func (m *mail) Email() Email { func (m *mail) Email() Email {
@@ -112,7 +111,7 @@ func (m *mail) SetDateString(layout, datetime string) liberr.Error {
} }
func (m *mail) GetDateString() string { func (m *mail) GetDateString() string {
return m.date.Format(MailDateTimeLayout) return m.date.Format(DateTimeLayout)
} }
func (m *mail) AddHeader(key string, values ...string) { func (m *mail) AddHeader(key string, values ...string) {
@@ -182,7 +181,7 @@ func (m *mail) GetHeaders() textproto.MIMEHeader {
h = m.addHeader(h, key, values...) h = m.addHeader(h, key, values...)
}) })
for k, _ := range m.headers { for k := range m.headers {
h = m.addHeader(h, k, m.headers.Values(k)...) h = m.addHeader(h, k, m.headers.Values(k)...)
} }

View File

@@ -34,11 +34,11 @@ const (
type Priority uint8 type Priority uint8
const ( const (
// PriorityNormal sets the email priority to normal // PriorityNormal sets the email priority to normal.
PriorityNormal Priority = iota PriorityNormal Priority = iota
// PriorityLow sets the email priority to Low // PriorityLow sets the email priority to Low.
PriorityLow PriorityLow
// PriorityHigh sets the email priority to High // PriorityHigh sets the email priority to High.
PriorityHigh PriorityHigh
) )
@@ -71,9 +71,9 @@ func (p Priority) headerPriority() string {
func (p Priority) headerImportance() string { func (p Priority) headerImportance() string {
switch p { switch p {
case PriorityLow: case PriorityLow:
return "Low" return PriorityLow.String()
case PriorityHigh: case PriorityHigh:
return "High" return PriorityHigh.String()
case PriorityNormal: case PriorityNormal:
return "" return ""
} }
@@ -84,9 +84,9 @@ func (p Priority) headerImportance() string {
func (p Priority) headerMSMailPriority() string { func (p Priority) headerMSMailPriority() string {
switch p { switch p {
case PriorityLow: case PriorityLow:
return "Low" return PriorityLow.String()
case PriorityHigh: case PriorityHigh:
return "High" return PriorityHigh.String()
case PriorityNormal: case PriorityNormal:
return "" return ""
} }

View File

@@ -31,29 +31,32 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/nabbar/golib/smtp"
"github.com/nabbar/golib/ioutils"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
libiot "github.com/nabbar/golib/ioutils"
libsmtp "github.com/nabbar/golib/smtp"
simple "github.com/xhit/go-simple-mail" simple "github.com/xhit/go-simple-mail"
) )
const (
_MinSizeAddr = 4
)
type Sender interface { type Sender interface {
Close() error Close() error
Send(ctx context.Context, cli smtp.SMTP) liberr.Error Send(ctx context.Context, cli libsmtp.SMTP) liberr.Error
SendClose(ctx context.Context, cli smtp.SMTP) liberr.Error SendClose(ctx context.Context, cli libsmtp.SMTP) liberr.Error
} }
type sender struct { type sender struct {
data ioutils.FileProgress data libiot.FileProgress
from string from string
rcpt []string rcpt []string
} }
//nolint #gocognit
func (m *mail) Sender() (snd Sender, err liberr.Error) { func (m *mail) Sender() (snd Sender, err liberr.Error) {
e := simple.NewMSG() e := simple.NewMSG()
f := make([]ioutils.FileProgress, 0) f := make([]libiot.FileProgress, 0)
switch m.GetPriority() { switch m.GetPriority() {
case PriorityHigh: case PriorityHigh:
@@ -142,7 +145,7 @@ func (m *mail) Sender() (snd Sender, err liberr.Error) {
if len(m.attach) > 0 { if len(m.attach) > 0 {
for _, i := range m.attach { for _, i := range m.attach {
if t, er := ioutils.NewFileProgressTemp(); er != nil { if t, er := libiot.NewFileProgressTemp(); er != nil {
return nil, er return nil, er
} else if _, er := t.ReadFrom(i.data); er != nil { } else if _, er := t.ReadFrom(i.data); er != nil {
return nil, ErrorIORead.ErrorParent(er) return nil, ErrorIORead.ErrorParent(er)
@@ -156,7 +159,7 @@ func (m *mail) Sender() (snd Sender, err liberr.Error) {
if len(m.inline) > 0 { if len(m.inline) > 0 {
for _, i := range m.inline { for _, i := range m.inline {
if t, er := ioutils.NewFileProgressTemp(); er != nil { if t, er := libiot.NewFileProgressTemp(); er != nil {
return nil, er return nil, er
} else if _, er := t.ReadFrom(i.data); er != nil { } else if _, er := t.ReadFrom(i.data); er != nil {
return nil, ErrorIORead.ErrorParent(er) return nil, ErrorIORead.ErrorParent(er)
@@ -206,7 +209,7 @@ func (m *mail) Sender() (snd Sender, err liberr.Error) {
s.rcpt = append(s.rcpt, m.Email().GetRecipients(RecipientCC)...) s.rcpt = append(s.rcpt, m.Email().GetRecipients(RecipientCC)...)
s.rcpt = append(s.rcpt, m.Email().GetRecipients(RecipientBCC)...) s.rcpt = append(s.rcpt, m.Email().GetRecipients(RecipientBCC)...)
if tmp, err := ioutils.NewFileProgressTemp(); err != nil { if tmp, err := libiot.NewFileProgressTemp(); err != nil {
return nil, err return nil, err
} else if _, er := tmp.WriteString(e.GetMessage()); er != nil { } else if _, er := tmp.WriteString(e.GetMessage()); er != nil {
return nil, ErrorIOWrite.ErrorParent(er) return nil, ErrorIOWrite.ErrorParent(er)
@@ -222,7 +225,7 @@ func (m *mail) Sender() (snd Sender, err liberr.Error) {
return return
} }
func (s *sender) SendClose(ctx context.Context, cli smtp.SMTP) liberr.Error { func (s *sender) SendClose(ctx context.Context, cli libsmtp.SMTP) liberr.Error {
defer func() { defer func() {
_ = s.Close() _ = s.Close()
}() }()
@@ -234,14 +237,16 @@ func (s *sender) SendClose(ctx context.Context, cli smtp.SMTP) liberr.Error {
return nil return nil
} }
func (s *sender) Send(ctx context.Context, cli smtp.SMTP) liberr.Error { func (s *sender) Send(ctx context.Context, cli libsmtp.SMTP) liberr.Error {
if e := cli.Check(ctx); e != nil { if e := cli.Check(ctx); e != nil {
return ErrorSmtpClient.ErrorParent(e) return ErrorSmtpClient.ErrorParent(e)
} }
if len(s.from) < 4 { if len(s.from) < _MinSizeAddr {
//nolint #goerr113
return ErrorParamsEmpty.ErrorParent(fmt.Errorf("parameters 'from' is not valid")) return ErrorParamsEmpty.ErrorParent(fmt.Errorf("parameters 'from' is not valid"))
} else if len(s.rcpt) < 1 || len(s.rcpt[0]) < 4 { } else if len(s.rcpt) < 1 || len(s.rcpt[0]) < _MinSizeAddr {
//nolint #goerr113
return ErrorParamsEmpty.ErrorParent(fmt.Errorf("parameters 'receipient' is not valid")) return ErrorParamsEmpty.ErrorParent(fmt.Errorf("parameters 'receipient' is not valid"))
} }

View File

@@ -1,83 +0,0 @@
/*
* 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 mail
import (
"bytes"
"encoding/base64"
"mime/quotedprintable"
"strings"
)
// base64Encode base64 encodes the provided text with line wrapping
func base64Encode(text []byte) []byte {
// create buffer
buf := new(bytes.Buffer)
// create base64 encoder that linewraps
encoder := base64.NewEncoder(base64.StdEncoding, &base64LineWrap{writer: buf})
// write the encoded text to buf
/* #nosec */
//nolint #nosec
_, _ = encoder.Write(text)
_ = encoder.Close()
return buf.Bytes()
}
// qpEncode uses the quoted-printable encoding to encode the provided text
func qpEncode(text []byte) []byte {
// create buffer
buf := new(bytes.Buffer)
encoder := quotedprintable.NewWriter(buf)
/* #nosec */
//nolint #nosec
_, _ = encoder.Write(text)
_ = encoder.Close()
return buf.Bytes()
}
func encodeHeader(text string, charset string, usedChars int) string {
// create buffer
buf := new(bytes.Buffer)
// encode
encoder := newEncoder(buf, charset, usedChars)
/* #nosec */
//nolint #nosec
_, _ = encoder.encode([]byte(text))
return buf.String()
}
func escapeQuotes(s string) string {
quoteEscaper := strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
return quoteEscaper.Replace(s)
}

View File

@@ -28,10 +28,10 @@ package mailer
import "github.com/matcornic/hermes/v2" import "github.com/matcornic/hermes/v2"
type email struct { type email struct {
t Themes
d TextDirection
p hermes.Product p hermes.Product
b *hermes.Body b *hermes.Body
t Themes
d TextDirection
c bool c bool
} }

View File

@@ -33,27 +33,14 @@ import (
) )
func (e *email) GenerateHTML() (*bytes.Buffer, liberr.Error) { func (e *email) GenerateHTML() (*bytes.Buffer, liberr.Error) {
var buf = bytes.NewBuffer(make([]byte, 0)) return e.generated(e.genHtml)
h := hermes.Hermes{
Theme: e.t.getHermes(),
TextDirection: e.d.getDirection(),
Product: e.p,
DisableCSSInlining: e.c,
}
if p, e := h.GenerateHTML(hermes.Email{
Body: *e.b,
}); e != nil {
return nil, ErrorMailerHtml.ErrorParent(e)
} else {
buf.WriteString(p)
}
return buf, nil
} }
func (e *email) GeneratePlainText() (*bytes.Buffer, liberr.Error) { func (e *email) GeneratePlainText() (*bytes.Buffer, liberr.Error) {
return e.generated(e.genText)
}
func (e email) generated(f func(h hermes.Hermes, m hermes.Email) (string, error)) (*bytes.Buffer, liberr.Error) {
var buf = bytes.NewBuffer(make([]byte, 0)) var buf = bytes.NewBuffer(make([]byte, 0))
h := hermes.Hermes{ h := hermes.Hermes{
@@ -63,7 +50,7 @@ func (e *email) GeneratePlainText() (*bytes.Buffer, liberr.Error) {
DisableCSSInlining: e.c, DisableCSSInlining: e.c,
} }
if p, e := h.GeneratePlainText(hermes.Email{ if p, e := f(h, hermes.Email{
Body: *e.b, Body: *e.b,
}); e != nil { }); e != nil {
return nil, ErrorMailerText.ErrorParent(e) return nil, ErrorMailerText.ErrorParent(e)
@@ -73,3 +60,11 @@ func (e *email) GeneratePlainText() (*bytes.Buffer, liberr.Error) {
return buf, nil return buf, nil
} }
func (e *email) genText(h hermes.Hermes, m hermes.Email) (string, error) {
return h.GeneratePlainText(m)
}
func (e *email) genHtml(h hermes.Hermes, m hermes.Email) (string, error) {
return h.GenerateHTML(m)
}

View File

@@ -66,6 +66,7 @@ func (o NutsDBOptions) GetNutsDBOptions(dataDir string) nutsdb.Options {
} else { } else {
d.Dir = dataDir d.Dir = dataDir
//nolint #exhaustive
switch o.RWMode { switch o.RWMode {
case nutsdb.MMap: case nutsdb.MMap:
d.RWMode = nutsdb.MMap d.RWMode = nutsdb.MMap
@@ -73,6 +74,7 @@ func (o NutsDBOptions) GetNutsDBOptions(dataDir string) nutsdb.Options {
d.RWMode = nutsdb.FileIO d.RWMode = nutsdb.FileIO
} }
//nolint #exhaustive
switch o.StartFileLoadingMode { switch o.StartFileLoadingMode {
case nutsdb.MMap: case nutsdb.MMap:
d.StartFileLoadingMode = nutsdb.MMap d.StartFileLoadingMode = nutsdb.MMap
@@ -81,6 +83,7 @@ func (o NutsDBOptions) GetNutsDBOptions(dataDir string) nutsdb.Options {
} }
} }
//nolint #exhaustive
switch o.EntryIdxMode { switch o.EntryIdxMode {
case nutsdb.HintKeyAndRAMIdxMode: case nutsdb.HintKeyAndRAMIdxMode:
d.EntryIdxMode = nutsdb.HintKeyAndRAMIdxMode d.EntryIdxMode = nutsdb.HintKeyAndRAMIdxMode

View File

@@ -104,7 +104,7 @@ func (s *snap) Save(opt Options, writer io.Writer) liberr.Error {
_ = t.Close() _ = t.Close()
}() }()
if _, e = archive.CreateArchive(archive.ArchiveTypeTarGzip, t, s.path); e != nil { if _, e = archive.CreateArchive(archive.TypeTarGzip, t, s.path); e != nil {
return ErrorFolderArchive.Error(e) return ErrorFolderArchive.Error(e)
} }

View File

@@ -29,12 +29,30 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
const EMPTY_GROUP = "<nil>" const EmptyHandlerGroup = "<nil>"
var ( var (
defaultRouters = NewRouterList() defaultRouters = NewRouterList(DefaultGinInit)
) )
func DefaultGinInit() *gin.Engine {
engine := gin.New()
engine.Use(gin.Logger(), gin.Recovery())
return engine
}
func DefaultGinWithTrustyProxy(trustyProxy []string) *gin.Engine {
engine := gin.New()
engine.Use(gin.Logger(), gin.Recovery())
if len(trustyProxy) > 0 {
engine.TrustedProxies = trustyProxy
}
return engine
}
type routerItem struct { type routerItem struct {
method string method string
relative string relative string
@@ -42,6 +60,7 @@ type routerItem struct {
} }
type routerList struct { type routerList struct {
init func() *gin.Engine
list map[string][]routerItem list map[string][]routerItem
} }
@@ -52,6 +71,7 @@ type RouterList interface {
Register(method string, relativePath string, router ...gin.HandlerFunc) Register(method string, relativePath string, router ...gin.HandlerFunc)
RegisterInGroup(group, method string, relativePath string, router ...gin.HandlerFunc) RegisterInGroup(group, method string, relativePath string, router ...gin.HandlerFunc)
Handler(engine *gin.Engine) Handler(engine *gin.Engine)
Engine() *gin.Engine
} }
func RoutersRegister(method string, relativePath string, router ...gin.HandlerFunc) { func RoutersRegister(method string, relativePath string, router ...gin.HandlerFunc) {
@@ -66,15 +86,16 @@ func RoutersHandler(engine *gin.Engine) {
defaultRouters.Handler(engine) defaultRouters.Handler(engine)
} }
func NewRouterList() RouterList { func NewRouterList(initGin func() *gin.Engine) RouterList {
return &routerList{ return &routerList{
init: initGin,
list: make(map[string][]routerItem), list: make(map[string][]routerItem),
} }
} }
func (l routerList) Handler(engine *gin.Engine) { func (l routerList) Handler(engine *gin.Engine) {
for grpRoute, grpList := range l.list { for grpRoute, grpList := range l.list {
if grpRoute == EMPTY_GROUP { if grpRoute == EmptyHandlerGroup {
for _, r := range grpList { for _, r := range grpList {
engine.Handle(r.method, r.relative, r.router...) engine.Handle(r.method, r.relative, r.router...)
} }
@@ -89,7 +110,7 @@ func (l routerList) Handler(engine *gin.Engine) {
func (l *routerList) RegisterInGroup(group, method string, relativePath string, router ...gin.HandlerFunc) { func (l *routerList) RegisterInGroup(group, method string, relativePath string, router ...gin.HandlerFunc) {
if group == "" { if group == "" {
group = EMPTY_GROUP group = EmptyHandlerGroup
} }
if _, ok := l.list[group]; !ok { if _, ok := l.list[group]; !ok {
@@ -106,3 +127,11 @@ func (l *routerList) RegisterInGroup(group, method string, relativePath string,
func (l *routerList) Register(method string, relativePath string, router ...gin.HandlerFunc) { func (l *routerList) Register(method string, relativePath string, router ...gin.HandlerFunc) {
l.RegisterInGroup("", method, relativePath, router...) l.RegisterInGroup("", method, relativePath, router...)
} }
func (l routerList) Engine() *gin.Engine {
if l.init != nil {
return l.init()
} else {
return DefaultGinInit()
}
}

View File

@@ -44,14 +44,13 @@ func SetGinHandler(fct func(c *gin.Context)) gin.HandlerFunc {
} }
func Handler(routerList RouterList) http.Handler { func Handler(routerList RouterList) http.Handler {
engine := gin.New() e := routerList.Engine()
engine.Use(gin.Logger(), gin.Recovery())
if routerList == nil { if routerList == nil {
RoutersHandler(engine) RoutersHandler(e)
} else { } else {
routerList.Handler(engine) routerList.Handler(e)
} }
return engine return e
} }

View File

@@ -70,17 +70,6 @@ func (s *smtpClient) dial(ctx context.Context, addr string) (con net.Conn, err l
return return
} }
func (s *smtpClient) dialStarttls(ctx context.Context, addr string, tlsConfig *tls.Config) (con net.Conn, err liberr.Error) {
defer func() {
if err != nil && con != nil {
_ = con.Close()
}
}()
con, err = s.dial(ctx, addr)
return
}
func (s *smtpClient) client(ctx context.Context, addr string, tlsConfig *tls.Config) (cli *smtp.Client, con net.Conn, err liberr.Error) { func (s *smtpClient) client(ctx context.Context, addr string, tlsConfig *tls.Config) (cli *smtp.Client, con net.Conn, err liberr.Error) {
var e error var e error

View File

@@ -120,7 +120,7 @@ func (s *smtpClient) Client(ctx context.Context) (*smtp.Client, errors.Error) {
return s.cli, nil return s.cli, nil
} }
// validateLine checks to see if a line has CR or LF as per RFC 5321 // validateLine checks to see if a line has CR or LF as per RFC 5321.
func (s smtpClient) validateLine(line string) errors.Error { func (s smtpClient) validateLine(line string) errors.Error {
if strings.ContainsAny(line, "\n\r") { if strings.ContainsAny(line, "\n\r") {
return ErrorSMTPLineCRLF.Error(nil) return ErrorSMTPLineCRLF.Error(nil)

View File

@@ -29,10 +29,9 @@ import (
"net/http" "net/http"
"sync/atomic" "sync/atomic"
"github.com/nabbar/golib/version"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/nabbar/golib/router" librtr "github.com/nabbar/golib/router"
libver "github.com/nabbar/golib/version"
) )
const statusOK = "OK" const statusOK = "OK"
@@ -82,8 +81,8 @@ type RouteStatus interface {
HttpStatusCode(codeOk, codeKO, codeWarning int) HttpStatusCode(codeOk, codeKO, codeWarning int)
Get(c *gin.Context) Get(c *gin.Context)
Register(prefix string, register router.RegisterRouter) Register(prefix string, register librtr.RegisterRouter)
RegisterGroup(group, prefix string, register router.RegisterRouterInGroup) RegisterGroup(group, prefix string, register librtr.RegisterRouterInGroup)
ComponentNew(key string, cpt Component) ComponentNew(key string, cpt Component)
ComponentDel(key string) ComponentDel(key string)
@@ -102,10 +101,10 @@ func New(Name string, Release string, Hash string, msgOk string, msgKo string, m
cKO: http.StatusServiceUnavailable, cKO: http.StatusServiceUnavailable,
mWM: msgWarm, mWM: msgWarm,
cWM: http.StatusOK, cWM: http.StatusOK,
c: make(map[string]*atomic.Value, 0), c: make(map[string]*atomic.Value),
} }
} }
func NewVersion(version version.Version, msgOk string, msgKO string, msgWarm string) RouteStatus { func NewVersion(version libver.Version, msgOk string, msgKO string, msgWarm string) RouteStatus {
return New(version.GetPackage(), version.GetRelease(), version.GetBuild(), msgOk, msgKO, msgWarm) return New(version.GetPackage(), version.GetRelease(), version.GetBuild(), msgOk, msgKO, msgWarm)
} }

View File

@@ -31,12 +31,11 @@ import (
"strings" "strings"
"sync/atomic" "sync/atomic"
"github.com/gin-gonic/gin"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
librtr "github.com/nabbar/golib/router"
"github.com/gin-gonic/gin" libsem "github.com/nabbar/golib/semaphore"
"github.com/nabbar/golib/router"
"github.com/nabbar/golib/semaphore"
) )
type rtrStatus struct { type rtrStatus struct {
@@ -74,7 +73,7 @@ func (r *rtrStatus) cleanPrefix(prefix string) string {
return path.Clean(strings.TrimRight(path.Join("/", prefix), "/")) return path.Clean(strings.TrimRight(path.Join("/", prefix), "/"))
} }
func (r *rtrStatus) Register(prefix string, register router.RegisterRouter) { func (r *rtrStatus) Register(prefix string, register librtr.RegisterRouter) {
prefix = r.cleanPrefix(prefix) prefix = r.cleanPrefix(prefix)
var m = r.m var m = r.m
@@ -86,7 +85,7 @@ func (r *rtrStatus) Register(prefix string, register router.RegisterRouter) {
} }
} }
func (r *rtrStatus) RegisterGroup(group, prefix string, register router.RegisterRouterInGroup) { func (r *rtrStatus) RegisterGroup(group, prefix string, register librtr.RegisterRouterInGroup) {
prefix = r.cleanPrefix(prefix) prefix = r.cleanPrefix(prefix)
var m = r.m var m = r.m
@@ -107,7 +106,7 @@ func (r *rtrStatus) Get(x *gin.Context) {
key string key string
err liberr.Error err liberr.Error
rsp *Response rsp *Response
sem semaphore.Sem sem libsem.Sem
) )
defer func() { defer func() {
@@ -130,7 +129,7 @@ func (r *rtrStatus) Get(x *gin.Context) {
Components: make([]CptResponse, 0), Components: make([]CptResponse, 0),
} }
sem = semaphore.NewSemaphoreWithContext(x, 0) sem = libsem.NewSemaphoreWithContext(x, 0)
for key, atm = range r.c { for key, atm = range r.c {
if atm == nil { if atm == nil {
@@ -182,7 +181,7 @@ func (r *rtrStatus) Get(x *gin.Context) {
func (r *rtrStatus) ComponentNew(key string, cpt Component) { func (r *rtrStatus) ComponentNew(key string, cpt Component) {
if len(r.c) < 1 { if len(r.c) < 1 {
r.c = make(map[string]*atomic.Value, 0) r.c = make(map[string]*atomic.Value)
} }
if _, ok := r.c[key]; !ok { if _, ok := r.c[key]; !ok {

View File

@@ -75,6 +75,8 @@ func main() {
} }
} }
//nolint #gosec
/* #nosec */
if file, err := os.OpenFile(LoggerFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666); err != nil { if file, err := os.OpenFile(LoggerFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666); err != nil {
panic(err) panic(err)
} else { } else {