Compare commits
3 Commits
v0.1
...
a128b473ff
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a128b473ff | ||
|
|
ee5d40cfee | ||
|
|
3ebd2b48d1 |
747
.golangci.yml
747
.golangci.yml
@@ -1,29 +1,12 @@
|
|||||||
|
version: "2"
|
||||||
run:
|
run:
|
||||||
tests: false
|
go: "1.25"
|
||||||
modules-download-mode: readonly
|
modules-download-mode: readonly
|
||||||
|
tests: false
|
||||||
allow-parallel-runners: true
|
allow-parallel-runners: true
|
||||||
go: '1.24'
|
|
||||||
issues:
|
|
||||||
exclude-dirs:
|
|
||||||
- data
|
|
||||||
- vendor
|
|
||||||
output:
|
|
||||||
sort-results: true
|
|
||||||
linters-settings:
|
|
||||||
gosec:
|
|
||||||
excludes:
|
|
||||||
# Оно не используется для повышения безопасности или каких-то таких секъюрых вещей, оно используется для выборки
|
|
||||||
# произвольного элемента из массива, так что ИДИ НАХУЙ с этой проверкой и не еби мозги липовой безопасностью.
|
|
||||||
- G404 # Insecure random number source (rand)
|
|
||||||
linters:
|
linters:
|
||||||
disable-all: true
|
default: none
|
||||||
enable:
|
enable:
|
||||||
- errcheck
|
|
||||||
- gosimple
|
|
||||||
- govet
|
|
||||||
- ineffassign
|
|
||||||
- staticcheck
|
|
||||||
- unused
|
|
||||||
- asasalint
|
- asasalint
|
||||||
- asciicheck
|
- asciicheck
|
||||||
- bodyclose
|
- bodyclose
|
||||||
@@ -31,25 +14,30 @@ linters:
|
|||||||
- contextcheck
|
- contextcheck
|
||||||
- decorder
|
- decorder
|
||||||
- durationcheck
|
- durationcheck
|
||||||
|
- errcheck
|
||||||
- errchkjson
|
- errchkjson
|
||||||
- errorlint
|
- errorlint
|
||||||
- exhaustive
|
- exhaustive
|
||||||
- exhaustruct
|
- exptostd
|
||||||
- copyloopvar
|
|
||||||
- ginkgolinter
|
- ginkgolinter
|
||||||
- gocheckcompilerdirectives
|
- gocheckcompilerdirectives
|
||||||
- gocritic
|
- gocritic
|
||||||
|
- godoclint
|
||||||
- godot
|
- godot
|
||||||
- err113
|
- godox
|
||||||
- gofmt
|
- goprintffuncname
|
||||||
- goimports
|
|
||||||
- gosec
|
- gosec
|
||||||
- gosmopolitan
|
- gosmopolitan
|
||||||
|
- govet
|
||||||
- grouper
|
- grouper
|
||||||
- importas
|
- importas
|
||||||
|
- ineffassign
|
||||||
|
- intrange
|
||||||
- ireturn
|
- ireturn
|
||||||
- makezero
|
- makezero
|
||||||
- mirror
|
- mirror
|
||||||
|
- misspell
|
||||||
|
- modernize
|
||||||
- nakedret
|
- nakedret
|
||||||
- nilerr
|
- nilerr
|
||||||
- nilnil
|
- nilnil
|
||||||
@@ -57,13 +45,714 @@ linters:
|
|||||||
- noctx
|
- noctx
|
||||||
- nolintlint
|
- nolintlint
|
||||||
- nonamedreturns
|
- nonamedreturns
|
||||||
|
- perfsprint
|
||||||
- predeclared
|
- predeclared
|
||||||
- promlinter
|
- promlinter
|
||||||
- reassign
|
- reassign
|
||||||
- revive
|
- revive
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- stylecheck
|
- staticcheck
|
||||||
- unconvert
|
- unconvert
|
||||||
|
- unused
|
||||||
|
- usestdlibvars
|
||||||
- wastedassign
|
- wastedassign
|
||||||
- whitespace
|
- wsl_v5
|
||||||
- wsl
|
settings:
|
||||||
|
decorder:
|
||||||
|
dec-order:
|
||||||
|
- type
|
||||||
|
- const
|
||||||
|
- var
|
||||||
|
- func
|
||||||
|
gocritic:
|
||||||
|
disable-all: false
|
||||||
|
enable-all: true
|
||||||
|
disabled-checks:
|
||||||
|
- singleCaseSwitch
|
||||||
|
- octalLiteral
|
||||||
|
- regexpSimplify
|
||||||
|
- paramTypeCombine
|
||||||
|
- whyNoLint
|
||||||
|
- hugeParam
|
||||||
|
godoclint:
|
||||||
|
default: all
|
||||||
|
ignore-unexported: false
|
||||||
|
ignore-exported: false
|
||||||
|
include-unexported: true
|
||||||
|
disable:
|
||||||
|
- max-len
|
||||||
|
godot:
|
||||||
|
scope: all
|
||||||
|
exclude:
|
||||||
|
# Exclude todo and fixme comments.
|
||||||
|
- "^fixme:"
|
||||||
|
- "^todo:"
|
||||||
|
period: true
|
||||||
|
capital: false
|
||||||
|
godox:
|
||||||
|
keywords:
|
||||||
|
- FIXME
|
||||||
|
gosec: # go-fucking-sic
|
||||||
|
excludes:
|
||||||
|
# Боже, как же вы затрахали своей крипто-ебучкой, наркоманы хреновы!
|
||||||
|
- G405 # Detect the usage of DES or RC4
|
||||||
|
- G406 # Detect the usage of MD4 or RIPEMD160
|
||||||
|
# Оно не используется для повышения безопасности или каких-то таких секъюрных вещей, оно используется для выборки
|
||||||
|
# произвольного элемента из массива, так что ИДИ НАХУЙ с этой проверкой и не еби мозги липовой безопасностью.
|
||||||
|
- G404 # Insecure random number source (rand)
|
||||||
|
- G501 # Import blocklist: crypto/md5
|
||||||
|
- G502 # Import blocklist: crypto/des
|
||||||
|
- G503 # Import blocklist: crypto/rc4
|
||||||
|
- G504 # Import blocklist: net/http/cgi
|
||||||
|
- G505 # Import blocklist: crypto/sha1
|
||||||
|
- G506 # Import blocklist: golang.org/x/crypto/md4
|
||||||
|
- G507 # Import blocklist: golang.org/x/crypto/ripemd160
|
||||||
|
config:
|
||||||
|
global:
|
||||||
|
audit: true
|
||||||
|
# Ваша сраная паранойя при создании файлов и каталогов мешает нормальной работе сервисов. Группы придуманы для
|
||||||
|
# удобства, группе удобно давать право чтения. Поэтому идите нахуй со своими ограничениями на чтение для
|
||||||
|
# группы, "безопасные" клоуны.
|
||||||
|
G301: "0755"
|
||||||
|
G306: "0644"
|
||||||
|
govet:
|
||||||
|
disable-all: false
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- shadow
|
||||||
|
- fieldalignment
|
||||||
|
grouper:
|
||||||
|
# Require the use of a single global 'const' declaration only.
|
||||||
|
# Default: false
|
||||||
|
const-require-single-const: true
|
||||||
|
# Require the use of grouped global 'const' declarations.
|
||||||
|
# Default: false
|
||||||
|
const-require-grouping: true
|
||||||
|
# Require the use of a single 'import' declaration only.
|
||||||
|
# Default: false
|
||||||
|
import-require-single-import: true
|
||||||
|
# Require the use of grouped 'import' declarations.
|
||||||
|
# Default: false
|
||||||
|
import-require-grouping: true
|
||||||
|
# Require the use of a single global 'type' declaration only.
|
||||||
|
# Default: false
|
||||||
|
type-require-single-type: true
|
||||||
|
# Require the use of grouped global 'type' declarations.
|
||||||
|
# Default: false
|
||||||
|
type-require-grouping: true
|
||||||
|
# Require the use of a single global 'var' declaration only.
|
||||||
|
# Default: false
|
||||||
|
var-require-single-var: true
|
||||||
|
# Require the use of grouped global 'var' declarations.
|
||||||
|
# Default: false
|
||||||
|
var-require-grouping: true
|
||||||
|
misspell:
|
||||||
|
# Correct spellings using locale preferences for US or UK.
|
||||||
|
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
|
||||||
|
# Default is to use a neutral variety of English.
|
||||||
|
locale: US
|
||||||
|
# Typos to ignore.
|
||||||
|
# Should be in lower case.
|
||||||
|
# Default: []
|
||||||
|
ignore-rules:
|
||||||
|
- someword
|
||||||
|
# Extra word corrections.
|
||||||
|
# `typo` and `correction` should only contain letters.
|
||||||
|
# The words are case-insensitive.
|
||||||
|
# Default: []
|
||||||
|
extra-words:
|
||||||
|
- typo: "iff"
|
||||||
|
correction: "if"
|
||||||
|
- typo: "cancelation"
|
||||||
|
correction: "cancellation"
|
||||||
|
# Mode of the analysis:
|
||||||
|
# - default: checks all the file content.
|
||||||
|
# - restricted: checks only comments.
|
||||||
|
# Default: ""
|
||||||
|
mode: restricted
|
||||||
|
nonamedreturns:
|
||||||
|
# Report named error if it is assigned inside defer.
|
||||||
|
# Default: false
|
||||||
|
report-error-in-defer: true
|
||||||
|
perfsprint:
|
||||||
|
integer-format: true
|
||||||
|
int-conversion: true
|
||||||
|
error-format: true
|
||||||
|
err-error: false
|
||||||
|
errorf: true
|
||||||
|
string-format: true
|
||||||
|
sprintf1: true
|
||||||
|
strconcat: true
|
||||||
|
bool-format: true
|
||||||
|
hex-format: true
|
||||||
|
concat-loop: true
|
||||||
|
loop-other-ops: false
|
||||||
|
revive:
|
||||||
|
enable-all-rules: false
|
||||||
|
staticcheck:
|
||||||
|
# https://staticcheck.dev/docs/configuration/options/#dot_import_whitelist
|
||||||
|
# Default: ["github.com/mmcloughlin/avo/build", "github.com/mmcloughlin/avo/operand", "github.com/mmcloughlin/avo/reg"]
|
||||||
|
dot-import-whitelist:
|
||||||
|
- fmt
|
||||||
|
# https://staticcheck.dev/docs/configuration/options/#initialisms
|
||||||
|
# Default: ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"]
|
||||||
|
initialisms: ["ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"]
|
||||||
|
# https://staticcheck.dev/docs/configuration/options/#http_status_code_whitelist
|
||||||
|
# Default: ["200", "400", "404", "500"]
|
||||||
|
http-status-code-whitelist: ["200", "400", "404", "500"]
|
||||||
|
# SAxxxx checks in https://staticcheck.dev/docs/configuration/options/#checks
|
||||||
|
# Example (to disable some checks): [ "all", "-SA1000", "-SA1001"]
|
||||||
|
# Run `GL_DEBUG=staticcheck golangci-lint run --enable=staticcheck` to see all available checks and enabled by config checks.
|
||||||
|
# Default: ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1020", "-ST1021", "-ST1022"]
|
||||||
|
checks:
|
||||||
|
# Invalid regular expression.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1000
|
||||||
|
- SA1000
|
||||||
|
# Invalid template.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1001
|
||||||
|
- SA1001
|
||||||
|
# Invalid format in 'time.Parse'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1002
|
||||||
|
- SA1002
|
||||||
|
# Unsupported argument to functions in 'encoding/binary'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1003
|
||||||
|
- SA1003
|
||||||
|
# Suspiciously small untyped constant in 'time.Sleep'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1004
|
||||||
|
- SA1004
|
||||||
|
# Invalid first argument to 'exec.Command'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1005
|
||||||
|
- SA1005
|
||||||
|
# 'Printf' with dynamic first argument and no further arguments.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1006
|
||||||
|
- SA1006
|
||||||
|
# Invalid URL in 'net/url.Parse'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1007
|
||||||
|
- SA1007
|
||||||
|
# Non-canonical key in 'http.Header' map.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1008
|
||||||
|
- SA1008
|
||||||
|
# '(*regexp.Regexp).FindAll' called with 'n == 0', which will always return zero results.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1010
|
||||||
|
- SA1010
|
||||||
|
# Various methods in the "strings" package expect valid UTF-8, but invalid input is provided.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1011
|
||||||
|
- SA1011
|
||||||
|
# A nil 'context.Context' is being passed to a function, consider using 'context.TODO' instead.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1012
|
||||||
|
- SA1012
|
||||||
|
# 'io.Seeker.Seek' is being called with the whence constant as the first argument, but it should be the second.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1013
|
||||||
|
- SA1013
|
||||||
|
# Non-pointer value passed to 'Unmarshal' or 'Decode'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1014
|
||||||
|
- SA1014
|
||||||
|
# Using 'time.Tick' in a way that will leak. Consider using 'time.NewTicker', and only use 'time.Tick' in tests, commands and endless functions.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1015
|
||||||
|
- SA1015
|
||||||
|
# Trapping a signal that cannot be trapped.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1016
|
||||||
|
- SA1016
|
||||||
|
# Channels used with 'os/signal.Notify' should be buffered.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1017
|
||||||
|
- SA1017
|
||||||
|
# 'strings.Replace' called with 'n == 0', which does nothing.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1018
|
||||||
|
- SA1018
|
||||||
|
# Using a deprecated function, variable, constant or field.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1019
|
||||||
|
- SA1019
|
||||||
|
# Using an invalid host:port pair with a 'net.Listen'-related function.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1020
|
||||||
|
- SA1020
|
||||||
|
# Using 'bytes.Equal' to compare two 'net.IP'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1021
|
||||||
|
- SA1021
|
||||||
|
# Modifying the buffer in an 'io.Writer' implementation.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1023
|
||||||
|
- SA1023
|
||||||
|
# A string cutset contains duplicate characters.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1024
|
||||||
|
- SA1024
|
||||||
|
# It is not possible to use '(*time.Timer).Reset''s return value correctly.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1025
|
||||||
|
- SA1025
|
||||||
|
# Cannot marshal channels or functions.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1026
|
||||||
|
- SA1026
|
||||||
|
# Atomic access to 64-bit variable must be 64-bit aligned.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1027
|
||||||
|
- SA1027
|
||||||
|
# 'sort.Slice' can only be used on slices.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1028
|
||||||
|
- SA1028
|
||||||
|
# Inappropriate key in call to 'context.WithValue'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1029
|
||||||
|
- SA1029
|
||||||
|
# Invalid argument in call to a 'strconv' function.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1030
|
||||||
|
- SA1030
|
||||||
|
# Overlapping byte slices passed to an encoder.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1031
|
||||||
|
- SA1031
|
||||||
|
# Wrong order of arguments to 'errors.Is'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA1032
|
||||||
|
- SA1032
|
||||||
|
# 'sync.WaitGroup.Add' called inside the goroutine, leading to a race condition.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA2000
|
||||||
|
- SA2000
|
||||||
|
# Empty critical section, did you mean to defer the unlock?.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA2001
|
||||||
|
- SA2001
|
||||||
|
# Called 'testing.T.FailNow' or 'SkipNow' in a goroutine, which isn't allowed.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA2002
|
||||||
|
- SA2002
|
||||||
|
# Deferred 'Lock' right after locking, likely meant to defer 'Unlock' instead.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA2003
|
||||||
|
- SA2003
|
||||||
|
# 'TestMain' doesn't call 'os.Exit', hiding test failures.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA3000
|
||||||
|
- SA3000
|
||||||
|
# Assigning to 'b.N' in benchmarks distorts the results.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA3001
|
||||||
|
- SA3001
|
||||||
|
# Binary operator has identical expressions on both sides.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4000
|
||||||
|
- SA4000
|
||||||
|
# '&*x' gets simplified to 'x', it does not copy 'x'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4001
|
||||||
|
- SA4001
|
||||||
|
# Comparing unsigned values against negative values is pointless.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4003
|
||||||
|
- SA4003
|
||||||
|
# The loop exits unconditionally after one iteration.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4004
|
||||||
|
- SA4004
|
||||||
|
# Field assignment that will never be observed. Did you mean to use a pointer receiver?.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4005
|
||||||
|
- SA4005
|
||||||
|
# A value assigned to a variable is never read before being overwritten. Forgotten error check or dead code?.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4006
|
||||||
|
- SA4006
|
||||||
|
# The variable in the loop condition never changes, are you incrementing the wrong variable?.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4008
|
||||||
|
- SA4008
|
||||||
|
# A function argument is overwritten before its first use.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4009
|
||||||
|
- SA4009
|
||||||
|
# The result of 'append' will never be observed anywhere.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4010
|
||||||
|
- SA4010
|
||||||
|
# Break statement with no effect. Did you mean to break out of an outer loop?.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4011
|
||||||
|
- SA4011
|
||||||
|
# Comparing a value against NaN even though no value is equal to NaN.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4012
|
||||||
|
- SA4012
|
||||||
|
# Negating a boolean twice ('!!b') is the same as writing 'b'. This is either redundant, or a typo.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4013
|
||||||
|
- SA4013
|
||||||
|
# An if/else if chain has repeated conditions and no side-effects; if the condition didn't match the first time, it won't match the second time, either.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4014
|
||||||
|
- SA4014
|
||||||
|
# Calling functions like 'math.Ceil' on floats converted from integers doesn't do anything useful.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4015
|
||||||
|
- SA4015
|
||||||
|
# Certain bitwise operations, such as 'x ^ 0', do not do anything useful.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4016
|
||||||
|
- SA4016
|
||||||
|
# Discarding the return values of a function without side effects, making the call pointless.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4017
|
||||||
|
- SA4017
|
||||||
|
# Self-assignment of variables.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4018
|
||||||
|
- SA4018
|
||||||
|
# Multiple, identical build constraints in the same file.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4019
|
||||||
|
- SA4019
|
||||||
|
# Unreachable case clause in a type switch.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4020
|
||||||
|
- SA4020
|
||||||
|
# "x = append(y)" is equivalent to "x = y".
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4021
|
||||||
|
- SA4021
|
||||||
|
# Comparing the address of a variable against nil.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4022
|
||||||
|
- SA4022
|
||||||
|
# Impossible comparison of interface value with untyped nil.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4023
|
||||||
|
- SA4023
|
||||||
|
# Checking for impossible return value from a builtin function.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4024
|
||||||
|
- SA4024
|
||||||
|
# Integer division of literals that results in zero.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4025
|
||||||
|
- SA4025
|
||||||
|
# Go constants cannot express negative zero.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4026
|
||||||
|
- SA4026
|
||||||
|
# '(*net/url.URL).Query' returns a copy, modifying it doesn't change the URL.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4027
|
||||||
|
- SA4027
|
||||||
|
# 'x % 1' is always zero.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4028
|
||||||
|
- SA4028
|
||||||
|
# Ineffective attempt at sorting slice.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4029
|
||||||
|
- SA4029
|
||||||
|
# Ineffective attempt at generating random number.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4030
|
||||||
|
- SA4030
|
||||||
|
# Checking never-nil value against nil.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4031
|
||||||
|
- SA4031
|
||||||
|
# Comparing 'runtime.GOOS' or 'runtime.GOARCH' against impossible value.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA4032
|
||||||
|
- SA4032
|
||||||
|
# Assignment to nil map.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5000
|
||||||
|
- SA5000
|
||||||
|
# Deferring 'Close' before checking for a possible error.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5001
|
||||||
|
- SA5001
|
||||||
|
# The empty for loop ("for {}") spins and can block the scheduler.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5002
|
||||||
|
- SA5002
|
||||||
|
# Defers in infinite loops will never execute.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5003
|
||||||
|
- SA5003
|
||||||
|
# "for { select { ..." with an empty default branch spins.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5004
|
||||||
|
- SA5004
|
||||||
|
# The finalizer references the finalized object, preventing garbage collection.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5005
|
||||||
|
- SA5005
|
||||||
|
# Infinite recursive call.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5007
|
||||||
|
- SA5007
|
||||||
|
# Invalid struct tag.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5008
|
||||||
|
- SA5008
|
||||||
|
# Invalid Printf call.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5009
|
||||||
|
- SA5009
|
||||||
|
# Impossible type assertion.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5010
|
||||||
|
- SA5010
|
||||||
|
# Possible nil pointer dereference.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5011
|
||||||
|
- SA5011
|
||||||
|
# Passing odd-sized slice to function expecting even size.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA5012
|
||||||
|
- SA5012
|
||||||
|
# Using 'regexp.Match' or related in a loop, should use 'regexp.Compile'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA6000
|
||||||
|
- SA6000
|
||||||
|
# Missing an optimization opportunity when indexing maps by byte slices.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA6001
|
||||||
|
- SA6001
|
||||||
|
# Storing non-pointer values in 'sync.Pool' allocates memory.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA6002
|
||||||
|
- SA6002
|
||||||
|
# Converting a string to a slice of runes before ranging over it.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA6003
|
||||||
|
- SA6003
|
||||||
|
# Inefficient string comparison with 'strings.ToLower' or 'strings.ToUpper'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA6005
|
||||||
|
- SA6005
|
||||||
|
# Using io.WriteString to write '[]byte'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA6006
|
||||||
|
- SA6006
|
||||||
|
# Defers in range loops may not run when you expect them to.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA9001
|
||||||
|
- SA9001
|
||||||
|
# Using a non-octal 'os.FileMode' that looks like it was meant to be in octal.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA9002
|
||||||
|
- SA9002
|
||||||
|
# Empty body in an if or else branch.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA9003
|
||||||
|
- SA9003
|
||||||
|
# Only the first constant has an explicit type.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA9004
|
||||||
|
- SA9004
|
||||||
|
# Trying to marshal a struct with no public fields nor custom marshaling.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA9005
|
||||||
|
- SA9005
|
||||||
|
# Dubious bit shifting of a fixed size integer value.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA9006
|
||||||
|
- SA9006
|
||||||
|
# Deleting a directory that shouldn't be deleted.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA9007
|
||||||
|
- SA9007
|
||||||
|
# 'else' branch of a type assertion is probably not reading the right value.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA9008
|
||||||
|
- SA9008
|
||||||
|
# Ineffectual Go compiler directive.
|
||||||
|
# https://staticcheck.dev/docs/checks/#SA9009
|
||||||
|
- SA9009
|
||||||
|
# Incorrect or missing package comment.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1000
|
||||||
|
- ST1000
|
||||||
|
# Dot imports are discouraged.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1001
|
||||||
|
- ST1001
|
||||||
|
# Poorly chosen identifier.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1003
|
||||||
|
- ST1003
|
||||||
|
# Incorrectly formatted error string.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1005
|
||||||
|
- ST1005
|
||||||
|
# Poorly chosen receiver name.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1006
|
||||||
|
- ST1006
|
||||||
|
# A function's error value should be its last return value.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1008
|
||||||
|
- ST1008
|
||||||
|
# Poorly chosen name for variable of type 'time.Duration'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1011
|
||||||
|
- ST1011
|
||||||
|
# Poorly chosen name for error variable.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1012
|
||||||
|
- ST1012
|
||||||
|
# Should use constants for HTTP error codes, not magic numbers.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1013
|
||||||
|
- ST1013
|
||||||
|
# A switch's default case should be the first or last case.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1015
|
||||||
|
- ST1015
|
||||||
|
# Use consistent method receiver names.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1016
|
||||||
|
- ST1016
|
||||||
|
# Don't use Yoda conditions.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1017
|
||||||
|
- ST1017
|
||||||
|
# Avoid zero-width and control characters in string literals.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1018
|
||||||
|
- ST1018
|
||||||
|
# Importing the same package multiple times.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1019
|
||||||
|
- ST1019
|
||||||
|
# The documentation of an exported function should start with the function's name.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1020
|
||||||
|
- ST1020
|
||||||
|
# The documentation of an exported type should start with type's name.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1021
|
||||||
|
- ST1021
|
||||||
|
# The documentation of an exported variable or constant should start with variable's name.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1022
|
||||||
|
- ST1022
|
||||||
|
# Redundant type in variable declaration.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1023
|
||||||
|
- ST1023
|
||||||
|
# Use plain channel send or receive instead of single-case select.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1000
|
||||||
|
- S1000
|
||||||
|
# Replace for loop with call to copy.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1001
|
||||||
|
- S1001
|
||||||
|
# Omit comparison with boolean constant.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1002
|
||||||
|
- S1002
|
||||||
|
# Replace call to 'strings.Index' with 'strings.Contains'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1003
|
||||||
|
- S1003
|
||||||
|
# Replace call to 'bytes.Compare' with 'bytes.Equal'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1004
|
||||||
|
- S1004
|
||||||
|
# Drop unnecessary use of the blank identifier.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1005
|
||||||
|
- S1005
|
||||||
|
# Use "for { ... }" for infinite loops.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1006
|
||||||
|
- S1006
|
||||||
|
# Simplify regular expression by using raw string literal.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1007
|
||||||
|
- S1007
|
||||||
|
# Simplify returning boolean expression.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1008
|
||||||
|
- S1008
|
||||||
|
# Omit redundant nil check on slices, maps, and channels.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1009
|
||||||
|
- S1009
|
||||||
|
# Omit default slice index.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1010
|
||||||
|
- S1010
|
||||||
|
# Use a single 'append' to concatenate two slices.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1011
|
||||||
|
- S1011
|
||||||
|
# Replace 'time.Now().Sub(x)' with 'time.Since(x)'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1012
|
||||||
|
- S1012
|
||||||
|
# Use a type conversion instead of manually copying struct fields.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1016
|
||||||
|
- S1016
|
||||||
|
# Replace manual trimming with 'strings.TrimPrefix'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1017
|
||||||
|
- S1017
|
||||||
|
# Use "copy" for sliding elements.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1018
|
||||||
|
- S1018
|
||||||
|
# Simplify "make" call by omitting redundant arguments.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1019
|
||||||
|
- S1019
|
||||||
|
# Omit redundant nil check in type assertion.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1020
|
||||||
|
- S1020
|
||||||
|
# Merge variable declaration and assignment.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1021
|
||||||
|
- S1021
|
||||||
|
# Omit redundant control flow.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1023
|
||||||
|
- S1023
|
||||||
|
# Replace 'x.Sub(time.Now())' with 'time.Until(x)'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1024
|
||||||
|
- S1024
|
||||||
|
# Don't use 'fmt.Sprintf("%s", x)' unnecessarily.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1025
|
||||||
|
- S1025
|
||||||
|
# Simplify error construction with 'fmt.Errorf'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1028
|
||||||
|
- S1028
|
||||||
|
# Range over the string directly.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1029
|
||||||
|
- S1029
|
||||||
|
# Use 'bytes.Buffer.String' or 'bytes.Buffer.Bytes'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1030
|
||||||
|
- S1030
|
||||||
|
# Omit redundant nil check around loop.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1031
|
||||||
|
- S1031
|
||||||
|
# Use 'sort.Ints(x)', 'sort.Float64s(x)', and 'sort.Strings(x)'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1032
|
||||||
|
- S1032
|
||||||
|
# Unnecessary guard around call to "delete".
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1033
|
||||||
|
- S1033
|
||||||
|
# Use result of type assertion to simplify cases.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1034
|
||||||
|
- S1034
|
||||||
|
# Redundant call to 'net/http.CanonicalHeaderKey' in method call on 'net/http.Header'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1035
|
||||||
|
- S1035
|
||||||
|
# Unnecessary guard around map access.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1036
|
||||||
|
- S1036
|
||||||
|
# Elaborate way of sleeping.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1037
|
||||||
|
- S1037
|
||||||
|
# Unnecessarily complex way of printing formatted string.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1038
|
||||||
|
- S1038
|
||||||
|
# Unnecessary use of 'fmt.Sprint'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1039
|
||||||
|
- S1039
|
||||||
|
# Type assertion to current type.
|
||||||
|
# https://staticcheck.dev/docs/checks/#S1040
|
||||||
|
- S1040
|
||||||
|
# Apply De Morgan's law.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1001
|
||||||
|
- QF1001
|
||||||
|
# Convert untagged switch to tagged switch.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1002
|
||||||
|
- QF1002
|
||||||
|
# Convert if/else-if chain to tagged switch.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1003
|
||||||
|
- QF1003
|
||||||
|
# Use 'strings.ReplaceAll' instead of 'strings.Replace' with 'n == -1'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1004
|
||||||
|
- QF1004
|
||||||
|
# Expand call to 'math.Pow'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1005
|
||||||
|
- QF1005
|
||||||
|
# Lift 'if'+'break' into loop condition.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1006
|
||||||
|
- QF1006
|
||||||
|
# Merge conditional assignment into variable declaration.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1007
|
||||||
|
- QF1007
|
||||||
|
# Omit embedded fields from selector expression.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1008
|
||||||
|
- QF1008
|
||||||
|
# Use 'time.Time.Equal' instead of '==' operator.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1009
|
||||||
|
- QF1009
|
||||||
|
# Convert slice of bytes to string when printing it.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1010
|
||||||
|
- QF1010
|
||||||
|
# Omit redundant type from variable declaration.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1011
|
||||||
|
- QF1011
|
||||||
|
# Use 'fmt.Fprintf(x, ...)' instead of 'x.Write(fmt.Sprintf(...))'.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1012
|
||||||
|
- QF1012
|
||||||
|
unconvert:
|
||||||
|
# Remove conversions that force intermediate rounding.
|
||||||
|
# Default: false
|
||||||
|
fast-math: true
|
||||||
|
# Be more conservative (experimental).
|
||||||
|
# Default: false
|
||||||
|
safe: true
|
||||||
|
usestdlibvars:
|
||||||
|
# Suggest the use of http.MethodXX.
|
||||||
|
# Default: true
|
||||||
|
http-method: false
|
||||||
|
# Suggest the use of http.StatusXX.
|
||||||
|
# Default: true
|
||||||
|
http-status-code: false
|
||||||
|
# Suggest the use of time.Month in time.Date.
|
||||||
|
# Default: false
|
||||||
|
time-date-month: true
|
||||||
|
# Suggest the use of time.Weekday.String().
|
||||||
|
# Default: true
|
||||||
|
time-weekday: true
|
||||||
|
# Suggest the use of time.Month.String().
|
||||||
|
# Default: false
|
||||||
|
time-month: true
|
||||||
|
# Suggest the use of time.Layout.
|
||||||
|
# Default: false
|
||||||
|
time-layout: true
|
||||||
|
# Suggest the use of crypto.Hash.String().
|
||||||
|
# Default: false
|
||||||
|
crypto-hash: true
|
||||||
|
# Suggest the use of rpc.DefaultXXPath.
|
||||||
|
# Default: false
|
||||||
|
default-rpc-path: true
|
||||||
|
# Suggest the use of sql.LevelXX.String().
|
||||||
|
# Default: false
|
||||||
|
sql-isolation-level: true
|
||||||
|
# Suggest the use of tls.SignatureScheme.String().
|
||||||
|
# Default: false
|
||||||
|
tls-signature-scheme: true
|
||||||
|
# Suggest the use of constant.Kind.String().
|
||||||
|
# Default: false
|
||||||
|
constant-kind: true
|
||||||
|
wsl_v5:
|
||||||
|
allow-first-in-block: true
|
||||||
|
allow-whole-block: true
|
||||||
|
branch-max-lines: 2
|
||||||
|
case-max-lines: 2
|
||||||
|
default: all
|
||||||
|
disable:
|
||||||
|
- if
|
||||||
|
- err
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
presets:
|
||||||
|
- comments
|
||||||
|
- common-false-positives
|
||||||
|
- legacy
|
||||||
|
- std-error-handling
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
formatters:
|
||||||
|
enable:
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
|||||||
18
Makefile
18
Makefile
@@ -3,6 +3,7 @@
|
|||||||
BUILDOPTS=-ldflags="-s -w" -a -gcflags=all=-l -trimpath
|
BUILDOPTS=-ldflags="-s -w" -a -gcflags=all=-l -trimpath
|
||||||
MYNAME=buny-jabber-bot
|
MYNAME=buny-jabber-bot
|
||||||
BINARY=$(MYNAME)
|
BINARY=$(MYNAME)
|
||||||
|
TEST1=xml-software-version-query
|
||||||
|
|
||||||
# На windows имя бинарника может зависеть не только от платформы, но и от выбранной цели, для linux-а суффикс .exe
|
# На windows имя бинарника может зависеть не только от платформы, но и от выбранной цели, для linux-а суффикс .exe
|
||||||
# не нужен
|
# не нужен
|
||||||
@@ -67,4 +68,21 @@ endif
|
|||||||
go mod tidy
|
go mod tidy
|
||||||
go mod vendor
|
go mod vendor
|
||||||
|
|
||||||
|
test1:
|
||||||
|
# Ну и дальше просто билдим бинарник средствами гошки
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
# вариант с powershell на windows
|
||||||
|
ifeq ($(SHELL),sh.exe)
|
||||||
|
SET CGO_ENABLED=0
|
||||||
|
go build ${BUILDOPTS} -o ${TEST1} ./cmd/${TEST1}.exe
|
||||||
|
else
|
||||||
|
# вариант с jetbrains golang на windows
|
||||||
|
CGO_ENABLED=0
|
||||||
|
go build ${BUILDOPTS} -o ${TEST1} ./cmd/${TEST1}.exe
|
||||||
|
endif
|
||||||
|
# вариант с bash/git (windows) и bash (linux)
|
||||||
|
else
|
||||||
|
CGO_ENABLED=0 go build ${BUILDOPTS} -o ${TEST1} ./cmd/${TEST1}
|
||||||
|
endif
|
||||||
|
|
||||||
# vim: set ft=make noet ai ts=4 sw=4 sts=4:
|
# vim: set ft=make noet ai ts=4 sw=4 sts=4:
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
* Имеет возможность заносить пользователей в бан-лист, согласно заданным в чёрном списке правилам:
|
* Имеет возможность заносить пользователей в бан-лист, согласно заданным в чёрном списке правилам:
|
||||||
- По совпадению с регулярными выражениями в nick-е или jid-е злодея
|
- По совпадению с регулярными выражениями в nick-е или jid-е злодея
|
||||||
- По регулярным выражениям характерных фраз.
|
- По регулярным выражениям характерных фраз.
|
||||||
|
- По названию и/или версии и, если есть, ос злодея.
|
||||||
- Правила можно настроить как глобально, для всех комнат, где присутствует бот, так и для каждой комнаты отдельно.
|
- Правила можно настроить как глобально, для всех комнат, где присутствует бот, так и для каждой комнаты отдельно.
|
||||||
- При изменении списка правил бота не надо перезапускать, достаточно отдать ему команду rehash либо в приват, либо
|
- При изменении списка правил бота не надо перезапускать, достаточно отдать ему команду rehash либо в приват, либо
|
||||||
прям в чатике.
|
прям в чатике.
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
// Package main содержит основную функцию для запуска логики бота.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -11,75 +13,55 @@ import (
|
|||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
||||||
"buny-jabber-bot/internal/jabber"
|
"buny-jabber-bot/internal/jabber"
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
|
|
||||||
"github.com/eleksir/go-xmpp"
|
"github.com/eleksir/go-xmpp"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"gopkg.in/tomb.v2"
|
"gopkg.in/tomb.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed version
|
//go:embed version
|
||||||
var version string
|
var version string //nolint: grouper
|
||||||
|
|
||||||
// main - фактичеcки, начало и основное тело программы.
|
// main - фактичеcки, начало и основное тело программы.
|
||||||
func main() {
|
func main() {
|
||||||
var err error
|
var (
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var j = jabber.Jabber{ //nolint:exhaustruct
|
var (
|
||||||
SigChan: make(chan os.Signal, 1),
|
logfile = os.Stderr
|
||||||
GTomb: tomb.Tomb{},
|
j = jabber.Jabber{ //nolint:exhaustruct
|
||||||
RoomsConnected: make([]string, 1),
|
SigChan: make(chan os.Signal, 1),
|
||||||
}
|
GTomb: tomb.Tomb{},
|
||||||
|
RoomsConnected: make([]string, 1),
|
||||||
log.SetFormatter(&log.TextFormatter{ //nolint:exhaustruct
|
}
|
||||||
DisableQuote: true,
|
)
|
||||||
DisableLevelTruncation: false,
|
|
||||||
DisableColors: true,
|
|
||||||
FullTimestamp: true,
|
|
||||||
TimestampFormat: "2006-01-02 15:04:05",
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := j.ReadConfig(); err != nil {
|
if err := j.ReadConfig(); err != nil {
|
||||||
log.Error(err)
|
log.Errorf("%s", err)
|
||||||
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
j.C.Version = version
|
j.C.Version = version
|
||||||
|
|
||||||
// no panic
|
|
||||||
switch j.C.Loglevel {
|
|
||||||
case "fatal":
|
|
||||||
log.SetLevel(log.FatalLevel)
|
|
||||||
case "error":
|
|
||||||
log.SetLevel(log.ErrorLevel)
|
|
||||||
case "warn":
|
|
||||||
log.SetLevel(log.WarnLevel)
|
|
||||||
case "info":
|
|
||||||
log.SetLevel(log.InfoLevel)
|
|
||||||
case "debug":
|
|
||||||
log.SetLevel(log.DebugLevel)
|
|
||||||
case "trace":
|
|
||||||
log.SetLevel(log.TraceLevel)
|
|
||||||
default:
|
|
||||||
log.SetLevel(log.InfoLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Откроем лог и скормим его логгеру.
|
// Откроем лог и скормим его логгеру.
|
||||||
if j.C.Log != "" {
|
if j.C.Log != "" {
|
||||||
logfile, err := os.OpenFile(j.C.Log, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
logfile, err = os.OpenFile(j.C.Log, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Unable to open log file %s: %s", j.C.Log, err)
|
log.Errorf("Unable to open log file %s: %s", j.C.Log, err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.SetOutput(logfile)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Init(j.C.Loglevel, logfile)
|
||||||
|
|
||||||
j.C.ExeName, err = os.Executable()
|
j.C.ExeName, err = os.Executable()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Unable to find my executable: %s", err)
|
log.Fatalf("Unable to find my executable: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle pricky windows case. But honestly i do not expect it runs on windows.
|
// handle pricky windows case. But honestly i do not expect it runs on windows.
|
||||||
@@ -98,25 +80,25 @@ func main() {
|
|||||||
|
|
||||||
verboseClient := false
|
verboseClient := false
|
||||||
|
|
||||||
if myLogLevel == log.TraceLevel {
|
if log.LogLevel == slog.LevelDebug {
|
||||||
verboseClient = true
|
verboseClient = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Самое время вгрузить белые и чёрные списки, если что - получим ошибку в лог.
|
// Самое время вгрузить белые и чёрные списки, если что - получим ошибку в лог.
|
||||||
if err := j.ReadWhitelist(); err != nil {
|
if err := j.ReadWhitelist(); err != nil {
|
||||||
log.Error(err)
|
log.Error(err.Error())
|
||||||
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := j.ReadBlacklist(); err != nil {
|
if err := j.ReadBlacklist(); err != nil {
|
||||||
log.Error(err)
|
log.Error(err.Error())
|
||||||
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// github.com/mattn/go-xmpp пишет в stdio, нам этого не надо, ловим выхлоп его в logrus с уровнем trace.
|
// github.com/mattn/go-xmpp пишет в stdio, нам этого не надо, ловим выхлоп его в logrus с уровнем trace.
|
||||||
xmpp.DebugWriter = log.WithFields(log.Fields{"logger": "stdlib"}).WriterLevel(log.TraceLevel)
|
xmpp.DebugWriter = log.Writer
|
||||||
|
|
||||||
// Хэндлер сигналов.
|
// Хэндлер сигналов.
|
||||||
j.GTomb.Go(func() error { return j.SigHandler() }) //nolint: gocritic
|
j.GTomb.Go(func() error { return j.SigHandler() }) //nolint: gocritic
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
0.1
|
0.2
|
||||||
@@ -22,10 +22,18 @@
|
|||||||
"^Buzzing_Wasp$"
|
"^Buzzing_Wasp$"
|
||||||
],
|
],
|
||||||
|
|
||||||
# Список регулярок, запрещённых к упоминанию в чяте.
|
# Список регулярок, запрещённых к упоминанию в чяте.
|
||||||
"phrase_re": [
|
"phrase_re": [
|
||||||
"^Exterminate.$"
|
"^Exterminate.$"
|
||||||
]
|
],
|
||||||
|
|
||||||
|
"user_agent": [
|
||||||
|
{
|
||||||
|
"software": "BadUserAgent",
|
||||||
|
"version": "0.666.0",
|
||||||
|
"os": "DeathStarOS"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -5,16 +5,14 @@ go 1.24.3
|
|||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/eleksir/go-xmpp v1.6.0
|
github.com/eleksir/go-xmpp v1.6.0
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
github.com/hjson/hjson-go v3.3.0+incompatible
|
github.com/hjson/hjson-go v3.3.0+incompatible
|
||||||
github.com/jbrukh/bayesian v0.0.0-20231117143245-13ae6f916c7a
|
github.com/jbrukh/bayesian v0.0.0-20231117143245-13ae6f916c7a
|
||||||
github.com/sirupsen/logrus v1.9.3
|
|
||||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6
|
|
||||||
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
|
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
golang.org/x/crypto v0.38.0 // indirect
|
golang.org/x/crypto v0.38.0 // indirect
|
||||||
golang.org/x/net v0.40.0 // indirect
|
golang.org/x/net v0.40.0 // indirect
|
||||||
golang.org/x/sys v0.33.0 // indirect
|
|
||||||
golang.org/x/text v0.25.0 // indirect
|
golang.org/x/text v0.25.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
18
go.sum
18
go.sum
@@ -1,32 +1,18 @@
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/eleksir/go-xmpp v1.6.0 h1:bkGr0YVczJWpkyk/IHhZb2ewv+NeHLvdNfds0TFgqao=
|
github.com/eleksir/go-xmpp v1.6.0 h1:bkGr0YVczJWpkyk/IHhZb2ewv+NeHLvdNfds0TFgqao=
|
||||||
github.com/eleksir/go-xmpp v1.6.0/go.mod h1:Ii6Wemk+yuGQOF+Glt0syjvtcPvdaBLstuNp/+rRJrg=
|
github.com/eleksir/go-xmpp v1.6.0/go.mod h1:Ii6Wemk+yuGQOF+Glt0syjvtcPvdaBLstuNp/+rRJrg=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/hjson/hjson-go v3.3.0+incompatible h1:Rqr+Ya+0aCJMjaE4s8E9YKvuJLuLVpEvz4ONum52vnI=
|
github.com/hjson/hjson-go v3.3.0+incompatible h1:Rqr+Ya+0aCJMjaE4s8E9YKvuJLuLVpEvz4ONum52vnI=
|
||||||
github.com/hjson/hjson-go v3.3.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio=
|
github.com/hjson/hjson-go v3.3.0+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio=
|
||||||
github.com/jbrukh/bayesian v0.0.0-20231117143245-13ae6f916c7a h1:zSc8tkEGo49/E6cQ9o00si0L9Q/Lu1Hsg8JWKCvzEDU=
|
github.com/jbrukh/bayesian v0.0.0-20231117143245-13ae6f916c7a h1:zSc8tkEGo49/E6cQ9o00si0L9Q/Lu1Hsg8JWKCvzEDU=
|
||||||
github.com/jbrukh/bayesian v0.0.0-20231117143245-13ae6f916c7a/go.mod h1:SELxwZQq/mPnfPCR2mchLmT4TQaPJvYtLcCtDWSM7vM=
|
github.com/jbrukh/bayesian v0.0.0-20231117143245-13ae6f916c7a/go.mod h1:SELxwZQq/mPnfPCR2mchLmT4TQaPJvYtLcCtDWSM7vM=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
|
|
||||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
|
||||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
|
||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
|
||||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=
|
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs=
|
||||||
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
|
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
|
|||||||
@@ -1,22 +1,28 @@
|
|||||||
|
// Package jabber contains all buny jabber bot guts.
|
||||||
package jabber
|
package jabber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jbrukh/bayesian"
|
"github.com/jbrukh/bayesian"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
goodDictionaryFile string = "./data/good_dictionary.txt"
|
// goodDictionaryFile путь до файла с заведомо хорошими фразами.
|
||||||
badDictionaryFile string = "./data/bad_dictionary.txt"
|
goodDictionaryFile string = "./data/good_dictionary.txt" //nolint: unused
|
||||||
dataFile string = "./data/data.bin"
|
// badDictionaryFile путь до файла с заведемо плохими фразами.
|
||||||
Bad bayesian.Class = "Bad"
|
badDictionaryFile string = "./data/bad_dictionary.txt" //nolint: unused
|
||||||
Good bayesian.Class = "Good"
|
// dataFile путь до файла с данными тренировки фильтра.
|
||||||
|
dataFile string = "./data/data.bin" //nolint: unused
|
||||||
|
// Bad bayessian class with bad items.
|
||||||
|
Bad bayesian.Class = "Bad"
|
||||||
|
// Good bayessian class with good items.
|
||||||
|
Good bayesian.Class = "Good"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Выдаёт "очки похожести" для данной фразы.
|
// Выдаёт "очки похожести" для данной фразы.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package jabber
|
package jabber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -8,7 +9,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/hjson/hjson-go"
|
"github.com/hjson/hjson-go"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadWhitelist читает и валидирует белые списки пользователей.
|
// ReadWhitelist читает и валидирует белые списки пользователей.
|
||||||
@@ -27,7 +27,7 @@ func (j *Jabber) ReadWhitelist() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
whitelistJSONPath := fmt.Sprintf("%s/data/whitelist.json", filepath.Dir(executablePath))
|
whitelistJSONPath := filepath.Dir(executablePath) + "/data/whitelist.json"
|
||||||
|
|
||||||
locations := []string{
|
locations := []string{
|
||||||
"~/.buny-jabber-bot-whitelist.json",
|
"~/.buny-jabber-bot-whitelist.json",
|
||||||
@@ -39,12 +39,12 @@ func (j *Jabber) ReadWhitelist() error {
|
|||||||
for _, location := range locations {
|
for _, location := range locations {
|
||||||
fileInfo, err := os.Stat(location)
|
fileInfo, err := os.Stat(location)
|
||||||
|
|
||||||
// Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём
|
// Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Файл белого списка длинноват для белого списка, попробуем следующего кандидата
|
// Файл белого списка длинноват для белого списка, попробуем следующего кандидата.
|
||||||
if fileInfo.Size() > 2097152 {
|
if fileInfo.Size() > 2097152 {
|
||||||
log.Warnf("Whitelist file %s is too long for whitelist, skipping", location)
|
log.Warnf("Whitelist file %s is too long for whitelist, skipping", location)
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ func (j *Jabber) ReadWhitelist() error {
|
|||||||
|
|
||||||
buf, err := os.ReadFile(location)
|
buf, err := os.ReadFile(location)
|
||||||
|
|
||||||
// Не удалось прочитать, попробуем следующего кандидата
|
// Не удалось прочитать, попробуем следующего кандидата.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Skip reading whitelist file %s: %s", location, err)
|
log.Warnf("Skip reading whitelist file %s: %s", location, err)
|
||||||
|
|
||||||
@@ -65,12 +65,12 @@ func (j *Jabber) ReadWhitelist() error {
|
|||||||
// сериализуем в json, а потом json превращаем в структурку. Не очень эффективно, но он и нечасто требуется.
|
// сериализуем в json, а потом json превращаем в структурку. Не очень эффективно, но он и нечасто требуется.
|
||||||
var (
|
var (
|
||||||
sampleWhitelist MyWhiteList
|
sampleWhitelist MyWhiteList
|
||||||
tmp map[string]interface{}
|
tmp map[string]any
|
||||||
)
|
)
|
||||||
|
|
||||||
err = hjson.Unmarshal(buf, &tmp)
|
err = hjson.Unmarshal(buf, &tmp)
|
||||||
|
|
||||||
// Не удалось распарсить - попробуем следующего кандидата
|
// Не удалось распарсить - попробуем следующего кандидата.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Skip parsing whitelist file %s: %s", location, err)
|
log.Warnf("Skip parsing whitelist file %s: %s", location, err)
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ func (j *Jabber) ReadWhitelist() error {
|
|||||||
|
|
||||||
tmpJSON, err := json.Marshal(tmp)
|
tmpJSON, err := json.Marshal(tmp)
|
||||||
|
|
||||||
// Не удалось преобразовать map-ку в json
|
// Не удалось преобразовать map-ку в json.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Skip parsing whitelist file %s: %s", location, err)
|
log.Warnf("Skip parsing whitelist file %s: %s", location, err)
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ func (j *Jabber) ReadBlacklist() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
whitelistJSONPath := fmt.Sprintf("%s/data/blacklist.json", filepath.Dir(executablePath))
|
whitelistJSONPath := filepath.Dir(executablePath) + "/data/blacklist.json"
|
||||||
|
|
||||||
locations := []string{
|
locations := []string{
|
||||||
"~/.bunyPresense-jabber-bot-blacklist.json",
|
"~/.bunyPresense-jabber-bot-blacklist.json",
|
||||||
@@ -135,12 +135,12 @@ func (j *Jabber) ReadBlacklist() error {
|
|||||||
for _, location := range locations {
|
for _, location := range locations {
|
||||||
fileInfo, err := os.Stat(location)
|
fileInfo, err := os.Stat(location)
|
||||||
|
|
||||||
// Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём
|
// Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Файл чёрного списка длинноват для чёрного списка, попробуем следующего кандидата
|
// Файл чёрного списка длинноват для чёрного списка, попробуем следующего кандидата.
|
||||||
if fileInfo.Size() > 16777216 {
|
if fileInfo.Size() > 16777216 {
|
||||||
log.Warnf("Blacklist file %s is too long for blacklist, skipping", location)
|
log.Warnf("Blacklist file %s is too long for blacklist, skipping", location)
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ func (j *Jabber) ReadBlacklist() error {
|
|||||||
|
|
||||||
buf, err := os.ReadFile(location)
|
buf, err := os.ReadFile(location)
|
||||||
|
|
||||||
// Не удалось прочитать, попробуем следующего кандидата
|
// Не удалось прочитать, попробуем следующего кандидата.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Skip reading blacklist file %s: %s", location, err)
|
log.Warnf("Skip reading blacklist file %s: %s", location, err)
|
||||||
|
|
||||||
@@ -161,12 +161,12 @@ func (j *Jabber) ReadBlacklist() error {
|
|||||||
// сериализуем в json, а потом json превращаем в структурку. Не очень эффективно, но он и нечасто требуется.
|
// сериализуем в json, а потом json превращаем в структурку. Не очень эффективно, но он и нечасто требуется.
|
||||||
var (
|
var (
|
||||||
sampleBlacklist MyBlackList
|
sampleBlacklist MyBlackList
|
||||||
tmp map[string]interface{}
|
tmp map[string]any
|
||||||
)
|
)
|
||||||
|
|
||||||
err = hjson.Unmarshal(buf, &tmp)
|
err = hjson.Unmarshal(buf, &tmp)
|
||||||
|
|
||||||
// Не удалось распарсить - попробуем следующего кандидата
|
// Не удалось распарсить - попробуем следующего кандидата.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Skip parsing blacklist file %s: %s", location, err)
|
log.Warnf("Skip parsing blacklist file %s: %s", location, err)
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ func (j *Jabber) ReadBlacklist() error {
|
|||||||
|
|
||||||
tmpJSON, err := json.Marshal(tmp)
|
tmpJSON, err := json.Marshal(tmp)
|
||||||
|
|
||||||
// Не удалось преобразовать map-ку в json
|
// Не удалось преобразовать map-ку в json.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Skip parsing blacklist file %s: %s", location, err)
|
log.Warnf("Skip parsing blacklist file %s: %s", location, err)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
package jabber
|
package jabber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/eleksir/go-xmpp"
|
"github.com/eleksir/go-xmpp"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// BunyPresense производит проверку по бело-чёрным спискам. Если presence пришёл от злодея (из чёрного списка), то
|
// BunyPresense производит проверку по бело-чёрным спискам. Если presence пришёл от злодея (из чёрного списка), то
|
||||||
@@ -16,9 +18,9 @@ func (j *Jabber) BunyPresense(v xmpp.Presence) error { //nolint:gocognit,gocyclo
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Если у presence-а есть JID и presence из одной из комнат, в которой мы есть и если его домен в чёрном
|
// Если у presence-а есть JID и presence из одной из комнат, в которой мы есть и если его домен в чёрном
|
||||||
// списке, заносим пидора в список outcast-ов
|
// списке, заносим пидора в список outcast-ов.
|
||||||
if v.JID != "" {
|
if v.JID != "" {
|
||||||
// На всякий случай: себя никогда не баним, явным образом
|
// На всякий случай: себя никогда не баним, явным образом.
|
||||||
if v.JID == j.Talk.JID() {
|
if v.JID == j.Talk.JID() {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -33,41 +35,52 @@ func (j *Jabber) BunyPresense(v xmpp.Presence) error { //nolint:gocognit,gocyclo
|
|||||||
|
|
||||||
goodJid := strings.SplitN(v.JID, "/", 2)[0]
|
goodJid := strings.SplitN(v.JID, "/", 2)[0]
|
||||||
|
|
||||||
// Обрабатываем правила белого списка
|
// Обрабатываем правила белого списка.
|
||||||
for _, good := range j.WhiteList.Whitelist {
|
for _, good := range j.WhiteList.Whitelist {
|
||||||
// Глобальный белый список
|
// Глобальный белый список.
|
||||||
if good.RoomName == "" {
|
if good.RoomName == "" {
|
||||||
for _, person := range good.Jid {
|
if slices.Contains(good.Jid, goodJid) {
|
||||||
if person == goodJid {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Белый список для конкретных каналов
|
// Белый список для конкретных каналов.
|
||||||
if good.RoomName == room {
|
if good.RoomName == room {
|
||||||
for _, person := range good.Jid {
|
if slices.Contains(good.Jid, goodJid) {
|
||||||
if person == goodJid {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id, err := j.QuerySoftwareVersion(v.From)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"unable to query user software and version: jid=%s id=%s, err=%w",
|
||||||
|
v.JID,
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
evilJid := strings.SplitN(v.JID, "/", 2)[0]
|
evilJid := strings.SplitN(v.JID, "/", 2)[0]
|
||||||
evilNick := ""
|
evilNick := ""
|
||||||
evilNicks := strings.SplitN(v.From, "/", 2)
|
evilNicks := strings.SplitN(v.From, "/", 2)
|
||||||
|
|
||||||
// Давайте-ка похэндлим нонсенс - когда у нас в строке нету разделителя
|
// Давайте-ка похэндлим нонсенс - когда у нас в строке нету разделителя.
|
||||||
if len(evilNicks) > 1 {
|
if len(evilNicks) > 1 {
|
||||||
evilNick = evilNicks[1]
|
evilNick = evilNicks[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обрабатываем правила чёрного списка
|
// Обрабатываем правила чёрного списка.
|
||||||
for _, cRoom := range j.RoomsConnected {
|
for _, cRoom := range j.RoomsConnected {
|
||||||
if cRoom == room {
|
if cRoom == room {
|
||||||
for _, bEntry := range j.BlackList.Blacklist {
|
for _, bEntry := range j.BlackList.Blacklist {
|
||||||
// Обработаем правила глобального чёрного списка
|
// Обработаем правила глобального чёрного списка.
|
||||||
if bEntry.RoomName == "" {
|
if bEntry.RoomName == "" {
|
||||||
for _, jidRegexp := range bEntry.JidRe {
|
for _, jidRegexp := range bEntry.JidRe {
|
||||||
if jidRegexp == "" {
|
if jidRegexp == "" {
|
||||||
@@ -131,7 +144,7 @@ func (j *Jabber) BunyPresense(v xmpp.Presence) error { //nolint:gocognit,gocyclo
|
|||||||
nickRegexp,
|
nickRegexp,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Баним именно jid
|
// Баним именно jid.
|
||||||
id, err := j.Squash(room, evilJid, bEntry.ReasonEnable, v.Type)
|
id, err := j.Squash(room, evilJid, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -151,7 +164,7 @@ func (j *Jabber) BunyPresense(v xmpp.Presence) error { //nolint:gocognit,gocyclo
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработаем правила конкретного канала, комнаты конференции
|
// Обработаем правила конкретного канала, комнаты конференции.
|
||||||
if bEntry.RoomName == room {
|
if bEntry.RoomName == room {
|
||||||
for _, jidRegexp := range bEntry.JidRe {
|
for _, jidRegexp := range bEntry.JidRe {
|
||||||
if jidRegexp == "" {
|
if jidRegexp == "" {
|
||||||
@@ -216,7 +229,7 @@ func (j *Jabber) BunyPresense(v xmpp.Presence) error { //nolint:gocognit,gocyclo
|
|||||||
nickRegexp,
|
nickRegexp,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Баним именно jid
|
// Баним именно jid.
|
||||||
id, err := j.Squash(room, evilJid, bEntry.ReasonEnable, v.Type)
|
id, err := j.Squash(room, evilJid, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -249,8 +262,7 @@ func (j *Jabber) BunyPresense(v xmpp.Presence) error { //nolint:gocognit,gocyclo
|
|||||||
func (j *Jabber) BunyChat(v xmpp.Chat) error {
|
func (j *Jabber) BunyChat(v xmpp.Chat) error {
|
||||||
var (
|
var (
|
||||||
room = (strings.SplitN(v.Remote, "/", 2))[0]
|
room = (strings.SplitN(v.Remote, "/", 2))[0]
|
||||||
// nick = (strings.SplitN(v.Remote, "/", 2))[1]
|
err error
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Действовать мы можем только в рамках тех комнат, где явно присуствуем.
|
// Действовать мы можем только в рамках тех комнат, где явно присуствуем.
|
||||||
@@ -258,7 +270,7 @@ func (j *Jabber) BunyChat(v xmpp.Chat) error {
|
|||||||
if cRoom == room {
|
if cRoom == room {
|
||||||
// Перебирём правила чёрных списков.
|
// Перебирём правила чёрных списков.
|
||||||
for _, bEntry := range j.BlackList.Blacklist {
|
for _, bEntry := range j.BlackList.Blacklist {
|
||||||
// Обработаем правила глобального чёрного списка
|
// Обработаем правила глобального чёрного списка.
|
||||||
if bEntry.RoomName == "" {
|
if bEntry.RoomName == "" {
|
||||||
for _, phraseRegexp := range bEntry.PhraseRe {
|
for _, phraseRegexp := range bEntry.PhraseRe {
|
||||||
if phraseRegexp == "" {
|
if phraseRegexp == "" {
|
||||||
@@ -301,7 +313,7 @@ func (j *Jabber) BunyChat(v xmpp.Chat) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Обработаем правила чёрного списка для конкретной комнаты
|
// Обработаем правила чёрного списка для конкретной комнаты.
|
||||||
if bEntry.RoomName == room {
|
if bEntry.RoomName == room {
|
||||||
for _, phraseRegexp := range bEntry.PhraseRe {
|
for _, phraseRegexp := range bEntry.PhraseRe {
|
||||||
if phraseRegexp == "" {
|
if phraseRegexp == "" {
|
||||||
@@ -348,10 +360,10 @@ func (j *Jabber) BunyChat(v xmpp.Chat) error {
|
|||||||
// Если включено, проверяем фразу на КАПС.
|
// Если включено, проверяем фразу на КАПС.
|
||||||
for _, channel := range j.C.Jabber.Channels {
|
for _, channel := range j.C.Jabber.Channels {
|
||||||
if channel.Name == room && channel.AllCaps.Enabled {
|
if channel.Name == room && channel.AllCaps.Enabled {
|
||||||
// Нормализуем строку и вырежем из неё пробелы
|
// Нормализуем строку и вырежем из неё пробелы.
|
||||||
normPhrase := strings.ReplaceAll(nString(v.Text), " ", "")
|
normPhrase := strings.ReplaceAll(nString(v.Text), " ", "")
|
||||||
|
|
||||||
// Проверяем согласно тому, что длина фразы более чем сколько-то символов
|
// Проверяем согласно тому, что длина фразы более чем сколько-то символов.
|
||||||
if len(normPhrase) >= channel.AllCaps.MinLength {
|
if len(normPhrase) >= channel.AllCaps.MinLength {
|
||||||
normPhraseUpper := strings.ReplaceAll(nStringUpper(v.Text), " ", "")
|
normPhraseUpper := strings.ReplaceAll(nStringUpper(v.Text), " ", "")
|
||||||
|
|
||||||
@@ -380,4 +392,209 @@ func (j *Jabber) BunyChat(v xmpp.Chat) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BunySoftwareVersion производит проверку по чёрному списку версий и названий клинтского ПО.
|
||||||
|
func (j *Jabber) BunySoftwareVersion(v xmpp.IQ, ver IqResultSoftwareVersion) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if v.From != "" {
|
||||||
|
// На всякий случай: себя никогда не баним, явным образом.
|
||||||
|
if v.From == j.Talk.JID() {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
room := strings.SplitN(v.From, "/", 2)[0]
|
||||||
|
|
||||||
|
var (
|
||||||
|
presenceJSONStrings []string
|
||||||
|
)
|
||||||
|
|
||||||
|
if presenceJSONInterface, present := j.RoomPresences.Get(room); present {
|
||||||
|
presenceJSONStrings = InterfaceToStringSlice(presenceJSONInterface)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("Looking up %s in presence db", v.From)
|
||||||
|
|
||||||
|
for _, presenceJSONString := range presenceJSONStrings {
|
||||||
|
var p xmpp.Presence
|
||||||
|
|
||||||
|
_ = json.Unmarshal([]byte(presenceJSONString), &p)
|
||||||
|
|
||||||
|
if p.Affiliation == "admin" || p.Affiliation == "owner" {
|
||||||
|
log.Infof("Skipping useragent blacklist check for %s because his affiliation is %s", v.From, p.Affiliation)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// На всякий случай.
|
||||||
|
if p.Role == "moderator" {
|
||||||
|
log.Infof("Skipping useragent blacklist check for %s because his role is %s", v.From, p.Role)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.From == p.From {
|
||||||
|
log.Errorf("Found jid of %s in presence db: %s", v.From, p.JID)
|
||||||
|
|
||||||
|
// Lookup in global blacklist.
|
||||||
|
for _, cRoom := range j.RoomsConnected {
|
||||||
|
if cRoom == room {
|
||||||
|
for _, bEntry := range j.BlackList.Blacklist {
|
||||||
|
// Обработаем правила глобального чёрного списка.
|
||||||
|
if bEntry.RoomName == "" {
|
||||||
|
for _, useragent := range bEntry.UserAgent {
|
||||||
|
switch {
|
||||||
|
case useragent.Name != "" && useragent.Version != "" && useragent.Os != "":
|
||||||
|
if ver.Name == useragent.Name && ver.Version == useragent.Version && ver.Os == useragent.Os {
|
||||||
|
id, err := j.Squash(room, p.JID, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"unable to ban user: id=%s, err=%w",
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case useragent.Name != "" && useragent.Version != "":
|
||||||
|
if ver.Name == useragent.Name && ver.Version == useragent.Version {
|
||||||
|
id, err := j.Squash(room, p.JID, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"unable to ban user: id=%s, err=%w",
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case useragent.Name != "":
|
||||||
|
if ver.Name == useragent.Name {
|
||||||
|
id, err := j.Squash(room, p.JID, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"unable to ban user: id=%s, err=%w",
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case useragent.Version != "":
|
||||||
|
if ver.Version == useragent.Version {
|
||||||
|
id, err := j.Squash(room, p.JID, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"unable to ban user: id=%s, err=%w",
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bEntry.RoomName == room {
|
||||||
|
for _, useragent := range bEntry.UserAgent {
|
||||||
|
switch {
|
||||||
|
case useragent.Name != "" && useragent.Version != "" && useragent.Os != "":
|
||||||
|
if ver.Name == useragent.Name && ver.Version == useragent.Version && ver.Os == useragent.Os {
|
||||||
|
id, err := j.Squash(room, p.JID, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"unable to ban user: id=%s, err=%w",
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case useragent.Name != "" && useragent.Version != "":
|
||||||
|
if ver.Name == useragent.Name && ver.Version == useragent.Version {
|
||||||
|
id, err := j.Squash(room, p.JID, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"unable to ban user: id=%s, err=%w",
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case useragent.Name != "":
|
||||||
|
if ver.Name == useragent.Name {
|
||||||
|
id, err := j.Squash(room, p.JID, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"unable to ban user: id=%s, err=%w",
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case useragent.Version != "":
|
||||||
|
if ver.Version == useragent.Version {
|
||||||
|
id, err := j.Squash(room, p.JID, bEntry.ReasonEnable, v.Type)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf(
|
||||||
|
"unable to ban user: id=%s, err=%w",
|
||||||
|
id,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
||||||
|
|||||||
@@ -4,16 +4,18 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Collection это sync.Map-ка, хранящая в себе произвольные итемы.
|
type (
|
||||||
type Collection struct {
|
// Collection это sync.Map-ка, хранящая в себе произвольные итемы.
|
||||||
items sync.Map
|
Collection struct {
|
||||||
close chan struct{}
|
close chan struct{}
|
||||||
}
|
items sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
// Item представляет собой интерфейс для хранения произвольных данных.
|
// Item представляет собой интерфейс для хранения произвольных данных.
|
||||||
type item struct {
|
item struct {
|
||||||
data interface{}
|
data any
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// NewCollection создаёт инстанс коллекции.
|
// NewCollection создаёт инстанс коллекции.
|
||||||
func NewCollection() *Collection {
|
func NewCollection() *Collection {
|
||||||
@@ -25,7 +27,7 @@ func NewCollection() *Collection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get достаёт данные по заданному ключу из коллекции.
|
// Get достаёт данные по заданному ключу из коллекции.
|
||||||
func (collection *Collection) Get(key interface{}) (interface{}, bool) {
|
func (collection *Collection) Get(key any) (any, bool) {
|
||||||
obj, exists := collection.items.Load(key)
|
obj, exists := collection.items.Load(key)
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -38,15 +40,15 @@ func (collection *Collection) Get(key interface{}) (interface{}, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set сохраняет данные с заданным ключом в коллекцию.
|
// Set сохраняет данные с заданным ключом в коллекцию.
|
||||||
func (collection *Collection) Set(key interface{}, value interface{}) {
|
func (collection *Collection) Set(key any, value any) {
|
||||||
collection.items.Store(key, item{
|
collection.items.Store(key, item{
|
||||||
data: value,
|
data: value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Range применяет функцию f ко всем ключам в коллекции.
|
// Range применяет функцию f ко всем ключам в коллекции.
|
||||||
func (collection *Collection) Range(f func(key, value interface{}) bool) {
|
func (collection *Collection) Range(f func(key, value any) bool) {
|
||||||
fn := func(key, value interface{}) bool {
|
fn := func(key, value any) bool {
|
||||||
item := value.(item)
|
item := value.(item)
|
||||||
|
|
||||||
return f(key, item.data)
|
return f(key, item.data)
|
||||||
@@ -56,13 +58,14 @@ func (collection *Collection) Range(f func(key, value interface{}) bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete удаляет ключ и значение из коллекции данных.
|
// Delete удаляет ключ и значение из коллекции данных.
|
||||||
func (collection *Collection) Delete(key interface{}) {
|
func (collection *Collection) Delete(key any) {
|
||||||
collection.items.Delete(key)
|
collection.items.Delete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close очищает и высвобождает ресурсы, занятые коллекцией.
|
// Close очищает и высвобождает ресурсы, занятые коллекцией.
|
||||||
func (collection *Collection) Close() {
|
func (collection *Collection) Close() {
|
||||||
collection.close <- struct{}{}
|
collection.close <- struct{}{}
|
||||||
|
|
||||||
collection.items = sync.Map{}
|
collection.items = sync.Map{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
package jabber
|
package jabber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/eleksir/go-xmpp"
|
"github.com/eleksir/go-xmpp"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cmd парсит команды из чятика.
|
// Cmd парсит команды из чятика.
|
||||||
func (j *Jabber) Cmd(v xmpp.Chat) error {
|
func (j *Jabber) Cmd(v xmpp.Chat) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
switch {
|
switch v.Text {
|
||||||
case v.Text == fmt.Sprintf("%shelp", j.C.CSign) || v.Text == fmt.Sprintf("%sпомощь", j.C.CSign):
|
case j.C.CSign + "help", j.C.CSign + "помощь":
|
||||||
var (
|
var (
|
||||||
answer string
|
answer string
|
||||||
chosenOneTalks = false
|
chosenOneTalks = false
|
||||||
@@ -30,10 +30,11 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if chosenOneTalks {
|
if chosenOneTalks {
|
||||||
answer = fmt.Sprintf("%sпомощь - этот список команд\n", j.C.CSign)
|
answer = j.C.CSign + "помощь - этот список команд\n"
|
||||||
answer += fmt.Sprintf("%shelp - this commands list\n", j.C.CSign)
|
|
||||||
answer += fmt.Sprintf("%srehash - reload white and black lists (available to bot admins only)\n", j.C.CSign)
|
answer += j.C.CSign + "help - this commands list\n"
|
||||||
answer += fmt.Sprintf("%sver|%sversion - prints version of software", j.C.CSign, j.C.CSign)
|
answer += j.C.CSign + "rehash - reload white and black lists (available to bot admins only)\n"
|
||||||
|
answer += j.C.CSign + "ver | " + j.C.CSign + "version - prints version of software"
|
||||||
} else {
|
} else {
|
||||||
answer = "Ничем помочь не могу. Луна не светит на тебя."
|
answer = "Ничем помочь не могу. Луна не светит на тебя."
|
||||||
}
|
}
|
||||||
@@ -56,15 +57,14 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
case v.Text == fmt.Sprintf("%srehash", j.C.CSign): //nolint:wsl
|
case j.C.CSign + "rehash":
|
||||||
/* Эта команда может прилетать из приватной беседы с realjid-ом, из приватной беседы с chat-nick-ом, а также из
|
/* Эта команда может прилетать из приватной беседы с realjid-ом, из приватной беседы с chat-nick-ом, а также из
|
||||||
* чятика.
|
* чятика.
|
||||||
* Groupchat мы можем определить по v.Type (groupchat) и тогда понятно что делать.
|
* Groupchat мы можем определить по v.Type (groupchat) и тогда понятно что делать.
|
||||||
* А вот, например, приватные притязания определить несколько сложно-вато. Но можно попробовать, например,
|
* А вот, например, приватные притязания определить несколько сложно-вато. Но можно попробовать, например,
|
||||||
* пытаться по списку presence-ов находить персонажа и его real jid и уже из этого определять master он или нет.
|
* пытаться по списку presence-ов находить персонажа и его real jid и уже из этого определять master он или нет.
|
||||||
*/
|
*/
|
||||||
|
// Попробуем определить каков алгоритм наших действий, в зависимости от типа сообщения.
|
||||||
// Попробуем определить каков алгоритм наших действий, в зависимости от типа сообщения
|
|
||||||
switch v.Type {
|
switch v.Type {
|
||||||
case "groupchat":
|
case "groupchat":
|
||||||
// Проверим, является ли "командир" избранным или это самозванец?
|
// Проверим, является ли "командир" избранным или это самозванец?
|
||||||
@@ -90,6 +90,7 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var msg xmpp.Chat
|
var msg xmpp.Chat
|
||||||
|
|
||||||
msg.Remote = v.Remote
|
msg.Remote = v.Remote
|
||||||
msg.Type = v.Type
|
msg.Type = v.Type
|
||||||
msg.Text = "Ничем помочь не могу. Луна не светит на тебя."
|
msg.Text = "Ничем помочь не могу. Луна не светит на тебя."
|
||||||
@@ -103,8 +104,9 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
listsLoaded = false
|
listsLoaded = false
|
||||||
|
|
||||||
var msg xmpp.Chat
|
var msg xmpp.Chat
|
||||||
|
|
||||||
msg.Remote = v.Remote
|
msg.Remote = v.Remote
|
||||||
msg.Type = "chat" // private message
|
msg.Type = "chat" // private message.
|
||||||
msg.Text = fmt.Sprint(err)
|
msg.Text = fmt.Sprint(err)
|
||||||
|
|
||||||
if _, err := j.Talk.Send(msg); err != nil {
|
if _, err := j.Talk.Send(msg); err != nil {
|
||||||
@@ -116,8 +118,9 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
listsLoaded = false
|
listsLoaded = false
|
||||||
|
|
||||||
var msg xmpp.Chat
|
var msg xmpp.Chat
|
||||||
|
|
||||||
msg.Remote = v.Remote
|
msg.Remote = v.Remote
|
||||||
msg.Type = "chat" // private message
|
msg.Type = "chat" // private message.
|
||||||
msg.Text = fmt.Sprint(err)
|
msg.Text = fmt.Sprint(err)
|
||||||
|
|
||||||
if _, err := j.Talk.Send(msg); err != nil {
|
if _, err := j.Talk.Send(msg); err != nil {
|
||||||
@@ -129,6 +132,7 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
room := (strings.SplitN(v.Remote, "/", 2))[0]
|
room := (strings.SplitN(v.Remote, "/", 2))[0]
|
||||||
|
|
||||||
var msg xmpp.Chat
|
var msg xmpp.Chat
|
||||||
|
|
||||||
msg.Remote = room
|
msg.Remote = room
|
||||||
msg.Type = v.Type
|
msg.Type = v.Type
|
||||||
msg.Text = "Сделано"
|
msg.Text = "Сделано"
|
||||||
@@ -137,17 +141,18 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case "chat":
|
case "chat":
|
||||||
room := (strings.SplitN(v.Remote, "/", 2))[0]
|
room := (strings.SplitN(v.Remote, "/", 2))[0]
|
||||||
|
|
||||||
// Реагировать на приватную команду "из комнаты", только если бот в комнате
|
// Реагировать на приватную команду "из комнаты", только если бот в комнате.
|
||||||
if slices.Contains(j.RoomsConnected, room) {
|
if slices.Contains(j.RoomsConnected, room) {
|
||||||
var (
|
var (
|
||||||
chosenOneTalks = false
|
chosenOneTalks = false
|
||||||
listsLoaded = true
|
listsLoaded = true
|
||||||
)
|
)
|
||||||
|
|
||||||
// Реагировать на rehash только если собеседник является bot master-ом
|
// Реагировать на rehash только если собеседник является bot master-ом.
|
||||||
realJID := j.GetRealJIDfromNick(v.Remote)
|
realJID := j.GetRealJIDfromNick(v.Remote)
|
||||||
|
|
||||||
for _, master := range j.C.Jabber.BotMasters {
|
for _, master := range j.C.Jabber.BotMasters {
|
||||||
@@ -165,6 +170,7 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var msg xmpp.Chat
|
var msg xmpp.Chat
|
||||||
|
|
||||||
msg.Remote = v.Remote
|
msg.Remote = v.Remote
|
||||||
msg.Type = v.Type
|
msg.Type = v.Type
|
||||||
msg.Text = "Ничем помочь не могу. Луна не светит на тебя."
|
msg.Text = "Ничем помочь не могу. Луна не светит на тебя."
|
||||||
@@ -178,6 +184,7 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
listsLoaded = false
|
listsLoaded = false
|
||||||
|
|
||||||
var msg xmpp.Chat
|
var msg xmpp.Chat
|
||||||
|
|
||||||
msg.Remote = v.Remote
|
msg.Remote = v.Remote
|
||||||
msg.Type = v.Type
|
msg.Type = v.Type
|
||||||
msg.Text = fmt.Sprint(err)
|
msg.Text = fmt.Sprint(err)
|
||||||
@@ -191,6 +198,7 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
listsLoaded = false
|
listsLoaded = false
|
||||||
|
|
||||||
var msg xmpp.Chat
|
var msg xmpp.Chat
|
||||||
|
|
||||||
msg.Remote = v.Remote
|
msg.Remote = v.Remote
|
||||||
msg.Type = v.Type
|
msg.Type = v.Type
|
||||||
msg.Text = fmt.Sprint(err)
|
msg.Text = fmt.Sprint(err)
|
||||||
@@ -202,6 +210,7 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
|
|
||||||
if listsLoaded {
|
if listsLoaded {
|
||||||
var msg xmpp.Chat
|
var msg xmpp.Chat
|
||||||
|
|
||||||
msg.Remote = v.Remote
|
msg.Remote = v.Remote
|
||||||
msg.Type = v.Type
|
msg.Type = v.Type
|
||||||
msg.Text = "Сделано"
|
msg.Text = "Сделано"
|
||||||
@@ -214,12 +223,14 @@ func (j *Jabber) Cmd(v xmpp.Chat) error {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
log.Infof("Rehash command from outer space: %s", spew.Sdump(v))
|
log.Infof("Rehash command from outer space: %s", spew.Sdump(v))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
case v.Text == fmt.Sprintf("%sver", j.C.CSign) || v.Text == fmt.Sprintf("%sversion", j.C.CSign):
|
|
||||||
|
case j.C.CSign + "ver", j.C.CSign + "version":
|
||||||
var (
|
var (
|
||||||
answer = fmt.Sprintf("Version %s", j.C.Version)
|
answer = "Version " + j.C.Version
|
||||||
)
|
)
|
||||||
|
|
||||||
dest := v.Remote
|
dest := v.Remote
|
||||||
|
|||||||
@@ -1,37 +1,36 @@
|
|||||||
package jabber
|
package jabber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/eleksir/go-xmpp"
|
"github.com/eleksir/go-xmpp"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ParseEvent парсит ивенты, прилетающие из модуля xmpp (изменения presence, фразы участников, ошибки).
|
// ParseEvent парсит ивенты, прилетающие из модуля xmpp (изменения presence, фразы участников, ошибки).
|
||||||
func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
func (j *Jabber) ParseEvent(e any) { //nolint:maintidx,gocognit,gocyclo
|
||||||
j.LastServerActivity = time.Now().Unix()
|
j.LastServerActivity = time.Now().Unix()
|
||||||
|
|
||||||
switch v := e.(type) {
|
switch v := e.(type) {
|
||||||
// Сообщение в чяти
|
// Сообщение в чяти.
|
||||||
case xmpp.Chat:
|
case xmpp.Chat:
|
||||||
log.Debugf("Looks like message, ChatType: %s, From: %s, Subject: %s Text: %s",
|
log.Debugf("Looks like message, ChatType: %s, From: %s, Subject: %s Text: %s",
|
||||||
v.Type, v.Remote, v.Subject, v.Text)
|
v.Type, v.Remote, v.Subject, v.Text)
|
||||||
|
|
||||||
// Топик чятика присылается в виде сообщения с subject, но без text
|
// Топик чятика присылается в виде сообщения с subject, но без text.
|
||||||
// В то же время сообщения от людей приходят с пустым subject, но с заполненным text
|
// В то же время сообщения от людей приходят с пустым subject, но с заполненным text.
|
||||||
if v.Text != "" {
|
if v.Text != "" {
|
||||||
// Чятики бывают групповые и не групповые, от этого зависит Remote, куда направлять сообщение
|
// Чятики бывают групповые и не групповые, от этого зависит Remote, куда направлять сообщение.
|
||||||
switch v.Type { //nolint:wsl,whitespace
|
switch v.Type { //nolint:wsl,whitespace
|
||||||
|
// Групповой чятик.
|
||||||
// Групповой чятик
|
|
||||||
case "groupchat":
|
case "groupchat":
|
||||||
var (
|
var (
|
||||||
room = strings.SplitN(v.Remote, "/", 2)[0]
|
room = strings.SplitN(v.Remote, "/", 2)[0]
|
||||||
@@ -64,7 +63,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
j.LastMucActivity.Set(muc, j.LastServerActivity)
|
j.LastMucActivity.Set(muc, j.LastServerActivity)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Приватный чятик
|
// Приватный чятик.
|
||||||
case "chat":
|
case "chat":
|
||||||
// Здесь у нас может быть 2 вида From:
|
// Здесь у нас может быть 2 вида From:
|
||||||
// slackware-current@conference.jabber.ru/eleksir - это если сообщение из публичного чятика
|
// slackware-current@conference.jabber.ru/eleksir - это если сообщение из публичного чятика
|
||||||
@@ -80,7 +79,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
j.LastActivity = j.LastServerActivity
|
j.LastActivity = j.LastServerActivity
|
||||||
|
|
||||||
// Внезапно, ошибки. По идее они должны ассоциироваться с отправляемыми сообщениями, но по ходу это
|
// Внезапно, ошибки. По идее они должны ассоциироваться с отправляемыми сообщениями, но по ходу это
|
||||||
// не реализовано, поэтому мы получаем ошибки в форме отдельного чятика
|
// не реализовано, поэтому мы получаем ошибки в форме отдельного чятика.
|
||||||
case "error":
|
case "error":
|
||||||
// Это ошибка со стороны сервера, видимо, в ответ на наши действия и поскольку такие вещи происходят
|
// Это ошибка со стороны сервера, видимо, в ответ на наши действия и поскольку такие вещи происходят
|
||||||
// асинхронно, связать их с конкретными нашими действиями довольно сложно.
|
// асинхронно, связать их с конкретными нашими действиями довольно сложно.
|
||||||
@@ -90,7 +89,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
// IQ-сообщение - пинг, понг, что-то ещё...
|
// IQ-сообщение - пинг, понг, что-то ещё...
|
||||||
case xmpp.IQ:
|
case xmpp.IQ:
|
||||||
// По правилам IQ обязательно должна содержать ID, причём не пустой
|
// По правилам IQ обязательно должна содержать ID, причём не пустой.
|
||||||
if v.ID == "" {
|
if v.ID == "" {
|
||||||
log.Info("Got an IQ stanza with empty id, discarding")
|
log.Info("Got an IQ stanza with empty id, discarding")
|
||||||
|
|
||||||
@@ -114,8 +113,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
if err := xml.Unmarshal(v.Query, &iqStruct); err == nil {
|
if err := xml.Unmarshal(v.Query, &iqStruct); err == nil {
|
||||||
switch iqStruct.Xmlns { //nolint:wsl,whitespace
|
switch iqStruct.Xmlns { //nolint:wsl,whitespace
|
||||||
|
// Запрос номера версии приложения.
|
||||||
// Запрос номера версии приложения
|
|
||||||
case "jabber:iq:version":
|
case "jabber:iq:version":
|
||||||
log.Infof("Got IQ get request for version from %s", v.From)
|
log.Infof("Got IQ get request for version from %s", v.From)
|
||||||
|
|
||||||
@@ -138,7 +136,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
parseError = false
|
parseError = false
|
||||||
|
|
||||||
// Нам прислали попингуй
|
// Нам прислали попингуй.
|
||||||
case "urn:xmpp:ping":
|
case "urn:xmpp:ping":
|
||||||
log.Infof("Got IQ get request for pong from %s", v.From)
|
log.Infof("Got IQ get request for pong from %s", v.From)
|
||||||
|
|
||||||
@@ -175,11 +173,12 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
parseError = false
|
parseError = false
|
||||||
|
|
||||||
// Запрос на список поддерживаемых фич - версия, локальное время, итд
|
// Запрос на список поддерживаемых фич - версия, локальное время, итд.
|
||||||
case xmpp.XMPPNS_DISCO_INFO:
|
case xmpp.XMPPNS_DISCO_INFO:
|
||||||
log.Infof("Got IQ get disco#info request from %s", v.From)
|
log.Infof("Got IQ get disco#info request from %s", v.From)
|
||||||
|
|
||||||
answer := "<query xmlns=\"http://jabber.org/protocol/disco#info\">"
|
answer := "<query xmlns=\"http://jabber.org/protocol/disco#info\">"
|
||||||
|
|
||||||
answer += "<feature var=\"jabber:iq:version\" />"
|
answer += "<feature var=\"jabber:iq:version\" />"
|
||||||
answer += "<feature var=\"urn:xmpp:time\" />"
|
answer += "<feature var=\"urn:xmpp:time\" />"
|
||||||
answer += "<feature var=\"urn:xmpp:ping\" />"
|
answer += "<feature var=\"urn:xmpp:ping\" />"
|
||||||
@@ -209,7 +208,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
parseError = false
|
parseError = false
|
||||||
|
|
||||||
// Спрашивают список команд, чтобы поуправлять этим клиентом (xep-0030)
|
// Спрашивают список команд, чтобы поуправлять этим клиентом (xep-0030).
|
||||||
case xmpp.XMPPNS_DISCO_ITEMS:
|
case xmpp.XMPPNS_DISCO_ITEMS:
|
||||||
log.Infof("Got IQ get disco#items request from %s, answer service unavailable", v.From)
|
log.Infof("Got IQ get disco#items request from %s, answer service unavailable", v.From)
|
||||||
|
|
||||||
@@ -231,7 +230,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
parseError = false
|
parseError = false
|
||||||
|
|
||||||
// Запрашивают что-то, о чём мы не имеем представления
|
// Запрашивают что-то, о чём мы не имеем представления.
|
||||||
default:
|
default:
|
||||||
log.Info("Got an unknown IQ get request, discarding")
|
log.Info("Got an unknown IQ get request, discarding")
|
||||||
log.Info(spew.Sdump(e))
|
log.Info(spew.Sdump(e))
|
||||||
@@ -242,7 +241,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
parseError = true
|
parseError = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Попробуем распарсить входящий запрос как urn:xmpp:time
|
// Попробуем распарсить входящий запрос как urn:xmpp:time.
|
||||||
if parseError {
|
if parseError {
|
||||||
var iqStruct TimeIqGetQuery
|
var iqStruct TimeIqGetQuery
|
||||||
|
|
||||||
@@ -276,7 +275,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Попробуем распарсить входящий запрос как http://jabber.org/protocol/pubsub
|
// Попробуем распарсить входящий запрос как http://jabber.org/protocol/pubsub.
|
||||||
if parseError {
|
if parseError {
|
||||||
var iqStruct PubsubIQGetQuery
|
var iqStruct PubsubIQGetQuery
|
||||||
|
|
||||||
@@ -305,6 +304,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
default:
|
default:
|
||||||
log.Info("Got unknown IQ get pubsub something request, discarding")
|
log.Info("Got unknown IQ get pubsub something request, discarding")
|
||||||
log.Info(spew.Sdump(e))
|
log.Info(spew.Sdump(e))
|
||||||
|
|
||||||
parseError = true //nolint:wsl
|
parseError = true //nolint:wsl
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -312,7 +312,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Попробуем распарсить входящий запрос как urn:xmpp:ping он приходит при MUC Self-Ping (Schrödinger's Chat)
|
// Попробуем распарсить входящий запрос как urn:xmpp:ping он приходит при MUC Self-Ping (Schrödinger's Chat).
|
||||||
// Предполагается, что такие респонсы должны приходить только для пинга без серверной оптимизации.
|
// Предполагается, что такие респонсы должны приходить только для пинга без серверной оптимизации.
|
||||||
// Хотя идейно мы не поддерживаем работу без серверной оптимизации, но на пинг ответим, нам несложно.
|
// Хотя идейно мы не поддерживаем работу без серверной оптимизации, но на пинг ответим, нам несложно.
|
||||||
if parseError {
|
if parseError {
|
||||||
@@ -337,7 +337,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
parseError = false
|
parseError = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Не знаю, как парсить... залоггируем это дело и пойдём дальше
|
// Не знаю, как парсить... залоггируем это дело и пойдём дальше.
|
||||||
if parseError {
|
if parseError {
|
||||||
log.Infof("Does not look like parsable via iqStruct")
|
log.Infof("Does not look like parsable via iqStruct")
|
||||||
log.Info(spew.Sdump(e))
|
log.Info(spew.Sdump(e))
|
||||||
@@ -351,12 +351,13 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// Похоже на pong от сервера (по стандарту в ответе нету query, но go-xmpp нам подсовывает это)
|
// Похоже на pong от сервера (по стандарту в ответе нету query, но go-xmpp нам подсовывает это).
|
||||||
case v.From == j.C.Jabber.Server && v.To == j.Talk.JID() && string(v.Query) == "<XMLElement></XMLElement>":
|
case v.From == j.C.Jabber.Server && v.To == j.Talk.JID() && string(v.Query) == "<XMLElement></XMLElement>":
|
||||||
log.Debugf("Got S2C pong answer from %s to %s", v.From, v.To)
|
log.Debugf("Got S2C pong answer from %s to %s", v.From, v.To)
|
||||||
|
|
||||||
j.ServerPingTimestampRx = time.Now().Unix() //nolint:wsl
|
j.ServerPingTimestampRx = time.Now().Unix() //nolint:wsl
|
||||||
|
|
||||||
// Похоже на понг второй стадии xep-0410 MUC-Ping-а, который у нас не реализован
|
// Похоже на понг второй стадии xep-0410 MUC-Ping-а, который у нас не реализован.
|
||||||
case v.To == j.Talk.JID() && string(v.Query) == "<XMLElement></XMLElement>":
|
case v.To == j.Talk.JID() && string(v.Query) == "<XMLElement></XMLElement>":
|
||||||
mucNameMatch := slices.Contains(j.RoomsConnected, v.From)
|
mucNameMatch := slices.Contains(j.RoomsConnected, v.From)
|
||||||
|
|
||||||
@@ -378,13 +379,13 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
if mucNickMatch {
|
if mucNickMatch {
|
||||||
log.Debugf("Got 2-nd stage MUC pong answer (xep-0410) from %s to %s", v.From, v.To)
|
log.Debugf("Got 2-nd stage MUC pong answer (xep-0410) from %s to %s", v.From, v.To)
|
||||||
} else {
|
} else {
|
||||||
// Поскольку никакой логики у нас на этот счёт не предусмотрено, то просто пропускаем ответ
|
// Поскольку никакой логики у нас на этот счёт не предусмотрено, то просто пропускаем ответ.
|
||||||
log.Infof("Got unknown pong from %s to %s", v.From, v.To)
|
log.Infof("Got unknown pong from %s to %s", v.From, v.To)
|
||||||
log.Debug(spew.Sdump(e))
|
log.Debug(spew.Sdump(e))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Подтверждение бана
|
// Подтверждение бана.
|
||||||
case v.To == j.Talk.JID() && v.ID == "ban1":
|
case v.To == j.Talk.JID() && v.ID == "ban1":
|
||||||
mucNickMatch := false
|
mucNickMatch := false
|
||||||
|
|
||||||
@@ -402,15 +403,15 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Формально, ответ должен парситься как пустой result и совпадать с типом jabberSimpleIqGetQuery
|
// Формально, ответ должен парситься как пустой result и совпадать с типом jabberSimpleIqGetQuery.
|
||||||
// Ответ приходит с 2 xmlns, похоже, он парсится неправильно в go-xmpp.
|
// Ответ приходит с 2 xmlns, похоже, он парсится неправильно в go-xmpp.
|
||||||
// TODO: после исправления go-xmpp, надо исправить это тут
|
// TODO: после исправления go-xmpp, надо исправить это тут.
|
||||||
var iqStruct SimpleIqGetQuery
|
var iqStruct SimpleIqGetQuery
|
||||||
|
|
||||||
if err := xml.Unmarshal(v.Query, &iqStruct); err == nil {
|
if err := xml.Unmarshal(v.Query, &iqStruct); err == nil {
|
||||||
if iqStruct.Xmlns == "http://jabber.org/protocol/muc#admin" && iqStruct.Text == "" {
|
if iqStruct.Xmlns == "http://jabber.org/protocol/muc#admin" && iqStruct.Text == "" {
|
||||||
if mucNickMatch {
|
if mucNickMatch {
|
||||||
// Поскольку никакой логики у нас на этот счёт не предусмотрено, то просто пропускаем ответ
|
// Поскольку никакой логики у нас на этот счёт не предусмотрено, то просто пропускаем ответ.
|
||||||
log.Infof("Got ban successful from %s to %s", v.From, v.To)
|
log.Infof("Got ban successful from %s to %s", v.From, v.To)
|
||||||
} else {
|
} else {
|
||||||
log.Infof("Got ban successful from %s to %s, from room we are not in", v.From, v.To)
|
log.Infof("Got ban successful from %s to %s, from room we are not in", v.From, v.To)
|
||||||
@@ -425,12 +426,47 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
log.Debug(spew.Sdump(e))
|
log.Debug(spew.Sdump(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ответ с результатом адресован нам.
|
||||||
|
case v.To == j.Talk.JID():
|
||||||
|
var softwareVersion IqResultSoftwareVersion
|
||||||
|
if err := xml.Unmarshal(v.Query, &softwareVersion); err == nil {
|
||||||
|
if softwareVersion.Os == "" {
|
||||||
|
log.Infof(
|
||||||
|
"Recieved software version query result for %s: software=%s version=%s",
|
||||||
|
v.From,
|
||||||
|
softwareVersion.Name,
|
||||||
|
softwareVersion.Version,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
log.Infof(
|
||||||
|
"Recieved software version query result for %s: software=%s version=%s os=%s",
|
||||||
|
v.From,
|
||||||
|
softwareVersion.Name,
|
||||||
|
softwareVersion.Version,
|
||||||
|
softwareVersion.Os,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = j.BunySoftwareVersion(v, softwareVersion); err != nil {
|
||||||
|
log.Errorf("Unable to query client software version: %s", err)
|
||||||
|
|
||||||
|
j.GTomb.Kill(err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Got an IQ result. Dunno how deal with it, discarding")
|
||||||
|
log.Debug(spew.Sdump(e))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Info("Got an IQ result. Dunno how deal with it, discarding")
|
log.Info("Got an IQ result. Dunno how deal with it, discarding")
|
||||||
log.Debug(spew.Sdump(e))
|
log.Debug(spew.Sdump(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Этот бот не управляется со стороны сервера, поэтому все попытки порулить игнорируем
|
// Этот бот не управляется со стороны сервера, поэтому все попытки порулить игнорируем.
|
||||||
case xmpp.IQTypeSet:
|
case xmpp.IQTypeSet:
|
||||||
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
|
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
|
||||||
if slices.Contains(j.RoomsConnected, muc) {
|
if slices.Contains(j.RoomsConnected, muc) {
|
||||||
@@ -458,7 +494,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
log.Debug(spew.Sdump(e))
|
log.Debug(spew.Sdump(e))
|
||||||
|
|
||||||
// Нам прилетело сообщение об ошибке
|
// Нам прилетело сообщение об ошибке.
|
||||||
case xmpp.IQTypeError:
|
case xmpp.IQTypeError:
|
||||||
// Если сервер не хочет пинговаться и отвечает ошибкой на пинг, то наверно он не умеет в пинги,
|
// Если сервер не хочет пинговаться и отвечает ошибкой на пинг, то наверно он не умеет в пинги,
|
||||||
// хотя если мы его пингуем, значит он анонсировал такой capability. Вот, засранец!
|
// хотя если мы его пингуем, значит он анонсировал такой capability. Вот, засранец!
|
||||||
@@ -471,6 +507,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
if iqPingStruct.Xmlns == "urn:xmpp:ping" {
|
if iqPingStruct.Xmlns == "urn:xmpp:ping" {
|
||||||
if v.From == j.C.Jabber.Server {
|
if v.From == j.C.Jabber.Server {
|
||||||
msg := "Server announced that it can answer c2s ping, but gives us an error to such query, "
|
msg := "Server announced that it can answer c2s ping, but gives us an error to such query, "
|
||||||
|
|
||||||
msg += "fallback to keepalive whitespace pings"
|
msg += "fallback to keepalive whitespace pings"
|
||||||
log.Error(msg)
|
log.Error(msg)
|
||||||
|
|
||||||
@@ -486,7 +523,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
parseError = false
|
parseError = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Это у нас пинг xep-0410 и мы не в комнате, предполагается, что надо бы заджойниться
|
// Это у нас пинг xep-0410 и мы не в комнате, предполагается, что надо бы заджойниться.
|
||||||
if parseError {
|
if parseError {
|
||||||
var iqErrorCancelNotAcceptable IqErrorCancelNotAcceptable
|
var iqErrorCancelNotAcceptable IqErrorCancelNotAcceptable
|
||||||
|
|
||||||
@@ -537,13 +574,13 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
log.Error("Unhandled IQ Error message")
|
log.Error("Unhandled IQ Error message")
|
||||||
log.Error(spew.Sdump(e))
|
log.Error(spew.Sdump(e))
|
||||||
}
|
}
|
||||||
// Нам прилетело что-то неизвестное из семейства IQ stanza
|
// Нам прилетело что-то неизвестное из семейства IQ stanza.
|
||||||
default:
|
default:
|
||||||
log.Info("Got an unknown IQ request. Dunno how deal with it, discarding")
|
log.Info("Got an unknown IQ request. Dunno how deal with it, discarding")
|
||||||
log.Info(spew.Sdump(e))
|
log.Info(spew.Sdump(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Смена статуса участника
|
// Смена статуса участника.
|
||||||
case xmpp.Presence:
|
case xmpp.Presence:
|
||||||
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
|
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
|
||||||
if slices.Contains(j.RoomsConnected, muc) {
|
if slices.Contains(j.RoomsConnected, muc) {
|
||||||
@@ -558,13 +595,21 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
// клиента забанят из-за спама "вошёл-вышел".
|
// клиента забанят из-за спама "вошёл-вышел".
|
||||||
// Однако, это не значит, что такую ситуацию мы не должны корректным образом обрабатывать.
|
// Однако, это не значит, что такую ситуацию мы не должны корректным образом обрабатывать.
|
||||||
if v.Type == "unavailable" {
|
if v.Type == "unavailable" {
|
||||||
// Считаем, что мы больше не в комнате, поэтому не знаем, кто там есть
|
// Считаем, что мы больше не в комнате, поэтому не знаем, кто там есть.
|
||||||
j.RoomPresences.Delete(v.From)
|
j.RoomPresences.Delete(v.From)
|
||||||
|
|
||||||
log.Error("Presence notification - looks like another instance of client leaves room")
|
log.Error("Presence notification - looks like another instance of client leaves room")
|
||||||
|
|
||||||
if slices.Contains(j.RoomsConnected, v.From) {
|
if slices.Contains(j.RoomsConnected, v.From) {
|
||||||
go j.JoinMuc(v.From)
|
j.GTomb.Go(
|
||||||
|
func() error {
|
||||||
|
if err := j.JoinMuc(v.From); err != nil {
|
||||||
|
return fmt.Errorf("unable to join MUC %s: %w", v.From, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("Presence notification, Type: %s, From: %s, Show: %s, Status: %s",
|
log.Errorf("Presence notification, Type: %s, From: %s, Show: %s, Status: %s",
|
||||||
@@ -586,18 +631,19 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Это наш собственный Presence
|
// Это наш собственный Presence.
|
||||||
if v.Show == "" && v.Status == "" {
|
if v.Show == "" && v.Status == "" {
|
||||||
if nick == j.GetBotNickFromRoomConfig(room) {
|
if nick == j.GetBotNickFromRoomConfig(room) {
|
||||||
j.RoomsConnected = append(j.RoomsConnected, room)
|
j.RoomsConnected = append(j.RoomsConnected, room)
|
||||||
// На всякий случай дедуплицируем список комнат, к которым мы заджойнились.
|
// На всякий случай дедуплицируем список комнат, к которым мы заджойнились.
|
||||||
sort.Strings(j.RoomsConnected)
|
sort.Strings(j.RoomsConnected)
|
||||||
slices.Compact(j.RoomsConnected)
|
|
||||||
|
j.RoomsConnected = slices.Compact(j.RoomsConnected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v.Role {
|
switch v.Role {
|
||||||
// Участник ушёл
|
// Участник ушёл.
|
||||||
case "none":
|
case "none":
|
||||||
if presenceJSONInterface, present := j.RoomPresences.Get(room); present {
|
if presenceJSONInterface, present := j.RoomPresences.Get(room); present {
|
||||||
presenceJSONStrings := InterfaceToStringSlice(presenceJSONInterface)
|
presenceJSONStrings := InterfaceToStringSlice(presenceJSONInterface)
|
||||||
@@ -606,6 +652,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
for _, presenceJSONstring := range presenceJSONStrings {
|
for _, presenceJSONstring := range presenceJSONStrings {
|
||||||
var p xmpp.Presence
|
var p xmpp.Presence
|
||||||
|
|
||||||
_ = json.Unmarshal([]byte(presenceJSONstring), &p)
|
_ = json.Unmarshal([]byte(presenceJSONstring), &p)
|
||||||
|
|
||||||
if p.From == v.From {
|
if p.From == v.From {
|
||||||
@@ -617,7 +664,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
j.RoomPresences.Set(room, newPresenceJSONStrings)
|
j.RoomPresences.Set(room, newPresenceJSONStrings)
|
||||||
}
|
}
|
||||||
// Участник пришёл
|
// Участник пришёл.
|
||||||
default:
|
default:
|
||||||
var (
|
var (
|
||||||
presenceJSONStrings []string
|
presenceJSONStrings []string
|
||||||
@@ -631,9 +678,10 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
for _, presenceJSONString := range presenceJSONStrings {
|
for _, presenceJSONString := range presenceJSONStrings {
|
||||||
var p xmpp.Presence
|
var p xmpp.Presence
|
||||||
|
|
||||||
_ = json.Unmarshal([]byte(presenceJSONString), &p)
|
_ = json.Unmarshal([]byte(presenceJSONString), &p)
|
||||||
|
|
||||||
// Если находим, что у нас уже есть клиент с таким же From, то есть полным nick-ом (для grouchat)
|
// Если находим, что у нас уже есть клиент с таким же From, то есть полным nick-ом (для groupchat)
|
||||||
// просто замещаем его.
|
// просто замещаем его.
|
||||||
if p.From == v.From {
|
if p.From == v.From {
|
||||||
continue
|
continue
|
||||||
@@ -661,7 +709,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ответ на запрос поддерживаемых фич, который "http://jabber.org/protocol/disco#info"
|
// Ответ на запрос поддерживаемых фич, который "http://jabber.org/protocol/disco#info".
|
||||||
case xmpp.DiscoResult:
|
case xmpp.DiscoResult:
|
||||||
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
|
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
|
||||||
if slices.Contains(j.RoomsConnected, muc) {
|
if slices.Contains(j.RoomsConnected, muc) {
|
||||||
@@ -669,12 +717,12 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Я видел 2 типа disco result и они отличались только []identities. Попробуем вытащить известный identity
|
// Я видел 2 типа disco result и они отличались только []identities. Попробуем вытащить известный identity.
|
||||||
// TODO: проверять адресата v.To
|
// TODO: проверять адресата v.To.
|
||||||
for _, ident := range v.Identities {
|
for _, ident := range v.Identities {
|
||||||
switch ident.Category {
|
switch ident.Category {
|
||||||
case "server":
|
case "server":
|
||||||
// Конкретно сейчас нас интересует только поддержка c2s ping
|
// Конкретно сейчас нас интересует только поддержка c2s ping.
|
||||||
for _, feature := range v.Features {
|
for _, feature := range v.Features {
|
||||||
log.Debugf("Server %s announced that it supports feature: %s", v.From, feature)
|
log.Debugf("Server %s announced that it supports feature: %s", v.From, feature)
|
||||||
j.ServerCapsList.Set(feature, true)
|
j.ServerCapsList.Set(feature, true)
|
||||||
@@ -687,6 +735,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
|
|
||||||
for _, feature := range v.Features {
|
for _, feature := range v.Features {
|
||||||
log.Debugf("MUC %s announced that it supports feature: %s", v.From, feature)
|
log.Debugf("MUC %s announced that it supports feature: %s", v.From, feature)
|
||||||
|
|
||||||
mucCaps[feature] = true //nolint:wsl
|
mucCaps[feature] = true //nolint:wsl
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,7 +750,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Это что-то неизвестное, подампим событие в лог
|
// Это что-то неизвестное, подампим событие в лог.
|
||||||
default:
|
default:
|
||||||
log.Info(spew.Sdump(e))
|
log.Info(spew.Sdump(e))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
package jabber
|
package jabber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MyLoop - основной цикл программы.
|
// MyLoop - основной цикл программы.
|
||||||
func (j *Jabber) MyLoop() error {
|
func (j *Jabber) MyLoop() error {
|
||||||
for {
|
for {
|
||||||
// Зададим начальное значение глобальным переменным
|
// Зададим начальное значение глобальным переменным.
|
||||||
j.ServerPingTimestampRx = 0
|
j.ServerPingTimestampRx = 0
|
||||||
j.ServerPingTimestampTx = 0
|
j.ServerPingTimestampTx = 0
|
||||||
j.RoomsConnected = make([]string, 1)
|
j.RoomsConnected = make([]string, 1)
|
||||||
@@ -23,9 +22,9 @@ func (j *Jabber) MyLoop() error {
|
|||||||
j.ServerPingTimestampRx = 0
|
j.ServerPingTimestampRx = 0
|
||||||
j.RoomPresences = NewCollection()
|
j.RoomPresences = NewCollection()
|
||||||
|
|
||||||
// Установим коннект
|
// Установим коннект.
|
||||||
if err := j.EstablishConnection(); err != nil {
|
if err := j.EstablishConnection(); err != nil {
|
||||||
log.Error(err)
|
log.Error(err.Error())
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -36,7 +35,7 @@ func (j *Jabber) MyLoop() error {
|
|||||||
j.GTomb.Go(
|
j.GTomb.Go(
|
||||||
func() error {
|
func() error {
|
||||||
err := j.ProbeServerLiveness()
|
err := j.ProbeServerLiveness()
|
||||||
log.Error(err)
|
log.Error(err.Error())
|
||||||
|
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
@@ -48,14 +47,8 @@ func (j *Jabber) MyLoop() error {
|
|||||||
// j.GTomb.Go() тут зовётся внутри на каждую комнату, если у нас ошибка, эта горутинка рано или поздно выйдет.
|
// j.GTomb.Go() тут зовётся внутри на каждую комнату, если у нас ошибка, эта горутинка рано или поздно выйдет.
|
||||||
go j.ProbeMUCLiveness()
|
go j.ProbeMUCLiveness()
|
||||||
|
|
||||||
// Гребём ивенты...
|
// Гребём ивенты, пока стриггерилось завершение работы приложения, или соединение не порвалось.
|
||||||
for {
|
for !j.Shutdown {
|
||||||
// Стриггерилось завершение работы приложения, или соединение не установлено (порвалось, например)
|
|
||||||
// грести не надо
|
|
||||||
if j.Shutdown {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if !j.IsConnected {
|
if !j.IsConnected {
|
||||||
// Tight loop - это наверно не очень хорошо, думаю, ничего страшного не будет, если мы поспим 100мс.
|
// Tight loop - это наверно не очень хорошо, думаю, ничего страшного не будет, если мы поспим 100мс.
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
@@ -63,7 +56,7 @@ func (j *Jabber) MyLoop() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Вынимаем ивент из "провода"
|
// Вынимаем ивент из "провода".
|
||||||
chat, err := j.Talk.Recv()
|
chat, err := j.Talk.Recv()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
36
internal/jabber/query_version.go
Normal file
36
internal/jabber/query_version.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package jabber
|
||||||
|
|
||||||
|
import (
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/eleksir/go-xmpp"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// QuerySoftwareVersion запрошивает версию и название клиента.
|
||||||
|
func (j *Jabber) QuerySoftwareVersion(jid string) (string, error) {
|
||||||
|
var (
|
||||||
|
id string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if id, err = j.Talk.RawInformationQuery(
|
||||||
|
j.Talk.JID(),
|
||||||
|
jid,
|
||||||
|
uuid.New().String(),
|
||||||
|
xmpp.IQTypeGet,
|
||||||
|
"jabber:iq:version",
|
||||||
|
"",
|
||||||
|
); err != nil {
|
||||||
|
err = fmt.Errorf(
|
||||||
|
"unable to query software version of jid=%s err=%w",
|
||||||
|
jid,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
log.Infof("Query software version of %s", jid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return id, err
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package jabber
|
package jabber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -8,7 +9,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/hjson/hjson-go"
|
"github.com/hjson/hjson-go"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге
|
// ReadConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге
|
||||||
@@ -28,7 +28,7 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
configJSONPath := fmt.Sprintf("%s/data/config.json", filepath.Dir(executablePath))
|
configJSONPath := filepath.Dir(executablePath) + "/data/config.json"
|
||||||
|
|
||||||
locations := []string{
|
locations := []string{
|
||||||
"~/.buny-jabber-bot.json",
|
"~/.buny-jabber-bot.json",
|
||||||
@@ -66,7 +66,7 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
// сериализуем в json, а потом json превращаем в структурку. Не очень эффективно, но он и нечасто требуется.
|
// сериализуем в json, а потом json превращаем в структурку. Не очень эффективно, но он и нечасто требуется.
|
||||||
var (
|
var (
|
||||||
sampleConfig MyConfig
|
sampleConfig MyConfig
|
||||||
tmp map[string]interface{}
|
tmp map[string]any
|
||||||
)
|
)
|
||||||
|
|
||||||
err = hjson.Unmarshal(buf, &tmp)
|
err = hjson.Unmarshal(buf, &tmp)
|
||||||
@@ -80,7 +80,7 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
|
|
||||||
tmpJSON, err := json.Marshal(tmp)
|
tmpJSON, err := json.Marshal(tmp)
|
||||||
|
|
||||||
// Не удалось преобразовать map-ку в json
|
// Не удалось преобразовать map-ку в json.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Skip parsing config file %s: %s", location, err)
|
log.Warnf("Skip parsing config file %s: %s", location, err)
|
||||||
|
|
||||||
@@ -93,9 +93,10 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Значения для Jabber-клиента
|
// Значения для Jabber-клиента.
|
||||||
if sampleConfig.Jabber.Server == "" {
|
if sampleConfig.Jabber.Server == "" {
|
||||||
log.Error("Jabber server is not defined in config, using localhost")
|
log.Error("Jabber server is not defined in config, using localhost")
|
||||||
|
|
||||||
sampleConfig.Jabber.Server = "localhost" //nolint:wsl
|
sampleConfig.Jabber.Server = "localhost" //nolint:wsl
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
sampleConfig.Jabber.SslVerify = false
|
sampleConfig.Jabber.SslVerify = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// sampleConfig.Jabber.InsecureAllowUnencryptedAuth = false, если не задан
|
// sampleConfig.Jabber.InsecureAllowUnencryptedAuth = false, если не задан.
|
||||||
|
|
||||||
if sampleConfig.Jabber.ConnectionTimeout == 0 {
|
if sampleConfig.Jabber.ConnectionTimeout == 0 {
|
||||||
sampleConfig.Jabber.ConnectionTimeout = 10
|
sampleConfig.Jabber.ConnectionTimeout = 10
|
||||||
@@ -175,14 +176,14 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
log.Infof("Jabber user not defined in config, guessing, it can be %s", sampleConfig.Jabber.User)
|
log.Infof("Jabber user not defined in config, guessing, it can be %s", sampleConfig.Jabber.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если sampleConfig.Jabber.Password не задан, то авторизации не будет
|
// Если sampleConfig.Jabber.Password не задан, то авторизации не будет.
|
||||||
|
|
||||||
// Если не задано ни одного мастера, то бот сам себе мастер
|
// Если не задано ни одного мастера, то бот сам себе мастер.
|
||||||
if len(sampleConfig.Jabber.BotMasters) == 0 {
|
if len(sampleConfig.Jabber.BotMasters) == 0 {
|
||||||
sampleConfig.Jabber.BotMasters[0] = sampleConfig.Jabber.User
|
sampleConfig.Jabber.BotMasters[0] = sampleConfig.Jabber.User
|
||||||
}
|
}
|
||||||
|
|
||||||
// Нам бот нужен в каких-то чат-румах, а не "просто так"
|
// Нам бот нужен в каких-то чат-румах, а не "просто так".
|
||||||
if len(sampleConfig.Jabber.Channels) < 1 {
|
if len(sampleConfig.Jabber.Channels) < 1 {
|
||||||
return errors.New("no jabber channels/rooms defined in config, quitting") //nolint:goerr113
|
return errors.New("no jabber channels/rooms defined in config, quitting") //nolint:goerr113
|
||||||
}
|
}
|
||||||
@@ -196,8 +197,8 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
sampleConfig.Jabber.Channels[n].Nick = sampleConfig.Jabber.Nick
|
sampleConfig.Jabber.Channels[n].Nick = sampleConfig.Jabber.Nick
|
||||||
}
|
}
|
||||||
|
|
||||||
// channel.Password может быть пустым, тогда пароля нет
|
// channel.Password может быть пустым, тогда пароля нет.
|
||||||
// channel.Bayes.Enabled будет false, если не проставлен
|
// channel.Bayes.Enabled будет false, если не проставлен.
|
||||||
|
|
||||||
if channel.Bayes.MinLength < 40 {
|
if channel.Bayes.MinLength < 40 {
|
||||||
channel.Bayes.MinLength = 40
|
channel.Bayes.MinLength = 40
|
||||||
@@ -215,7 +216,7 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
channel.Bayes.DefaultAction = "log"
|
channel.Bayes.DefaultAction = "log"
|
||||||
}
|
}
|
||||||
|
|
||||||
// channel.AllCaps.Enabled будет false, если не указан
|
// channel.AllCaps.Enabled будет false, если не указан.
|
||||||
if channel.AllCaps.MinLength < 10 {
|
if channel.AllCaps.MinLength < 10 {
|
||||||
channel.AllCaps.MinLength = 10
|
channel.AllCaps.MinLength = 10
|
||||||
}
|
}
|
||||||
@@ -229,23 +230,23 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если список фраз с которыми стартует бот пустой, вносим в него 1 запись с пустой строкой
|
// Если список фраз с которыми стартует бот пустой, вносим в него 1 запись с пустой строкой.
|
||||||
if len(sampleConfig.Jabber.StartupStatus) == 0 {
|
if len(sampleConfig.Jabber.StartupStatus) == 0 {
|
||||||
sampleConfig.Jabber.StartupStatus[0] = ""
|
sampleConfig.Jabber.StartupStatus[0] = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если список статусов, с которыми работает бот пустой, вносим в него 1 запись с пустой строкой
|
// Если список статусов, с которыми работает бот пустой, вносим в него 1 запись с пустой строкой.
|
||||||
if len(sampleConfig.Jabber.RuntimeStatus.Text) == 0 {
|
if len(sampleConfig.Jabber.RuntimeStatus.Text) == 0 {
|
||||||
sampleConfig.Jabber.RuntimeStatus.Text[0] = ""
|
sampleConfig.Jabber.RuntimeStatus.Text[0] = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если sampleConfig.Jabber.RuntimeStatus.RotationTime не задан, то он равен 0
|
// Если sampleConfig.Jabber.RuntimeStatus.RotationTime не задан, то он равен 0.
|
||||||
// Если sampleConfig.Jabber.RuntimeStatus.RotationSplayTime не задан, то он равен 0
|
// Если sampleConfig.Jabber.RuntimeStatus.RotationSplayTime не задан, то он равен 0.
|
||||||
|
|
||||||
// Если sampleConfig.Jabber.BanDelay не задан, то он равен 0
|
// Если sampleConfig.Jabber.BanDelay не задан, то он равен 0.
|
||||||
// Если sampleConfig.Jabber.BanPhrasesEnable не задан, то он false
|
// Если sampleConfig.Jabber.BanPhrasesEnable не задан, то он false.
|
||||||
|
|
||||||
// Если список фраз, с которыми банят пустой, то вносим в него одну позицию с пустой строкой
|
// Если список фраз, с которыми банят пустой, то вносим в него одну позицию с пустой строкой.
|
||||||
if len(sampleConfig.Jabber.BanPhrases) == 0 {
|
if len(sampleConfig.Jabber.BanPhrases) == 0 {
|
||||||
sampleConfig.Jabber.BanPhrases[0] = ""
|
sampleConfig.Jabber.BanPhrases[0] = ""
|
||||||
}
|
}
|
||||||
@@ -260,7 +261,7 @@ func (j *Jabber) ReadConfig() error { //nolint:gocognit,gocyclo
|
|||||||
log.Info("loglevel not defined in config, using info")
|
log.Info("loglevel not defined in config, using info")
|
||||||
}
|
}
|
||||||
|
|
||||||
// sampleConfig.Log = "" if not set
|
// sampleConfig.Log = "" if not set.
|
||||||
|
|
||||||
j.C = sampleConfig
|
j.C = sampleConfig
|
||||||
configLoaded = true
|
configLoaded = true
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
package jabber
|
package jabber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/eleksir/go-xmpp"
|
"github.com/eleksir/go-xmpp"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SigHandler срабатывает если происходит завершение программы, инициированное либо init-ом, либо пользователем.
|
||||||
|
// Обрабатвает сигналы INT, TERM, QUIT.
|
||||||
func (j *Jabber) SigHandler() error {
|
func (j *Jabber) SigHandler() error {
|
||||||
log.Debug("Installing signal handler")
|
log.Debug("Installing signal handler")
|
||||||
|
|
||||||
for s := range j.SigChan {
|
for s := range j.SigChan {
|
||||||
switch s {
|
switch s {
|
||||||
case syscall.SIGINT:
|
case syscall.SIGINT:
|
||||||
log.Infoln("Got SIGINT, quitting")
|
log.Info("Got SIGINT, quitting")
|
||||||
case syscall.SIGTERM:
|
case syscall.SIGTERM:
|
||||||
log.Infoln("Got SIGTERM, quitting")
|
log.Info("Got SIGTERM, quitting")
|
||||||
case syscall.SIGQUIT:
|
case syscall.SIGQUIT:
|
||||||
log.Infoln("Got SIGQUIT, quitting")
|
log.Info("Got SIGQUIT, quitting")
|
||||||
|
|
||||||
// Заходим на новую итерацию, если у нас "неинтересный" сигнал.
|
// Заходим на новую итерацию, если у нас "неинтересный" сигнал.
|
||||||
default:
|
default:
|
||||||
@@ -46,7 +48,7 @@ func (j *Jabber) SigHandler() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// И закрываем соединение.
|
// И закрываем соединение.
|
||||||
log.Infoln("Closing connection to jabber server")
|
log.Info("Closing connection to jabber server")
|
||||||
|
|
||||||
if err := j.Talk.Close(); err != nil {
|
if err := j.Talk.Close(); err != nil {
|
||||||
log.Infof("Unable to close connection to jabber server: %s", err)
|
log.Infof("Unable to close connection to jabber server: %s", err)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ func (j *Jabber) Squash(room, jid string, reasonEnable bool, vType string) (stri
|
|||||||
|
|
||||||
if reasonEnable {
|
if reasonEnable {
|
||||||
var t = time.Now()
|
var t = time.Now()
|
||||||
|
|
||||||
ban += fmt.Sprintf(
|
ban += fmt.Sprintf(
|
||||||
"<reason>autoban at %04d.%02d.%02d %02d:%02d:%02d</reason>",
|
"<reason>autoban at %04d.%02d.%02d %02d:%02d:%02d</reason>",
|
||||||
t.Year(),
|
t.Year(),
|
||||||
|
|||||||
@@ -8,193 +8,209 @@ import (
|
|||||||
"gopkg.in/tomb.v2"
|
"gopkg.in/tomb.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MyConfig прототип структурки с конфигом.
|
type (
|
||||||
type MyConfig struct {
|
// MyConfig прототип структурки с конфигом.
|
||||||
|
MyConfig struct {
|
||||||
|
CSign string `json:"csign,omitempty"`
|
||||||
|
Loglevel string `json:"loglevel,omitempty"`
|
||||||
|
Log string `json:"log,omitempty"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
ExeName string `json:"exe_name,omitempty"`
|
||||||
|
Jabber struct {
|
||||||
|
Server string `json:"server,omitempty"`
|
||||||
|
Nick string `json:"nick,omitempty"`
|
||||||
|
Resource string `json:"resource,omitempty"`
|
||||||
|
User string `json:"user,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
StartupStatus []string `json:"startup_status,omitempty"`
|
||||||
|
BotMasters []string `json:"bot_masters,omitempty"`
|
||||||
|
BanPhrases []string `json:"ban_phrases,omitempty"`
|
||||||
|
RuntimeStatus struct {
|
||||||
|
Text []string `json:"text,omitempty"`
|
||||||
|
RotationTime int64 `json:"rotation_time,omitempty"`
|
||||||
|
RotationSplayTime int64 `json:"rotation_splay_time,omitempty"`
|
||||||
|
} `json:"runtime_status"`
|
||||||
|
Channels []struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Nick string `json:"nick,omitempty"`
|
||||||
|
Password string `json:"password,omitempty"`
|
||||||
|
AllCaps struct {
|
||||||
|
DefaultAction string `json:"default_action,omitempty"`
|
||||||
|
MinLength int `json:"min_length,omitempty"`
|
||||||
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
} `json:"all_caps"`
|
||||||
|
Bayes struct {
|
||||||
|
DefaultAction string `json:"default_action,omitempty"`
|
||||||
|
MinWords int64 `json:"min_words,omitempty"`
|
||||||
|
MinLength int `json:"min_length,omitempty"`
|
||||||
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
} `json:"bayes"`
|
||||||
|
} `json:"channels"`
|
||||||
|
ConnectionTimeout int64 `json:"connection_timeout,omitempty"`
|
||||||
|
ReconnectDelay int64 `json:"reconnect_delay,omitempty"`
|
||||||
|
ServerPingDelay int64 `json:"server_ping_delay,omitempty"`
|
||||||
|
MucPingDelay int64 `json:"muc_ping_delay,omitempty"`
|
||||||
|
MucRejoinDelay int64 `json:"muc_rejoin_delay,omitempty"`
|
||||||
|
PingSplayDelay int64 `json:"ping_splay_delay,omitempty"`
|
||||||
|
BanDelay int64 `json:"ban_delay,omitempty"`
|
||||||
|
Port int `json:"port,omitempty"`
|
||||||
|
Ssl bool `json:"ssl,omitempty"`
|
||||||
|
StartTLS bool `json:"starttls,omitempty"`
|
||||||
|
SslVerify bool `json:"ssl_verify,omitempty"`
|
||||||
|
InsecureAllowUnencryptedAuth bool `json:"insecureallowunencryptedauth,omitempty"`
|
||||||
|
BanPhrasesEnable bool `json:"ban_phrases_enable,omitempty"`
|
||||||
|
} `json:"jabber"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MyWhiteList прототип структурки с белым списком jid-ов.
|
||||||
|
MyWhiteList struct {
|
||||||
|
Whitelist []struct {
|
||||||
|
RoomName string `json:"room_name,omitempty"`
|
||||||
|
Jid []string `json:"jid,omitempty"`
|
||||||
|
WipeBans bool `json:"wipe_bans,omitempty"`
|
||||||
|
} `json:"whitelist,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MyBlackList прототип структурки с чёрным списком jid-ов.
|
||||||
|
MyBlackList struct {
|
||||||
|
Blacklist []struct {
|
||||||
|
RoomName string `json:"room_name,omitempty"`
|
||||||
|
JidRe []string `json:"jid_re,omitempty"`
|
||||||
|
NickRe []string `json:"nick_re,omitempty"`
|
||||||
|
PhraseRe []string `json:"phrase_re,omitempty"`
|
||||||
|
UserAgent []struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
Os string `json:"os,omitempty"`
|
||||||
|
} `json:"user_agent"`
|
||||||
|
ReasonEnable bool `json:"reason_enable,omitempty"`
|
||||||
|
} `json:"blacklist"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jabber основная структура-объект, содержащая стейты и проч.
|
||||||
Jabber struct {
|
Jabber struct {
|
||||||
Server string `json:"server,omitempty"`
|
// C - конфиг, как он распарсился из конфиг-файла.
|
||||||
Port int `json:"port,omitempty"`
|
C MyConfig
|
||||||
Ssl bool `json:"ssl,omitempty"`
|
|
||||||
StartTLS bool `json:"starttls,omitempty"`
|
|
||||||
SslVerify bool `json:"ssl_verify,omitempty"`
|
|
||||||
InsecureAllowUnencryptedAuth bool `json:"insecureallowunencryptedauth,omitempty"`
|
|
||||||
ConnectionTimeout int64 `json:"connection_timeout,omitempty"`
|
|
||||||
ReconnectDelay int64 `json:"reconnect_delay,omitempty"`
|
|
||||||
ServerPingDelay int64 `json:"server_ping_delay,omitempty"`
|
|
||||||
MucPingDelay int64 `json:"muc_ping_delay,omitempty"`
|
|
||||||
MucRejoinDelay int64 `json:"muc_rejoin_delay,omitempty"`
|
|
||||||
PingSplayDelay int64 `json:"ping_splay_delay,omitempty"`
|
|
||||||
Nick string `json:"nick,omitempty"`
|
|
||||||
Resource string `json:"resource,omitempty"`
|
|
||||||
User string `json:"user,omitempty"`
|
|
||||||
Password string `json:"password,omitempty"`
|
|
||||||
BotMasters []string `json:"bot_masters,omitempty"`
|
|
||||||
Channels []struct {
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Nick string `json:"nick,omitempty"`
|
|
||||||
Password string `json:"password,omitempty"`
|
|
||||||
Bayes struct {
|
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
|
||||||
MinWords int64 `json:"min_words,omitempty"`
|
|
||||||
MinLength int `json:"min_length,omitempty"`
|
|
||||||
DefaultAction string `json:"default_action,omitempty"`
|
|
||||||
} `json:"bayes,omitempty"`
|
|
||||||
AllCaps struct {
|
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
|
||||||
MinLength int `json:"min_length,omitempty"`
|
|
||||||
DefaultAction string `json:"default_action,omitempty"`
|
|
||||||
} `json:"all_caps,omitempty"`
|
|
||||||
} `json:"channels"`
|
|
||||||
StartupStatus []string `json:"startup_status,omitempty"`
|
|
||||||
RuntimeStatus struct {
|
|
||||||
Text []string `json:"text,omitempty"`
|
|
||||||
RotationTime int64 `json:"rotation_time,omitempty"`
|
|
||||||
RotationSplayTime int64 `json:"rotation_splay_time,omitempty"`
|
|
||||||
} `json:"runtime_status,omitempty"`
|
|
||||||
BanDelay int64 `json:"ban_delay,omitempty"`
|
|
||||||
BanPhrasesEnable bool `json:"ban_phrases_enable,omitempty"`
|
|
||||||
BanPhrases []string `json:"ban_phrases,omitempty"`
|
|
||||||
} `json:"jabber,omitempty"`
|
|
||||||
|
|
||||||
CSign string `json:"csign,omitempty"`
|
// WhiteList - структурка с безусловно разрешёнными jid-ами.
|
||||||
Loglevel string `json:"loglevel,omitempty"`
|
WhiteList MyWhiteList
|
||||||
Log string `json:"log,omitempty"`
|
|
||||||
Version string `json:"version,omitempty"`
|
|
||||||
ExeName string `json:"exe_name,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MyWhiteList прототип структурки с белым списком jid-ов.
|
// BlackList - структурка с запрещёнными по регуляркам фразами, никами, jid-ами.
|
||||||
type MyWhiteList struct {
|
BlackList MyBlackList
|
||||||
Whitelist []struct {
|
|
||||||
RoomName string `json:"room_name,omitempty"`
|
|
||||||
Jid []string `json:"jid,omitempty"`
|
|
||||||
WipeBans bool `json:"wipe_bans,omitempty"`
|
|
||||||
} `json:"whitelist,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MyBlackList прототип структурки с чёрным списком jid-ов.
|
// Опции подключения к xmpp-серверу.
|
||||||
type MyBlackList struct {
|
Options *xmpp.Options
|
||||||
Blacklist []struct {
|
|
||||||
RoomName string `json:"room_name,omitempty"`
|
|
||||||
ReasonEnable bool `json:"reason_enable,omitempty"`
|
|
||||||
JidRe []string `json:"jid_re,omitempty"`
|
|
||||||
NickRe []string `json:"nick_re,omitempty"`
|
|
||||||
PhraseRe []string `json:"phrase_re,omitempty"`
|
|
||||||
} `json:"blacklist,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jabber основная структура-объект, содержащая стейты и проч.
|
// gTomb пул активных горутин.
|
||||||
type Jabber struct {
|
GTomb tomb.Tomb
|
||||||
// C - конфиг, как он распарсился из конфиг-файла.
|
|
||||||
C MyConfig
|
|
||||||
|
|
||||||
// WhiteList - структурка с безусловно разрешёнными jid-ами
|
// Talk основная структурка xmpp-клиента.
|
||||||
WhiteList MyWhiteList
|
Talk *xmpp.Client
|
||||||
|
|
||||||
// BlackList - структурка с запрещёнными по регуляркам фразами, никами, jid-ами.
|
// sync.Map-ка с капабилити сервера.
|
||||||
BlackList MyBlackList
|
ServerCapsList *Collection
|
||||||
|
|
||||||
// Опции подключения к xmpp-серверу.
|
// ServerCapsQueried показывает, были ли запрошены capabilities сервера.
|
||||||
Options *xmpp.Options
|
ServerCapsQueried bool
|
||||||
|
|
||||||
// gTomb пул активных горутин.
|
// Время последней активности, нужно для c2s пингов - посылаем пинги, только если давненько ничего не приходило с
|
||||||
GTomb tomb.Tomb
|
// сервера.
|
||||||
|
LastServerActivity int64
|
||||||
|
|
||||||
// Talk основная структурка xmpp-клиента.
|
// Время, когда был отправлен c2s ping.
|
||||||
Talk *xmpp.Client
|
ServerPingTimestampTx int64
|
||||||
|
|
||||||
// sync.Map-ка с капабилити сервера.
|
// Время, когда был принят s2c pong.
|
||||||
ServerCapsList *Collection
|
ServerPingTimestampRx int64
|
||||||
|
|
||||||
// ServerCapsQueried показывает, были ли запрошены capabilities сервера.
|
// Время последней активности, нужно для jabber:iq:last.
|
||||||
ServerCapsQueried bool
|
LastActivity int64
|
||||||
|
|
||||||
// Время последней активности, нужно для c2s пингов - посылаем пинги, только если давненько ничего не приходило с
|
// sync.Map-ка с комнатами и их capability.
|
||||||
// сервера.
|
MucCapsList *Collection
|
||||||
LastServerActivity int64
|
|
||||||
|
|
||||||
// Время, когда был отправлен c2s ping.
|
// Время последней активности MUC-ов, нужно для пингов - посылаем пинги, только если давненько ничего не приходило из
|
||||||
ServerPingTimestampTx int64
|
// muc-ов.
|
||||||
|
LastMucActivity *Collection
|
||||||
|
|
||||||
// Время, когда был принят s2c pong.
|
// Список комнат, в которых находится бот.
|
||||||
ServerPingTimestampRx int64
|
RoomsConnected []string
|
||||||
|
|
||||||
// Время последней активности, нужно для jabber:iq:last.
|
// sync.Map-ка со списком участников конференций (в json-формате, согласно структуре xmpp.Presence, "room".[]json).
|
||||||
LastActivity int64
|
RoomPresences *Collection
|
||||||
|
|
||||||
// sync.Map-ка с комнатами и их capability.
|
// Канал, по котором приходят сообщения о том, что ОС отправила некие сигналы процессу.
|
||||||
MucCapsList *Collection
|
SigChan chan os.Signal
|
||||||
|
|
||||||
// Время последней активности MUC-ов, нужно для пингов - посылаем пинги, только если давненько ничего не приходило из
|
// Индиктор того, что процесс завершается.
|
||||||
// muc-ов.
|
Shutdown bool
|
||||||
LastMucActivity *Collection
|
|
||||||
|
|
||||||
// Список комнат, в которых находится бот.
|
// Индиктор того, что соединение установлено.
|
||||||
RoomsConnected []string
|
IsConnected bool
|
||||||
|
|
||||||
// sync.Map-ка со списком участников конференций (в json-формате, согласно структуре xmpp.Presence, "room".[]json).
|
// Индикатор того, что соединение в процессе достукивания до сервера.
|
||||||
RoomPresences *Collection
|
Connecting bool
|
||||||
|
}
|
||||||
|
|
||||||
// Канал, по котором приходят сообщения о том, что ОС отправила некие сигналы процессу.
|
// SimpleIqGetQuery прототип структурки для разбора запросов xmpp discovery query, например,
|
||||||
SigChan chan os.Signal
|
// https://xmpp.org/extensions/xep-0030.html#example-18 .
|
||||||
|
SimpleIqGetQuery struct {
|
||||||
|
XMLName xml.Name `xml:"query"`
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
Xmlns string `xml:"xmlns,attr"`
|
||||||
|
Node string `xml:"node,attr,omitempty"` // для xmlns="http://jabber.org/protocol/disco#items"
|
||||||
|
}
|
||||||
|
|
||||||
// Индиктор того, что процесс завершается.
|
// PubsubIQGetQuery прототип структурки для разбора запросов xmpp pubsub.
|
||||||
Shutdown bool
|
PubsubIQGetQuery struct {
|
||||||
|
XMLName xml.Name `xml:"pubsub"`
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
Xmlns string `xml:"xmlns,attr"`
|
||||||
|
Items struct {
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
Node string `xml:"node,attr"`
|
||||||
|
MaxItems string `xml:"max_items,attr"`
|
||||||
|
} `xml:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
// Индиктор того, что соединение установлено.
|
// TimeIqGetQuery прототип структурки для разбора IQ запросов на локальное время клиента,
|
||||||
IsConnected bool
|
// https://xmpp.org/extensions/xep-0202.html
|
||||||
|
TimeIqGetQuery struct {
|
||||||
|
// <time xmlns="urn:xmpp:time"/>.
|
||||||
|
XMLName xml.Name `xml:"time"`
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
Xmlns string `xml:"xmlns,attr"`
|
||||||
|
}
|
||||||
|
|
||||||
// Индикатор того, что соединение в процессе достукивания до сервера.
|
// IqPing прототип структурки для разбора IQ запросов на пинг клиента, https://xmpp.org/extensions/xep-0199.html
|
||||||
Connecting bool
|
IqPing struct {
|
||||||
}
|
XMLName xml.Name `xml:"ping"`
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
Xmlns string `xml:"xmlns,attr"`
|
||||||
|
}
|
||||||
|
|
||||||
// SimpleIqGetQuery прототип структурки для разбора запросов xmpp discovery query, например,
|
// IqErrorCancelNotAcceptable прототип структурки для разбора IQ ответов, когда сервис (сервер, клиент, etc) не
|
||||||
// https://xmpp.org/extensions/xep-0030.html#example-18 .
|
// может или не хочет принимать наш iq-запрос https://xmpp.org/extensions/xep-0099.html
|
||||||
type SimpleIqGetQuery struct {
|
IqErrorCancelNotAcceptable struct {
|
||||||
XMLName xml.Name `xml:"query"`
|
XMLName xml.Name `xml:"error"`
|
||||||
Text string `xml:",chardata"`
|
Text string `xml:",chardata"`
|
||||||
Xmlns string `xml:"xmlns,attr"`
|
Type string `xml:"type,attr"`
|
||||||
Node string `xml:"node,attr,omitempty"` // для xmlns="http://jabber.org/protocol/disco#items"
|
By string `xml:"by,attr"`
|
||||||
}
|
NotAcceptable struct {
|
||||||
|
Text string `xml:",chardata"`
|
||||||
|
Xmlns string `xml:"xmlns,attr"`
|
||||||
|
} `xml:"not-acceptable"`
|
||||||
|
}
|
||||||
|
|
||||||
// PubsubIQGetQuery прототип структурки для разбора запросов xmpp pubsub.
|
// IqResultSoftwareVersion прототип структурки для разбора IQ ответов на запрос о названии и версии клиентского ПО.
|
||||||
type PubsubIQGetQuery struct {
|
IqResultSoftwareVersion struct {
|
||||||
XMLName xml.Name `xml:"pubsub"`
|
XMLName xml.Name `xml:"query"`
|
||||||
Text string `xml:",chardata"`
|
Text string `xml:",chardata"`
|
||||||
Xmlns string `xml:"xmlns,attr"`
|
Xmlns string `xml:"xmlns,attr"`
|
||||||
Items struct {
|
Name string `xml:"name"`
|
||||||
Text string `xml:",chardata"`
|
Version string `xml:"version"`
|
||||||
Node string `xml:"node,attr"`
|
Os string `xml:"os,omitempty"`
|
||||||
MaxItems string `xml:"max_items,attr"`
|
}
|
||||||
} `xml:"items"`
|
)
|
||||||
}
|
|
||||||
|
|
||||||
// TimeIqGetQuery прототип структурки для разбора IQ запросов на локальное время клиента,
|
|
||||||
// https://xmpp.org/extensions/xep-0202.html
|
|
||||||
type TimeIqGetQuery struct {
|
|
||||||
// <time xmlns="urn:xmpp:time"/>
|
|
||||||
XMLName xml.Name `xml:"time"`
|
|
||||||
Text string `xml:",chardata"`
|
|
||||||
Xmlns string `xml:"xmlns,attr"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// IqPing прототип структурки для разбора IQ запросов на пинг клиента, https://xmpp.org/extensions/xep-0199.html
|
|
||||||
type IqPing struct {
|
|
||||||
XMLName xml.Name `xml:"ping"`
|
|
||||||
Text string `xml:",chardata"`
|
|
||||||
Xmlns string `xml:"xmlns,attr"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// IqErrorCancelNotAcceptable прототип структурки для разбора IQ ответов, когда сервис (сервер, клиент, etc) не
|
|
||||||
// может или не хочет принимать наш iq-запрос https://xmpp.org/extensions/xep-0099.html
|
|
||||||
type IqErrorCancelNotAcceptable struct {
|
|
||||||
XMLName xml.Name `xml:"error"`
|
|
||||||
Text string `xml:",chardata"`
|
|
||||||
Type string `xml:"type,attr"`
|
|
||||||
By string `xml:"by,attr"`
|
|
||||||
NotAcceptable struct {
|
|
||||||
Text string `xml:",chardata"`
|
|
||||||
Xmlns string `xml:"xmlns,attr"`
|
|
||||||
} `xml:"not-acceptable"`
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package jabber
|
package jabber
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"buny-jabber-bot/internal/log"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -10,7 +11,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/eleksir/go-xmpp"
|
"github.com/eleksir/go-xmpp"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RandomPhrase выдаёт одну рандомную фразу из даденного списка фраз.
|
// RandomPhrase выдаёт одну рандомную фразу из даденного списка фраз.
|
||||||
@@ -26,16 +26,16 @@ func RandomPhrase(list []string) string {
|
|||||||
|
|
||||||
// InterfaceToStringSlice превращает данный интерфейс в слайс строк.
|
// InterfaceToStringSlice превращает данный интерфейс в слайс строк.
|
||||||
// Если может, конечно :) .
|
// Если может, конечно :) .
|
||||||
func InterfaceToStringSlice(iface interface{}) []string {
|
func InterfaceToStringSlice(iface any) []string {
|
||||||
var mySlice []string
|
var mySlice []string
|
||||||
|
|
||||||
// А теперь мы начинаем дурдом, нам надо превратить ёбанный interface{} в []string
|
// А теперь мы начинаем дурдом, нам надо превратить ёбанный any в []string.
|
||||||
// Поскольку interface{} может быть чем угодно, перестрахуемся
|
// Поскольку any может быть чем угодно, перестрахуемся.
|
||||||
if reflect.TypeOf(iface).Kind() == reflect.Slice {
|
if reflect.TypeOf(iface).Kind() == reflect.Slice {
|
||||||
shit := reflect.ValueOf(iface)
|
shit := reflect.ValueOf(iface)
|
||||||
|
|
||||||
for i := 0; i < shit.Len(); i++ {
|
for v := range shit.Seq() {
|
||||||
mySlice = append(mySlice, fmt.Sprint(shit.Index(i)))
|
mySlice = append(mySlice, v.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,10 +49,10 @@ func (j *Jabber) GetRealJIDfromNick(fullNick string) string {
|
|||||||
|
|
||||||
room := (strings.SplitN(fullNick, "/", 2))[0]
|
room := (strings.SplitN(fullNick, "/", 2))[0]
|
||||||
|
|
||||||
// Достанем presence участника
|
// Достанем presence участника.
|
||||||
presenceJSONInterface, present := j.RoomPresences.Get(room)
|
presenceJSONInterface, present := j.RoomPresences.Get(room)
|
||||||
|
|
||||||
// Никого нет дома
|
// Никого нет дома.
|
||||||
if !present {
|
if !present {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -85,8 +85,9 @@ func (j *Jabber) GetBotNickFromRoomConfig(room string) string {
|
|||||||
// RotateStatus периодически изменяет статус бота в MUC-е согласно настройкам из кофига.
|
// RotateStatus периодически изменяет статус бота в MUC-е согласно настройкам из кофига.
|
||||||
func (j *Jabber) RotateStatus(room string) error {
|
func (j *Jabber) RotateStatus(room string) error {
|
||||||
for {
|
for {
|
||||||
// TODO: Переделать на ticker-ы
|
// TODO: Переделать на ticker-ы.
|
||||||
totalSleepTime := time.Duration(j.C.Jabber.RuntimeStatus.RotationTime) * time.Second
|
totalSleepTime := time.Duration(j.C.Jabber.RuntimeStatus.RotationTime) * time.Second
|
||||||
|
|
||||||
totalSleepTime += time.Duration(j.C.Jabber.RuntimeStatus.RotationSplayTime) * time.Second
|
totalSleepTime += time.Duration(j.C.Jabber.RuntimeStatus.RotationSplayTime) * time.Second
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -129,9 +130,9 @@ func (j *Jabber) JoinMuc(room string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ждём, пока muc нам вернёт список фичей.
|
// Ждём, пока muc нам вернёт список фичей.
|
||||||
for i := 0; i < (20 * int(j.C.Jabber.ConnectionTimeout)); i++ {
|
for range 20 * int(j.C.Jabber.ConnectionTimeout) {
|
||||||
var (
|
var (
|
||||||
myRoom interface{}
|
myRoom any
|
||||||
supported bool
|
supported bool
|
||||||
exist bool
|
exist bool
|
||||||
)
|
)
|
||||||
@@ -154,7 +155,7 @@ func (j *Jabber) JoinMuc(room string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Заходим в конфу, наконец-то
|
// Заходим в конфу, наконец-то.
|
||||||
if _, err := j.Talk.JoinMUCNoHistory(room, j.GetBotNickFromRoomConfig(room)); err != nil {
|
if _, err := j.Talk.JoinMUCNoHistory(room, j.GetBotNickFromRoomConfig(room)); err != nil {
|
||||||
return fmt.Errorf("unable to join to MUC: %s, %w", room, err)
|
return fmt.Errorf("unable to join to MUC: %s, %w", room, err)
|
||||||
}
|
}
|
||||||
@@ -164,7 +165,7 @@ func (j *Jabber) JoinMuc(room string) error {
|
|||||||
// Ждём, когда прилетит presence из комнаты, тогда мы точно знаем, что мы вошли.
|
// Ждём, когда прилетит presence из комнаты, тогда мы точно знаем, что мы вошли.
|
||||||
entered := false
|
entered := false
|
||||||
|
|
||||||
for i := 0; i < (20 * int(j.C.Jabber.ConnectionTimeout)); i++ {
|
for range 20 * int(j.C.Jabber.ConnectionTimeout) {
|
||||||
time.Sleep(50 * time.Millisecond)
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
|
||||||
if slices.Contains(j.RoomsConnected, room) {
|
if slices.Contains(j.RoomsConnected, room) {
|
||||||
@@ -189,7 +190,7 @@ func (j *Jabber) JoinMuc(room string) error {
|
|||||||
|
|
||||||
j.GTomb.Go(func() error { return j.RotateStatus(room) })
|
j.GTomb.Go(func() error { return j.RotateStatus(room) })
|
||||||
|
|
||||||
// Время проверить участников на предмет злобности
|
// Время проверить участников на предмет злобности.
|
||||||
namesInterface, present := j.RoomPresences.Get(room)
|
namesInterface, present := j.RoomPresences.Get(room)
|
||||||
|
|
||||||
// Если room есть в списке presence-ов, то фигачим. room там должен быть, просто обязан.
|
// Если room есть в списке presence-ов, то фигачим. room там должен быть, просто обязан.
|
||||||
@@ -221,6 +222,7 @@ func (j *Jabber) EstablishConnection() error {
|
|||||||
j.RoomsConnected = make([]string, 0)
|
j.RoomsConnected = make([]string, 0)
|
||||||
|
|
||||||
log.Debugf("Establishing connection to %s", j.Options.Host)
|
log.Debugf("Establishing connection to %s", j.Options.Host)
|
||||||
|
|
||||||
j.Talk, err = j.Options.NewClient()
|
j.Talk, err = j.Options.NewClient()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -234,7 +236,7 @@ func (j *Jabber) EstablishConnection() error {
|
|||||||
|
|
||||||
log.Info("Connected")
|
log.Info("Connected")
|
||||||
|
|
||||||
// Джойнимся к чятикам, но делаем это в фоне, чтобы не блочиться на ошибках, например, если бота забанили
|
// Джойнимся к чятикам, но делаем это в фоне, чтобы не блочиться на ошибках, например, если бота забанили.
|
||||||
for _, roomStruct := range j.C.Jabber.Channels {
|
for _, roomStruct := range j.C.Jabber.Channels {
|
||||||
room := roomStruct.Name
|
room := roomStruct.Name
|
||||||
|
|
||||||
@@ -268,6 +270,7 @@ func (j *Jabber) ProbeServerLiveness() error { //nolint:gocognit
|
|||||||
}
|
}
|
||||||
|
|
||||||
sleepTime := time.Duration(j.C.Jabber.ServerPingDelay) * 1000 * time.Millisecond
|
sleepTime := time.Duration(j.C.Jabber.ServerPingDelay) * 1000 * time.Millisecond
|
||||||
|
|
||||||
sleepTime += time.Duration(rand.Int63n(1000*j.C.Jabber.PingSplayDelay)) * time.Millisecond
|
sleepTime += time.Duration(rand.Int63n(1000*j.C.Jabber.PingSplayDelay)) * time.Millisecond
|
||||||
time.Sleep(sleepTime)
|
time.Sleep(sleepTime)
|
||||||
|
|
||||||
@@ -276,26 +279,25 @@ func (j *Jabber) ProbeServerLiveness() error { //nolint:gocognit
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Пингуем, только если не было никакой активности в течение > config.Jabber.ServerPingDelay,
|
// Пингуем, только если не было никакой активности в течение > config.Jabber.ServerPingDelay,
|
||||||
// в худшем случе это будет ~ (config.Jabber.PingSplayDelay * 2) + config.Jabber.PingSplayDelay
|
// в худшем случе это будет ~ (config.Jabber.PingSplayDelay * 2) + config.Jabber.PingSplayDelay.
|
||||||
// if (time.Now().Unix() - lastServerActivity) < (config.Jabber.ServerPingDelay + config.Jabber.PingSplayDelay) {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
if j.ServerCapsQueried { // Сервер ответил на disco#info
|
if j.ServerCapsQueried { // Сервер ответил на disco#info.
|
||||||
var (
|
var (
|
||||||
value interface{}
|
value any
|
||||||
exist bool
|
exist bool
|
||||||
)
|
)
|
||||||
|
|
||||||
value, exist = j.ServerCapsList.Get("urn:xmpp:ping")
|
value, exist = j.ServerCapsList.Get("urn:xmpp:ping")
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// Сервер анонсировал, что умеет в c2s пинги
|
// Сервер анонсировал, что умеет в c2s пинги.
|
||||||
case exist && value.(bool):
|
case exist && value.(bool):
|
||||||
// Таймаут c2s пинга. Возьмём сумму задержки между пингами, добавим таймаут коннекта и добавим
|
// Таймаут c2s пинга. Возьмём сумму задержки между пингами, добавим таймаут коннекта и добавим
|
||||||
// максимальную корректировку разброса.
|
// максимальную корректировку разброса.
|
||||||
txTimeout := j.C.Jabber.ServerPingDelay + j.C.Jabber.ConnectionTimeout
|
txTimeout := j.C.Jabber.ServerPingDelay + j.C.Jabber.ConnectionTimeout
|
||||||
|
|
||||||
txTimeout += j.C.Jabber.PingSplayDelay
|
txTimeout += j.C.Jabber.PingSplayDelay
|
||||||
|
|
||||||
rxTimeout := txTimeout
|
rxTimeout := txTimeout
|
||||||
|
|
||||||
rxTimeAgo := time.Now().Unix() - j.ServerPingTimestampRx
|
rxTimeAgo := time.Now().Unix() - j.ServerPingTimestampRx
|
||||||
@@ -311,7 +313,7 @@ func (j *Jabber) ProbeServerLiveness() error { //nolint:gocognit
|
|||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
||||||
// По-умолчанию, мы отправляем c2s пинг
|
// По-умолчанию, мы отправляем c2s пинг.
|
||||||
default:
|
default:
|
||||||
log.Debugf("Sending c2s ping from %s to %s", j.Talk.JID(), j.C.Jabber.Server)
|
log.Debugf("Sending c2s ping from %s to %s", j.Talk.JID(), j.C.Jabber.Server)
|
||||||
|
|
||||||
@@ -321,7 +323,7 @@ func (j *Jabber) ProbeServerLiveness() error { //nolint:gocognit
|
|||||||
|
|
||||||
j.ServerPingTimestampTx = time.Now().Unix()
|
j.ServerPingTimestampTx = time.Now().Unix()
|
||||||
}
|
}
|
||||||
} else { // Первая пуля пока не вылетела, отправляем
|
} else { // Первая пуля пока не вылетела, отправляем.
|
||||||
log.Debugf("Sending first c2s ping from %s to %s", j.Talk.JID(), j.C.Jabber.Server)
|
log.Debugf("Sending first c2s ping from %s to %s", j.Talk.JID(), j.C.Jabber.Server)
|
||||||
|
|
||||||
if err := j.Talk.PingC2S(j.Talk.JID(), j.C.Jabber.Server); err != nil {
|
if err := j.Talk.PingC2S(j.Talk.JID(), j.C.Jabber.Server); err != nil {
|
||||||
@@ -331,7 +333,7 @@ func (j *Jabber) ProbeServerLiveness() error { //nolint:gocognit
|
|||||||
j.ServerPingTimestampTx = time.Now().Unix()
|
j.ServerPingTimestampTx = time.Now().Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Сервер не анонсировал, что умеет в c2s пинги
|
// Сервер не анонсировал, что умеет в c2s пинги.
|
||||||
default:
|
default:
|
||||||
log.Debug("Sending keepalive whitespace ping")
|
log.Debug("Sending keepalive whitespace ping")
|
||||||
|
|
||||||
@@ -339,7 +341,7 @@ func (j *Jabber) ProbeServerLiveness() error { //nolint:gocognit
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Сервер не ответил на disco#info
|
} else { // Сервер не ответил на disco#info.
|
||||||
log.Debug("Sending keepalive whitespace ping")
|
log.Debug("Sending keepalive whitespace ping")
|
||||||
|
|
||||||
if _, err := j.Talk.SendKeepAlive(); err != nil {
|
if _, err := j.Talk.SendKeepAlive(); err != nil {
|
||||||
@@ -358,7 +360,7 @@ func (j *Jabber) ProbeMUCLiveness() { //nolint:gocognit
|
|||||||
for _, room := range j.RoomsConnected {
|
for _, room := range j.RoomsConnected {
|
||||||
var (
|
var (
|
||||||
exist bool
|
exist bool
|
||||||
lastActivityTS interface{}
|
lastActivityTS any
|
||||||
)
|
)
|
||||||
|
|
||||||
// Если записи про комнату нету, то пинговать её бессмысленно.
|
// Если записи про комнату нету, то пинговать её бессмысленно.
|
||||||
@@ -393,7 +395,7 @@ func (j *Jabber) ProbeMUCLiveness() { //nolint:gocognit
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
*/
|
*/
|
||||||
var roomMap interface{}
|
var roomMap any
|
||||||
|
|
||||||
roomMap, exist = j.MucCapsList.Get(room)
|
roomMap, exist = j.MucCapsList.Get(room)
|
||||||
|
|
||||||
|
|||||||
232
internal/log/log.go
Normal file
232
internal/log/log.go
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
// Package log wraps log/slog for more easier and convinient use.
|
||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Handler exposes slog handler struct.
|
||||||
|
Handler slog.Handler
|
||||||
|
|
||||||
|
// Ctx log context. For now it is just sits here and do nothing.
|
||||||
|
Ctx = context.Background()
|
||||||
|
|
||||||
|
// Writer go-writer eported for capturing other types of logs, even for std log go facility.
|
||||||
|
Writer io.Writer
|
||||||
|
|
||||||
|
// reader is required for Writer to work properly. It is connected via io.Pipe() to Writer.
|
||||||
|
reader io.Reader
|
||||||
|
|
||||||
|
// Logger *log.Logger thing required for compatibility with old-good log package.
|
||||||
|
Logger log.Logger
|
||||||
|
|
||||||
|
// LogFileHandler is currently opened log file descriptor. Stderr by default.
|
||||||
|
LogFileHandler = os.Stderr
|
||||||
|
|
||||||
|
// LogLevel current loglevel. Info by default.
|
||||||
|
LogLevel = slog.LevelInfo
|
||||||
|
)
|
||||||
|
|
||||||
|
// Init setup logger stuff.
|
||||||
|
// level can be error, warn, info, debug if something other supplied info level selected.
|
||||||
|
// fileDescriptor should be opened before supplying it to Init().
|
||||||
|
func Init(level string, fileDescriptor *os.File) {
|
||||||
|
LogFileHandler = fileDescriptor
|
||||||
|
|
||||||
|
// no panic, no trace.
|
||||||
|
switch level {
|
||||||
|
case "debug":
|
||||||
|
LogLevel = slog.LevelDebug
|
||||||
|
|
||||||
|
case "info":
|
||||||
|
LogLevel = slog.LevelInfo
|
||||||
|
|
||||||
|
case "warn":
|
||||||
|
LogLevel = slog.LevelWarn
|
||||||
|
|
||||||
|
case "error":
|
||||||
|
LogLevel = slog.LevelError
|
||||||
|
|
||||||
|
default:
|
||||||
|
LogLevel = slog.LevelInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &slog.HandlerOptions{ //nolint: exhaustruct
|
||||||
|
// Use the ReplaceAttr function on the handler options
|
||||||
|
// to be able to replace any single attribute in the log output.
|
||||||
|
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { //nolint: revive
|
||||||
|
// Check that we are handling the time key.
|
||||||
|
if a.Key != slog.TimeKey {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
t := a.Value.Time()
|
||||||
|
|
||||||
|
// change the value from a time.Time to a String
|
||||||
|
// where the string has the correct time format.
|
||||||
|
a.Value = slog.StringValue(t.Format(time.DateTime))
|
||||||
|
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
|
||||||
|
Level: LogLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Documentation says that we can use *os.File in place of io.Writer, but in this case it did not work.
|
||||||
|
// So we have to cast fileDescriptor to io.Writer.
|
||||||
|
w := io.Writer(fileDescriptor)
|
||||||
|
|
||||||
|
Handler = slog.NewTextHandler(w, opts)
|
||||||
|
|
||||||
|
slog.SetDefault(
|
||||||
|
slog.New(Handler),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Catch log.Logger message at info loglevel of slog logging facility.
|
||||||
|
Logger = *slog.NewLogLogger(Handler, slog.LevelError)
|
||||||
|
|
||||||
|
reader, Writer = io.Pipe()
|
||||||
|
|
||||||
|
go readIoPipe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// readIoPipe reads pipe and writes it to slog.
|
||||||
|
func readIoPipe() {
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
for {
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text() // Get the current line as a string.
|
||||||
|
slog.Debug(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
// io.EOF is expected when done reading, e.g. on exit.
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// something weird happen, we should it log to guess later what it was.
|
||||||
|
Errorf("Error during scanning log writer pipe: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLevel returns current loglevel as string.
|
||||||
|
func GetLevel() string {
|
||||||
|
switch {
|
||||||
|
case Handler.Enabled(Ctx, slog.LevelDebug):
|
||||||
|
return "debug"
|
||||||
|
|
||||||
|
case Handler.Enabled(Ctx, slog.LevelInfo):
|
||||||
|
return "info"
|
||||||
|
|
||||||
|
case Handler.Enabled(Ctx, slog.LevelWarn):
|
||||||
|
return "warn"
|
||||||
|
|
||||||
|
case Handler.Enabled(Ctx, slog.LevelError):
|
||||||
|
return "error"
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal passes message directly to slog.Error() and exits with error code 1.
|
||||||
|
func Fatal(message string) {
|
||||||
|
slog.Error(message)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalf logs message on error log level and exits with error code 1. It allows to supply arguments in printf() style .
|
||||||
|
func Fatalf(format string, a ...any) {
|
||||||
|
slog.Error(fmt.Sprintf(format, a...))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error passes message directly to slog.Error().
|
||||||
|
func Error(message string) {
|
||||||
|
slog.Error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf logs message on error log level and allows to supply arguments in printf() style.
|
||||||
|
func Errorf(format string, a ...any) {
|
||||||
|
slog.Error(fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn passes message directly to slog.Warn().
|
||||||
|
func Warn(message string) {
|
||||||
|
slog.Warn(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf logs message on warn log level and allows to supply arguments in printf() style.
|
||||||
|
func Warnf(format string, a ...any) {
|
||||||
|
slog.Warn(fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info passes message directly to slog.Info().
|
||||||
|
func Info(message string) {
|
||||||
|
slog.Info(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof logs message on info log level and allows to supply arguments in printf() style.
|
||||||
|
func Infof(format string, a ...any) {
|
||||||
|
slog.Info(fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug passes message directly to slog.Debug().
|
||||||
|
func Debug(message string) {
|
||||||
|
slog.Debug(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf logs message on debug log level and allows to supply arguments in printf() style.
|
||||||
|
func Debugf(format string, a ...any) {
|
||||||
|
slog.Debug(fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes opened log file descriptors.
|
||||||
|
func Close() {
|
||||||
|
LogFileHandler.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReOpenLog closes and opens log file again.
|
||||||
|
func ReOpenLog() {
|
||||||
|
filename := LogFileHandler.Name()
|
||||||
|
|
||||||
|
// If we writing to stderr, we should not re-open it.
|
||||||
|
if filename == os.Stderr.Name() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loglevel := GetLevel()
|
||||||
|
|
||||||
|
LogFileHandler.Close()
|
||||||
|
|
||||||
|
file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Try to emulate our own log message format.
|
||||||
|
fmt.Fprintf(
|
||||||
|
os.Stderr,
|
||||||
|
"time=\"%s\" level=ERROR msg=\"Unable to open logfile %s: %s\"",
|
||||||
|
time.Now().Format(time.DateTime),
|
||||||
|
filename,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Init(loglevel, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
||||||
41
vendor/github.com/google/uuid/CHANGELOG.md
generated
vendored
Normal file
41
vendor/github.com/google/uuid/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## [1.6.0](https://github.com/google/uuid/compare/v1.5.0...v1.6.0) (2024-01-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add Max UUID constant ([#149](https://github.com/google/uuid/issues/149)) ([c58770e](https://github.com/google/uuid/commit/c58770eb495f55fe2ced6284f93c5158a62e53e3))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fix typo in version 7 uuid documentation ([#153](https://github.com/google/uuid/issues/153)) ([016b199](https://github.com/google/uuid/commit/016b199544692f745ffc8867b914129ecb47ef06))
|
||||||
|
* Monotonicity in UUIDv7 ([#150](https://github.com/google/uuid/issues/150)) ([a2b2b32](https://github.com/google/uuid/commit/a2b2b32373ff0b1a312b7fdf6d38a977099698a6))
|
||||||
|
|
||||||
|
## [1.5.0](https://github.com/google/uuid/compare/v1.4.0...v1.5.0) (2023-12-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Validate UUID without creating new UUID ([#141](https://github.com/google/uuid/issues/141)) ([9ee7366](https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29))
|
||||||
|
|
||||||
|
## [1.4.0](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) (2023-10-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* UUIDs slice type with Strings() convenience method ([#133](https://github.com/google/uuid/issues/133)) ([cd5fbbd](https://github.com/google/uuid/commit/cd5fbbdd02f3e3467ac18940e07e062be1f864b4))
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
* Clarify that Parse's job is to parse but not necessarily validate strings. (Documents current behavior)
|
||||||
|
|
||||||
|
## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0))
|
||||||
|
|
||||||
|
## Changelog
|
||||||
26
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
Normal file
26
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# How to contribute
|
||||||
|
|
||||||
|
We definitely welcome patches and contribution to this project!
|
||||||
|
|
||||||
|
### Tips
|
||||||
|
|
||||||
|
Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org).
|
||||||
|
|
||||||
|
Always try to include a test case! If it is not possible or not necessary,
|
||||||
|
please explain why in the pull request description.
|
||||||
|
|
||||||
|
### Releasing
|
||||||
|
|
||||||
|
Commits that would precipitate a SemVer change, as described in the Conventional
|
||||||
|
Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action)
|
||||||
|
to create a release candidate pull request. Once submitted, `release-please`
|
||||||
|
will create a release.
|
||||||
|
|
||||||
|
For tips on how to work with `release-please`, see its documentation.
|
||||||
|
|
||||||
|
### Legal requirements
|
||||||
|
|
||||||
|
In order to protect both you and ourselves, you will need to sign the
|
||||||
|
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||||
|
|
||||||
|
You may have already signed it for other Google projects.
|
||||||
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
Normal file
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Paul Borman <borman@google.com>
|
||||||
|
bmatsuo
|
||||||
|
shawnps
|
||||||
|
theory
|
||||||
|
jboverfelt
|
||||||
|
dsymonds
|
||||||
|
cd1
|
||||||
|
wallclockbuilder
|
||||||
|
dansouza
|
||||||
4
vendor/golang.org/x/sys/LICENSE → vendor/github.com/google/uuid/LICENSE
generated
vendored
4
vendor/golang.org/x/sys/LICENSE → vendor/github.com/google/uuid/LICENSE
generated
vendored
@@ -1,4 +1,4 @@
|
|||||||
Copyright 2009 The Go Authors.
|
Copyright (c) 2009,2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are
|
modification, are permitted provided that the following conditions are
|
||||||
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
|||||||
copyright notice, this list of conditions and the following disclaimer
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
in the documentation and/or other materials provided with the
|
in the documentation and/or other materials provided with the
|
||||||
distribution.
|
distribution.
|
||||||
* Neither the name of Google LLC nor the names of its
|
* Neither the name of Google Inc. nor the names of its
|
||||||
contributors may be used to endorse or promote products derived from
|
contributors may be used to endorse or promote products derived from
|
||||||
this software without specific prior written permission.
|
this software without specific prior written permission.
|
||||||
|
|
||||||
21
vendor/github.com/google/uuid/README.md
generated
vendored
Normal file
21
vendor/github.com/google/uuid/README.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# uuid
|
||||||
|
The uuid package generates and inspects UUIDs based on
|
||||||
|
[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122)
|
||||||
|
and DCE 1.1: Authentication and Security Services.
|
||||||
|
|
||||||
|
This package is based on the github.com/pborman/uuid package (previously named
|
||||||
|
code.google.com/p/go-uuid). It differs from these earlier packages in that
|
||||||
|
a UUID is a 16 byte array rather than a byte slice. One loss due to this
|
||||||
|
change is the ability to represent an invalid UUID (vs a NIL UUID).
|
||||||
|
|
||||||
|
###### Install
|
||||||
|
```sh
|
||||||
|
go get github.com/google/uuid
|
||||||
|
```
|
||||||
|
|
||||||
|
###### Documentation
|
||||||
|
[](https://pkg.go.dev/github.com/google/uuid)
|
||||||
|
|
||||||
|
Full `go doc` style documentation for the package can be viewed online without
|
||||||
|
installing this package by using the GoDoc site here:
|
||||||
|
http://pkg.go.dev/github.com/google/uuid
|
||||||
80
vendor/github.com/google/uuid/dce.go
generated
vendored
Normal file
80
vendor/github.com/google/uuid/dce.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Domain represents a Version 2 domain
|
||||||
|
type Domain byte
|
||||||
|
|
||||||
|
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||||
|
const (
|
||||||
|
Person = Domain(0)
|
||||||
|
Group = Domain(1)
|
||||||
|
Org = Domain(2)
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||||
|
//
|
||||||
|
// The domain should be one of Person, Group or Org.
|
||||||
|
// On a POSIX system the id should be the users UID for the Person
|
||||||
|
// domain and the users GID for the Group. The meaning of id for
|
||||||
|
// the domain Org or on non-POSIX systems is site defined.
|
||||||
|
//
|
||||||
|
// For a given domain/id pair the same token may be returned for up to
|
||||||
|
// 7 minutes and 10 seconds.
|
||||||
|
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
|
||||||
|
uuid, err := NewUUID()
|
||||||
|
if err == nil {
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||||
|
uuid[9] = byte(domain)
|
||||||
|
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||||
|
}
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||||
|
// domain with the id returned by os.Getuid.
|
||||||
|
//
|
||||||
|
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||||
|
func NewDCEPerson() (UUID, error) {
|
||||||
|
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||||
|
// domain with the id returned by os.Getgid.
|
||||||
|
//
|
||||||
|
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||||
|
func NewDCEGroup() (UUID, error) {
|
||||||
|
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain returns the domain for a Version 2 UUID. Domains are only defined
|
||||||
|
// for Version 2 UUIDs.
|
||||||
|
func (uuid UUID) Domain() Domain {
|
||||||
|
return Domain(uuid[9])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
|
||||||
|
// UUIDs.
|
||||||
|
func (uuid UUID) ID() uint32 {
|
||||||
|
return binary.BigEndian.Uint32(uuid[0:4])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Domain) String() string {
|
||||||
|
switch d {
|
||||||
|
case Person:
|
||||||
|
return "Person"
|
||||||
|
case Group:
|
||||||
|
return "Group"
|
||||||
|
case Org:
|
||||||
|
return "Org"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Domain%d", int(d))
|
||||||
|
}
|
||||||
12
vendor/github.com/google/uuid/doc.go
generated
vendored
Normal file
12
vendor/github.com/google/uuid/doc.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package uuid generates and inspects UUIDs.
|
||||||
|
//
|
||||||
|
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
|
||||||
|
// Services.
|
||||||
|
//
|
||||||
|
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
|
||||||
|
// maps or compared directly.
|
||||||
|
package uuid
|
||||||
59
vendor/github.com/google/uuid/hash.go
generated
vendored
Normal file
59
vendor/github.com/google/uuid/hash.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/sha1"
|
||||||
|
"hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Well known namespace IDs and UUIDs
|
||||||
|
var (
|
||||||
|
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
|
||||||
|
Nil UUID // empty UUID, all zeros
|
||||||
|
|
||||||
|
// The Max UUID is special form of UUID that is specified to have all 128 bits set to 1.
|
||||||
|
Max = UUID{
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewHash returns a new UUID derived from the hash of space concatenated with
|
||||||
|
// data generated by h. The hash should be at least 16 byte in length. The
|
||||||
|
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||||
|
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||||
|
// NewMD5 and NewSHA1.
|
||||||
|
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||||
|
h.Reset()
|
||||||
|
h.Write(space[:]) //nolint:errcheck
|
||||||
|
h.Write(data) //nolint:errcheck
|
||||||
|
s := h.Sum(nil)
|
||||||
|
var uuid UUID
|
||||||
|
copy(uuid[:], s)
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||||
|
// supplied name space and data. It is the same as calling:
|
||||||
|
//
|
||||||
|
// NewHash(md5.New(), space, data, 3)
|
||||||
|
func NewMD5(space UUID, data []byte) UUID {
|
||||||
|
return NewHash(md5.New(), space, data, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||||
|
// supplied name space and data. It is the same as calling:
|
||||||
|
//
|
||||||
|
// NewHash(sha1.New(), space, data, 5)
|
||||||
|
func NewSHA1(space UUID, data []byte) UUID {
|
||||||
|
return NewHash(sha1.New(), space, data, 5)
|
||||||
|
}
|
||||||
38
vendor/github.com/google/uuid/marshal.go
generated
vendored
Normal file
38
vendor/github.com/google/uuid/marshal.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
|
func (uuid UUID) MarshalText() ([]byte, error) {
|
||||||
|
var js [36]byte
|
||||||
|
encodeHex(js[:], uuid)
|
||||||
|
return js[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (uuid *UUID) UnmarshalText(data []byte) error {
|
||||||
|
id, err := ParseBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*uuid = id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||||
|
func (uuid UUID) MarshalBinary() ([]byte, error) {
|
||||||
|
return uuid[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||||
|
func (uuid *UUID) UnmarshalBinary(data []byte) error {
|
||||||
|
if len(data) != 16 {
|
||||||
|
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||||
|
}
|
||||||
|
copy(uuid[:], data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
90
vendor/github.com/google/uuid/node.go
generated
vendored
Normal file
90
vendor/github.com/google/uuid/node.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
nodeMu sync.Mutex
|
||||||
|
ifname string // name of interface being used
|
||||||
|
nodeID [6]byte // hardware for version 1 UUIDs
|
||||||
|
zeroID [6]byte // nodeID with only 0's
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodeInterface returns the name of the interface from which the NodeID was
|
||||||
|
// derived. The interface "user" is returned if the NodeID was set by
|
||||||
|
// SetNodeID.
|
||||||
|
func NodeInterface() string {
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
return ifname
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||||
|
// If name is "" then the first usable interface found will be used or a random
|
||||||
|
// Node ID will be generated. If a named interface cannot be found then false
|
||||||
|
// is returned.
|
||||||
|
//
|
||||||
|
// SetNodeInterface never fails when name is "".
|
||||||
|
func SetNodeInterface(name string) bool {
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
return setNodeInterface(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNodeInterface(name string) bool {
|
||||||
|
iname, addr := getHardwareInterface(name) // null implementation for js
|
||||||
|
if iname != "" && addr != nil {
|
||||||
|
ifname = iname
|
||||||
|
copy(nodeID[:], addr)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found no interfaces with a valid hardware address. If name
|
||||||
|
// does not specify a specific interface generate a random Node ID
|
||||||
|
// (section 4.1.6)
|
||||||
|
if name == "" {
|
||||||
|
ifname = "random"
|
||||||
|
randomBits(nodeID[:])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||||
|
// if not already set.
|
||||||
|
func NodeID() []byte {
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
if nodeID == zeroID {
|
||||||
|
setNodeInterface("")
|
||||||
|
}
|
||||||
|
nid := nodeID
|
||||||
|
return nid[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||||
|
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||||
|
// Node ID is not set.
|
||||||
|
func SetNodeID(id []byte) bool {
|
||||||
|
if len(id) < 6 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer nodeMu.Unlock()
|
||||||
|
nodeMu.Lock()
|
||||||
|
copy(nodeID[:], id)
|
||||||
|
ifname = "user"
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||||
|
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||||
|
func (uuid UUID) NodeID() []byte {
|
||||||
|
var node [6]byte
|
||||||
|
copy(node[:], uuid[10:])
|
||||||
|
return node[:]
|
||||||
|
}
|
||||||
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
Normal file
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build js
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
// getHardwareInterface returns nil values for the JS version of the code.
|
||||||
|
// This removes the "net" dependency, because it is not used in the browser.
|
||||||
|
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
|
||||||
|
func getHardwareInterface(name string) (string, []byte) { return "", nil }
|
||||||
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
Normal file
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !js
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
var interfaces []net.Interface // cached list of interfaces
|
||||||
|
|
||||||
|
// getHardwareInterface returns the name and hardware address of interface name.
|
||||||
|
// If name is "" then the name and hardware address of one of the system's
|
||||||
|
// interfaces is returned. If no interfaces are found (name does not exist or
|
||||||
|
// there are no interfaces) then "", nil is returned.
|
||||||
|
//
|
||||||
|
// Only addresses of at least 6 bytes are returned.
|
||||||
|
func getHardwareInterface(name string) (string, []byte) {
|
||||||
|
if interfaces == nil {
|
||||||
|
var err error
|
||||||
|
interfaces, err = net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, ifs := range interfaces {
|
||||||
|
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||||
|
return ifs.Name, ifs.HardwareAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
118
vendor/github.com/google/uuid/null.go
generated
vendored
Normal file
118
vendor/github.com/google/uuid/null.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"database/sql/driver"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var jsonNull = []byte("null")
|
||||||
|
|
||||||
|
// NullUUID represents a UUID that may be null.
|
||||||
|
// NullUUID implements the SQL driver.Scanner interface so
|
||||||
|
// it can be used as a scan destination:
|
||||||
|
//
|
||||||
|
// var u uuid.NullUUID
|
||||||
|
// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&u)
|
||||||
|
// ...
|
||||||
|
// if u.Valid {
|
||||||
|
// // use u.UUID
|
||||||
|
// } else {
|
||||||
|
// // NULL value
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type NullUUID struct {
|
||||||
|
UUID UUID
|
||||||
|
Valid bool // Valid is true if UUID is not NULL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan implements the SQL driver.Scanner interface.
|
||||||
|
func (nu *NullUUID) Scan(value interface{}) error {
|
||||||
|
if value == nil {
|
||||||
|
nu.UUID, nu.Valid = Nil, false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := nu.UUID.Scan(value)
|
||||||
|
if err != nil {
|
||||||
|
nu.Valid = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nu.Valid = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements the driver Valuer interface.
|
||||||
|
func (nu NullUUID) Value() (driver.Value, error) {
|
||||||
|
if !nu.Valid {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
// Delegate to UUID Value function
|
||||||
|
return nu.UUID.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||||
|
func (nu NullUUID) MarshalBinary() ([]byte, error) {
|
||||||
|
if nu.Valid {
|
||||||
|
return nu.UUID[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||||
|
func (nu *NullUUID) UnmarshalBinary(data []byte) error {
|
||||||
|
if len(data) != 16 {
|
||||||
|
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||||
|
}
|
||||||
|
copy(nu.UUID[:], data)
|
||||||
|
nu.Valid = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
|
func (nu NullUUID) MarshalText() ([]byte, error) {
|
||||||
|
if nu.Valid {
|
||||||
|
return nu.UUID.MarshalText()
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonNull, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
|
func (nu *NullUUID) UnmarshalText(data []byte) error {
|
||||||
|
id, err := ParseBytes(data)
|
||||||
|
if err != nil {
|
||||||
|
nu.Valid = false
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nu.UUID = id
|
||||||
|
nu.Valid = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaler.
|
||||||
|
func (nu NullUUID) MarshalJSON() ([]byte, error) {
|
||||||
|
if nu.Valid {
|
||||||
|
return json.Marshal(nu.UUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonNull, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaler.
|
||||||
|
func (nu *NullUUID) UnmarshalJSON(data []byte) error {
|
||||||
|
if bytes.Equal(data, jsonNull) {
|
||||||
|
*nu = NullUUID{}
|
||||||
|
return nil // valid null UUID
|
||||||
|
}
|
||||||
|
err := json.Unmarshal(data, &nu.UUID)
|
||||||
|
nu.Valid = err == nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
59
vendor/github.com/google/uuid/sql.go
generated
vendored
Normal file
59
vendor/github.com/google/uuid/sql.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Scan implements sql.Scanner so UUIDs can be read from databases transparently.
|
||||||
|
// Currently, database types that map to string and []byte are supported. Please
|
||||||
|
// consult database-specific driver documentation for matching types.
|
||||||
|
func (uuid *UUID) Scan(src interface{}) error {
|
||||||
|
switch src := src.(type) {
|
||||||
|
case nil:
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case string:
|
||||||
|
// if an empty UUID comes from a table, we return a null UUID
|
||||||
|
if src == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// see Parse for required string format
|
||||||
|
u, err := Parse(src)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Scan: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*uuid = u
|
||||||
|
|
||||||
|
case []byte:
|
||||||
|
// if an empty UUID comes from a table, we return a null UUID
|
||||||
|
if len(src) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assumes a simple slice of bytes if 16 bytes
|
||||||
|
// otherwise attempts to parse
|
||||||
|
if len(src) != 16 {
|
||||||
|
return uuid.Scan(string(src))
|
||||||
|
}
|
||||||
|
copy((*uuid)[:], src)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements sql.Valuer so that UUIDs can be written to databases
|
||||||
|
// transparently. Currently, UUIDs map to strings. Please consult
|
||||||
|
// database-specific driver documentation for matching types.
|
||||||
|
func (uuid UUID) Value() (driver.Value, error) {
|
||||||
|
return uuid.String(), nil
|
||||||
|
}
|
||||||
134
vendor/github.com/google/uuid/time.go
generated
vendored
Normal file
134
vendor/github.com/google/uuid/time.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||||
|
// 1582.
|
||||||
|
type Time int64
|
||||||
|
|
||||||
|
const (
|
||||||
|
lillian = 2299160 // Julian day of 15 Oct 1582
|
||||||
|
unix = 2440587 // Julian day of 1 Jan 1970
|
||||||
|
epoch = unix - lillian // Days between epochs
|
||||||
|
g1582 = epoch * 86400 // seconds between epochs
|
||||||
|
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
timeMu sync.Mutex
|
||||||
|
lasttime uint64 // last time we returned
|
||||||
|
clockSeq uint16 // clock sequence for this run
|
||||||
|
|
||||||
|
timeNow = time.Now // for testing
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnixTime converts t the number of seconds and nanoseconds using the Unix
|
||||||
|
// epoch of 1 Jan 1970.
|
||||||
|
func (t Time) UnixTime() (sec, nsec int64) {
|
||||||
|
sec = int64(t - g1582ns100)
|
||||||
|
nsec = (sec % 10000000) * 100
|
||||||
|
sec /= 10000000
|
||||||
|
return sec, nsec
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||||
|
// clock sequence as well as adjusting the clock sequence as needed. An error
|
||||||
|
// is returned if the current time cannot be determined.
|
||||||
|
func GetTime() (Time, uint16, error) {
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
timeMu.Lock()
|
||||||
|
return getTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTime() (Time, uint16, error) {
|
||||||
|
t := timeNow()
|
||||||
|
|
||||||
|
// If we don't have a clock sequence already, set one.
|
||||||
|
if clockSeq == 0 {
|
||||||
|
setClockSequence(-1)
|
||||||
|
}
|
||||||
|
now := uint64(t.UnixNano()/100) + g1582ns100
|
||||||
|
|
||||||
|
// If time has gone backwards with this clock sequence then we
|
||||||
|
// increment the clock sequence
|
||||||
|
if now <= lasttime {
|
||||||
|
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
|
||||||
|
}
|
||||||
|
lasttime = now
|
||||||
|
return Time(now), clockSeq, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClockSequence returns the current clock sequence, generating one if not
|
||||||
|
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||||
|
//
|
||||||
|
// The uuid package does not use global static storage for the clock sequence or
|
||||||
|
// the last time a UUID was generated. Unless SetClockSequence is used, a new
|
||||||
|
// random clock sequence is generated the first time a clock sequence is
|
||||||
|
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
|
||||||
|
func ClockSequence() int {
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
timeMu.Lock()
|
||||||
|
return clockSequence()
|
||||||
|
}
|
||||||
|
|
||||||
|
func clockSequence() int {
|
||||||
|
if clockSeq == 0 {
|
||||||
|
setClockSequence(-1)
|
||||||
|
}
|
||||||
|
return int(clockSeq & 0x3fff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||||
|
// -1 causes a new sequence to be generated.
|
||||||
|
func SetClockSequence(seq int) {
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
timeMu.Lock()
|
||||||
|
setClockSequence(seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setClockSequence(seq int) {
|
||||||
|
if seq == -1 {
|
||||||
|
var b [2]byte
|
||||||
|
randomBits(b[:]) // clock sequence
|
||||||
|
seq = int(b[0])<<8 | int(b[1])
|
||||||
|
}
|
||||||
|
oldSeq := clockSeq
|
||||||
|
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||||
|
if oldSeq != clockSeq {
|
||||||
|
lasttime = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||||
|
// uuid. The time is only defined for version 1, 2, 6 and 7 UUIDs.
|
||||||
|
func (uuid UUID) Time() Time {
|
||||||
|
var t Time
|
||||||
|
switch uuid.Version() {
|
||||||
|
case 6:
|
||||||
|
time := binary.BigEndian.Uint64(uuid[:8]) // Ignore uuid[6] version b0110
|
||||||
|
t = Time(time)
|
||||||
|
case 7:
|
||||||
|
time := binary.BigEndian.Uint64(uuid[:8])
|
||||||
|
t = Time((time>>16)*10000 + g1582ns100)
|
||||||
|
default: // forward compatible
|
||||||
|
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||||
|
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||||
|
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||||
|
t = Time(time)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClockSequence returns the clock sequence encoded in uuid.
|
||||||
|
// The clock sequence is only well defined for version 1 and 2 UUIDs.
|
||||||
|
func (uuid UUID) ClockSequence() int {
|
||||||
|
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
|
||||||
|
}
|
||||||
43
vendor/github.com/google/uuid/util.go
generated
vendored
Normal file
43
vendor/github.com/google/uuid/util.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// randomBits completely fills slice b with random data.
|
||||||
|
func randomBits(b []byte) {
|
||||||
|
if _, err := io.ReadFull(rander, b); err != nil {
|
||||||
|
panic(err.Error()) // rand should never fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||||
|
var xvalues = [256]byte{
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
}
|
||||||
|
|
||||||
|
// xtob converts hex characters x1 and x2 into a byte.
|
||||||
|
func xtob(x1, x2 byte) (byte, bool) {
|
||||||
|
b1 := xvalues[x1]
|
||||||
|
b2 := xvalues[x2]
|
||||||
|
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||||
|
}
|
||||||
365
vendor/github.com/google/uuid/uuid.go
generated
vendored
Normal file
365
vendor/github.com/google/uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
// Copyright 2018 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||||
|
// 4122.
|
||||||
|
type UUID [16]byte
|
||||||
|
|
||||||
|
// A Version represents a UUID's version.
|
||||||
|
type Version byte
|
||||||
|
|
||||||
|
// A Variant represents a UUID's variant.
|
||||||
|
type Variant byte
|
||||||
|
|
||||||
|
// Constants returned by Variant.
|
||||||
|
const (
|
||||||
|
Invalid = Variant(iota) // Invalid UUID
|
||||||
|
RFC4122 // The variant specified in RFC4122
|
||||||
|
Reserved // Reserved, NCS backward compatibility.
|
||||||
|
Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||||
|
Future // Reserved for future definition.
|
||||||
|
)
|
||||||
|
|
||||||
|
const randPoolSize = 16 * 16
|
||||||
|
|
||||||
|
var (
|
||||||
|
rander = rand.Reader // random function
|
||||||
|
poolEnabled = false
|
||||||
|
poolMu sync.Mutex
|
||||||
|
poolPos = randPoolSize // protected with poolMu
|
||||||
|
pool [randPoolSize]byte // protected with poolMu
|
||||||
|
)
|
||||||
|
|
||||||
|
type invalidLengthError struct{ len int }
|
||||||
|
|
||||||
|
func (err invalidLengthError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid UUID length: %d", err.len)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInvalidLengthError is matcher function for custom error invalidLengthError
|
||||||
|
func IsInvalidLengthError(err error) bool {
|
||||||
|
_, ok := err.(invalidLengthError)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse decodes s into a UUID or returns an error if it cannot be parsed. Both
|
||||||
|
// the standard UUID forms defined in RFC 4122
|
||||||
|
// (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) are decoded. In addition,
|
||||||
|
// Parse accepts non-standard strings such as the raw hex encoding
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and 38 byte "Microsoft style" encodings,
|
||||||
|
// e.g. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}. Only the middle 36 bytes are
|
||||||
|
// examined in the latter case. Parse should not be used to validate strings as
|
||||||
|
// it parses non-standard encodings as indicated above.
|
||||||
|
func Parse(s string) (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
switch len(s) {
|
||||||
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36:
|
||||||
|
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36 + 9:
|
||||||
|
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||||
|
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||||
|
}
|
||||||
|
s = s[9:]
|
||||||
|
|
||||||
|
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
case 36 + 2:
|
||||||
|
s = s[1:]
|
||||||
|
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
case 32:
|
||||||
|
var ok bool
|
||||||
|
for i := range uuid {
|
||||||
|
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
default:
|
||||||
|
return uuid, invalidLengthError{len(s)}
|
||||||
|
}
|
||||||
|
// s is now at least 36 bytes long
|
||||||
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
for i, x := range [16]int{
|
||||||
|
0, 2, 4, 6,
|
||||||
|
9, 11,
|
||||||
|
14, 16,
|
||||||
|
19, 21,
|
||||||
|
24, 26, 28, 30, 32, 34,
|
||||||
|
} {
|
||||||
|
v, ok := xtob(s[x], s[x+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
uuid[i] = v
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||||
|
func ParseBytes(b []byte) (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
switch len(b) {
|
||||||
|
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
|
||||||
|
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||||
|
}
|
||||||
|
b = b[9:]
|
||||||
|
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
b = b[1:]
|
||||||
|
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
var ok bool
|
||||||
|
for i := 0; i < 32; i += 2 {
|
||||||
|
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
default:
|
||||||
|
return uuid, invalidLengthError{len(b)}
|
||||||
|
}
|
||||||
|
// s is now at least 36 bytes long
|
||||||
|
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
for i, x := range [16]int{
|
||||||
|
0, 2, 4, 6,
|
||||||
|
9, 11,
|
||||||
|
14, 16,
|
||||||
|
19, 21,
|
||||||
|
24, 26, 28, 30, 32, 34,
|
||||||
|
} {
|
||||||
|
v, ok := xtob(b[x], b[x+1])
|
||||||
|
if !ok {
|
||||||
|
return uuid, errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
uuid[i] = v
|
||||||
|
}
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustParse is like Parse but panics if the string cannot be parsed.
|
||||||
|
// It simplifies safe initialization of global variables holding compiled UUIDs.
|
||||||
|
func MustParse(s string) UUID {
|
||||||
|
uuid, err := Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(`uuid: Parse(` + s + `): ` + err.Error())
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
|
||||||
|
// does not have a length of 16. The bytes are copied from the slice.
|
||||||
|
func FromBytes(b []byte) (uuid UUID, err error) {
|
||||||
|
err = uuid.UnmarshalBinary(b)
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must returns uuid if err is nil and panics otherwise.
|
||||||
|
func Must(uuid UUID, err error) UUID {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate returns an error if s is not a properly formatted UUID in one of the following formats:
|
||||||
|
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||||
|
// It returns an error if the format is invalid, otherwise nil.
|
||||||
|
func Validate(s string) error {
|
||||||
|
switch len(s) {
|
||||||
|
// Standard UUID format
|
||||||
|
case 36:
|
||||||
|
|
||||||
|
// UUID with "urn:uuid:" prefix
|
||||||
|
case 36 + 9:
|
||||||
|
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||||
|
return fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||||
|
}
|
||||||
|
s = s[9:]
|
||||||
|
|
||||||
|
// UUID enclosed in braces
|
||||||
|
case 36 + 2:
|
||||||
|
if s[0] != '{' || s[len(s)-1] != '}' {
|
||||||
|
return fmt.Errorf("invalid bracketed UUID format")
|
||||||
|
}
|
||||||
|
s = s[1 : len(s)-1]
|
||||||
|
|
||||||
|
// UUID without hyphens
|
||||||
|
case 32:
|
||||||
|
for i := 0; i < len(s); i += 2 {
|
||||||
|
_, ok := xtob(s[i], s[i+1])
|
||||||
|
if !ok {
|
||||||
|
return errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return invalidLengthError{len(s)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for standard UUID format
|
||||||
|
if len(s) == 36 {
|
||||||
|
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||||
|
return errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
for _, x := range []int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} {
|
||||||
|
if _, ok := xtob(s[x], s[x+1]); !ok {
|
||||||
|
return errors.New("invalid UUID format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
// , or "" if uuid is invalid.
|
||||||
|
func (uuid UUID) String() string {
|
||||||
|
var buf [36]byte
|
||||||
|
encodeHex(buf[:], uuid)
|
||||||
|
return string(buf[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// URN returns the RFC 2141 URN form of uuid,
|
||||||
|
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||||
|
func (uuid UUID) URN() string {
|
||||||
|
var buf [36 + 9]byte
|
||||||
|
copy(buf[:], "urn:uuid:")
|
||||||
|
encodeHex(buf[9:], uuid)
|
||||||
|
return string(buf[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeHex(dst []byte, uuid UUID) {
|
||||||
|
hex.Encode(dst, uuid[:4])
|
||||||
|
dst[8] = '-'
|
||||||
|
hex.Encode(dst[9:13], uuid[4:6])
|
||||||
|
dst[13] = '-'
|
||||||
|
hex.Encode(dst[14:18], uuid[6:8])
|
||||||
|
dst[18] = '-'
|
||||||
|
hex.Encode(dst[19:23], uuid[8:10])
|
||||||
|
dst[23] = '-'
|
||||||
|
hex.Encode(dst[24:], uuid[10:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variant returns the variant encoded in uuid.
|
||||||
|
func (uuid UUID) Variant() Variant {
|
||||||
|
switch {
|
||||||
|
case (uuid[8] & 0xc0) == 0x80:
|
||||||
|
return RFC4122
|
||||||
|
case (uuid[8] & 0xe0) == 0xc0:
|
||||||
|
return Microsoft
|
||||||
|
case (uuid[8] & 0xe0) == 0xe0:
|
||||||
|
return Future
|
||||||
|
default:
|
||||||
|
return Reserved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns the version of uuid.
|
||||||
|
func (uuid UUID) Version() Version {
|
||||||
|
return Version(uuid[6] >> 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Version) String() string {
|
||||||
|
if v > 15 {
|
||||||
|
return fmt.Sprintf("BAD_VERSION_%d", v)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("VERSION_%d", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Variant) String() string {
|
||||||
|
switch v {
|
||||||
|
case RFC4122:
|
||||||
|
return "RFC4122"
|
||||||
|
case Reserved:
|
||||||
|
return "Reserved"
|
||||||
|
case Microsoft:
|
||||||
|
return "Microsoft"
|
||||||
|
case Future:
|
||||||
|
return "Future"
|
||||||
|
case Invalid:
|
||||||
|
return "Invalid"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("BadVariant%d", int(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRand sets the random number generator to r, which implements io.Reader.
|
||||||
|
// If r.Read returns an error when the package requests random data then
|
||||||
|
// a panic will be issued.
|
||||||
|
//
|
||||||
|
// Calling SetRand with nil sets the random number generator to the default
|
||||||
|
// generator.
|
||||||
|
func SetRand(r io.Reader) {
|
||||||
|
if r == nil {
|
||||||
|
rander = rand.Reader
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rander = r
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableRandPool enables internal randomness pool used for Random
|
||||||
|
// (Version 4) UUID generation. The pool contains random bytes read from
|
||||||
|
// the random number generator on demand in batches. Enabling the pool
|
||||||
|
// may improve the UUID generation throughput significantly.
|
||||||
|
//
|
||||||
|
// Since the pool is stored on the Go heap, this feature may be a bad fit
|
||||||
|
// for security sensitive applications.
|
||||||
|
//
|
||||||
|
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||||
|
// only be called when there is no possibility that New or any other
|
||||||
|
// UUID Version 4 generation function will be called concurrently.
|
||||||
|
func EnableRandPool() {
|
||||||
|
poolEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableRandPool disables the randomness pool if it was previously
|
||||||
|
// enabled with EnableRandPool.
|
||||||
|
//
|
||||||
|
// Both EnableRandPool and DisableRandPool are not thread-safe and should
|
||||||
|
// only be called when there is no possibility that New or any other
|
||||||
|
// UUID Version 4 generation function will be called concurrently.
|
||||||
|
func DisableRandPool() {
|
||||||
|
poolEnabled = false
|
||||||
|
defer poolMu.Unlock()
|
||||||
|
poolMu.Lock()
|
||||||
|
poolPos = randPoolSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// UUIDs is a slice of UUID types.
|
||||||
|
type UUIDs []UUID
|
||||||
|
|
||||||
|
// Strings returns a string slice containing the string form of each UUID in uuids.
|
||||||
|
func (uuids UUIDs) Strings() []string {
|
||||||
|
var uuidStrs = make([]string, len(uuids))
|
||||||
|
for i, uuid := range uuids {
|
||||||
|
uuidStrs[i] = uuid.String()
|
||||||
|
}
|
||||||
|
return uuidStrs
|
||||||
|
}
|
||||||
44
vendor/github.com/google/uuid/version1.go
generated
vendored
Normal file
44
vendor/github.com/google/uuid/version1.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||||
|
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||||
|
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||||
|
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||||
|
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||||
|
// return the current NewUUID returns nil and an error.
|
||||||
|
//
|
||||||
|
// In most cases, New should be used.
|
||||||
|
func NewUUID() (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
now, seq, err := GetTime()
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
timeLow := uint32(now & 0xffffffff)
|
||||||
|
timeMid := uint16((now >> 32) & 0xffff)
|
||||||
|
timeHi := uint16((now >> 48) & 0x0fff)
|
||||||
|
timeHi |= 0x1000 // Version 1
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint32(uuid[0:], timeLow)
|
||||||
|
binary.BigEndian.PutUint16(uuid[4:], timeMid)
|
||||||
|
binary.BigEndian.PutUint16(uuid[6:], timeHi)
|
||||||
|
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||||
|
|
||||||
|
nodeMu.Lock()
|
||||||
|
if nodeID == zeroID {
|
||||||
|
setNodeInterface("")
|
||||||
|
}
|
||||||
|
copy(uuid[10:], nodeID[:])
|
||||||
|
nodeMu.Unlock()
|
||||||
|
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
76
vendor/github.com/google/uuid/version4.go
generated
vendored
Normal file
76
vendor/github.com/google/uuid/version4.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
// New creates a new random UUID or panics. New is equivalent to
|
||||||
|
// the expression
|
||||||
|
//
|
||||||
|
// uuid.Must(uuid.NewRandom())
|
||||||
|
func New() UUID {
|
||||||
|
return Must(NewRandom())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewString creates a new random UUID and returns it as a string or panics.
|
||||||
|
// NewString is equivalent to the expression
|
||||||
|
//
|
||||||
|
// uuid.New().String()
|
||||||
|
func NewString() string {
|
||||||
|
return Must(NewRandom()).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRandom returns a Random (Version 4) UUID.
|
||||||
|
//
|
||||||
|
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||||
|
// package.
|
||||||
|
//
|
||||||
|
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||||
|
//
|
||||||
|
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||||
|
//
|
||||||
|
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||||
|
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||||
|
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||||
|
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||||
|
// year and having one duplicate.
|
||||||
|
func NewRandom() (UUID, error) {
|
||||||
|
if !poolEnabled {
|
||||||
|
return NewRandomFromReader(rander)
|
||||||
|
}
|
||||||
|
return newRandomFromPool()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRandomFromReader returns a UUID based on bytes read from a given io.Reader.
|
||||||
|
func NewRandomFromReader(r io.Reader) (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
_, err := io.ReadFull(r, uuid[:])
|
||||||
|
if err != nil {
|
||||||
|
return Nil, err
|
||||||
|
}
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRandomFromPool() (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
poolMu.Lock()
|
||||||
|
if poolPos == randPoolSize {
|
||||||
|
_, err := io.ReadFull(rander, pool[:])
|
||||||
|
if err != nil {
|
||||||
|
poolMu.Unlock()
|
||||||
|
return Nil, err
|
||||||
|
}
|
||||||
|
poolPos = 0
|
||||||
|
}
|
||||||
|
copy(uuid[:], pool[poolPos:(poolPos+16)])
|
||||||
|
poolPos += 16
|
||||||
|
poolMu.Unlock()
|
||||||
|
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
56
vendor/github.com/google/uuid/version6.go
generated
vendored
Normal file
56
vendor/github.com/google/uuid/version6.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2023 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
// UUID version 6 is a field-compatible version of UUIDv1, reordered for improved DB locality.
|
||||||
|
// It is expected that UUIDv6 will primarily be used in contexts where there are existing v1 UUIDs.
|
||||||
|
// Systems that do not involve legacy UUIDv1 SHOULD consider using UUIDv7 instead.
|
||||||
|
//
|
||||||
|
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#uuidv6
|
||||||
|
//
|
||||||
|
// NewV6 returns a Version 6 UUID based on the current NodeID and clock
|
||||||
|
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||||
|
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||||
|
// be set NewV6 set NodeID is random bits automatically . If clock sequence has not been set by
|
||||||
|
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||||
|
// return the current NewV6 returns Nil and an error.
|
||||||
|
func NewV6() (UUID, error) {
|
||||||
|
var uuid UUID
|
||||||
|
now, seq, err := GetTime()
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| time_high |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| time_mid | time_low_and_version |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|clk_seq_hi_res | clk_seq_low | node (0-1) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| node (2-5) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint64(uuid[0:], uint64(now))
|
||||||
|
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||||
|
|
||||||
|
uuid[6] = 0x60 | (uuid[6] & 0x0F)
|
||||||
|
uuid[8] = 0x80 | (uuid[8] & 0x3F)
|
||||||
|
|
||||||
|
nodeMu.Lock()
|
||||||
|
if nodeID == zeroID {
|
||||||
|
setNodeInterface("")
|
||||||
|
}
|
||||||
|
copy(uuid[10:], nodeID[:])
|
||||||
|
nodeMu.Unlock()
|
||||||
|
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
104
vendor/github.com/google/uuid/version7.go
generated
vendored
Normal file
104
vendor/github.com/google/uuid/version7.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// Copyright 2023 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UUID version 7 features a time-ordered value field derived from the widely
|
||||||
|
// implemented and well known Unix Epoch timestamp source,
|
||||||
|
// the number of milliseconds seconds since midnight 1 Jan 1970 UTC, leap seconds excluded.
|
||||||
|
// As well as improved entropy characteristics over versions 1 or 6.
|
||||||
|
//
|
||||||
|
// see https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-03#name-uuid-version-7
|
||||||
|
//
|
||||||
|
// Implementations SHOULD utilize UUID version 7 over UUID version 1 and 6 if possible.
|
||||||
|
//
|
||||||
|
// NewV7 returns a Version 7 UUID based on the current time(Unix Epoch).
|
||||||
|
// Uses the randomness pool if it was enabled with EnableRandPool.
|
||||||
|
// On error, NewV7 returns Nil and an error
|
||||||
|
func NewV7() (UUID, error) {
|
||||||
|
uuid, err := NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
makeV7(uuid[:])
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewV7FromReader returns a Version 7 UUID based on the current time(Unix Epoch).
|
||||||
|
// it use NewRandomFromReader fill random bits.
|
||||||
|
// On error, NewV7FromReader returns Nil and an error.
|
||||||
|
func NewV7FromReader(r io.Reader) (UUID, error) {
|
||||||
|
uuid, err := NewRandomFromReader(r)
|
||||||
|
if err != nil {
|
||||||
|
return uuid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
makeV7(uuid[:])
|
||||||
|
return uuid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeV7 fill 48 bits time (uuid[0] - uuid[5]), set version b0111 (uuid[6])
|
||||||
|
// uuid[8] already has the right version number (Variant is 10)
|
||||||
|
// see function NewV7 and NewV7FromReader
|
||||||
|
func makeV7(uuid []byte) {
|
||||||
|
/*
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| unix_ts_ms |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| unix_ts_ms | ver | rand_a (12 bit seq) |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|var| rand_b |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| rand_b |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
_ = uuid[15] // bounds check
|
||||||
|
|
||||||
|
t, s := getV7Time()
|
||||||
|
|
||||||
|
uuid[0] = byte(t >> 40)
|
||||||
|
uuid[1] = byte(t >> 32)
|
||||||
|
uuid[2] = byte(t >> 24)
|
||||||
|
uuid[3] = byte(t >> 16)
|
||||||
|
uuid[4] = byte(t >> 8)
|
||||||
|
uuid[5] = byte(t)
|
||||||
|
|
||||||
|
uuid[6] = 0x70 | (0x0F & byte(s>>8))
|
||||||
|
uuid[7] = byte(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lastV7time is the last time we returned stored as:
|
||||||
|
//
|
||||||
|
// 52 bits of time in milliseconds since epoch
|
||||||
|
// 12 bits of (fractional nanoseconds) >> 8
|
||||||
|
var lastV7time int64
|
||||||
|
|
||||||
|
const nanoPerMilli = 1000000
|
||||||
|
|
||||||
|
// getV7Time returns the time in milliseconds and nanoseconds / 256.
|
||||||
|
// The returned (milli << 12 + seq) is guarenteed to be greater than
|
||||||
|
// (milli << 12 + seq) returned by any previous call to getV7Time.
|
||||||
|
func getV7Time() (milli, seq int64) {
|
||||||
|
timeMu.Lock()
|
||||||
|
defer timeMu.Unlock()
|
||||||
|
|
||||||
|
nano := timeNow().UnixNano()
|
||||||
|
milli = nano / nanoPerMilli
|
||||||
|
// Sequence number is between 0 and 3906 (nanoPerMilli>>8)
|
||||||
|
seq = (nano - milli*nanoPerMilli) >> 8
|
||||||
|
now := milli<<12 + seq
|
||||||
|
if now <= lastV7time {
|
||||||
|
now = lastV7time + 1
|
||||||
|
milli = now >> 12
|
||||||
|
seq = now & 0xfff
|
||||||
|
}
|
||||||
|
lastV7time = now
|
||||||
|
return milli, seq
|
||||||
|
}
|
||||||
4
vendor/github.com/sirupsen/logrus/.gitignore
generated
vendored
4
vendor/github.com/sirupsen/logrus/.gitignore
generated
vendored
@@ -1,4 +0,0 @@
|
|||||||
logrus
|
|
||||||
vendor
|
|
||||||
|
|
||||||
.idea/
|
|
||||||
40
vendor/github.com/sirupsen/logrus/.golangci.yml
generated
vendored
40
vendor/github.com/sirupsen/logrus/.golangci.yml
generated
vendored
@@ -1,40 +0,0 @@
|
|||||||
run:
|
|
||||||
# do not run on test files yet
|
|
||||||
tests: false
|
|
||||||
|
|
||||||
# all available settings of specific linters
|
|
||||||
linters-settings:
|
|
||||||
errcheck:
|
|
||||||
# report about not checking of errors in type assetions: `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
|
|
||||||
|
|
||||||
lll:
|
|
||||||
line-length: 100
|
|
||||||
tab-width: 4
|
|
||||||
|
|
||||||
prealloc:
|
|
||||||
simple: false
|
|
||||||
range-loops: false
|
|
||||||
for-loops: 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
|
|
||||||
|
|
||||||
linters:
|
|
||||||
enable:
|
|
||||||
- megacheck
|
|
||||||
- govet
|
|
||||||
disable:
|
|
||||||
- maligned
|
|
||||||
- prealloc
|
|
||||||
disable-all: false
|
|
||||||
presets:
|
|
||||||
- bugs
|
|
||||||
- unused
|
|
||||||
fast: false
|
|
||||||
15
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
15
vendor/github.com/sirupsen/logrus/.travis.yml
generated
vendored
@@ -1,15 +0,0 @@
|
|||||||
language: go
|
|
||||||
go_import_path: github.com/sirupsen/logrus
|
|
||||||
git:
|
|
||||||
depth: 1
|
|
||||||
env:
|
|
||||||
- GO111MODULE=on
|
|
||||||
go: 1.15.x
|
|
||||||
os: linux
|
|
||||||
install:
|
|
||||||
- ./travis/install.sh
|
|
||||||
script:
|
|
||||||
- cd ci
|
|
||||||
- go run mage.go -v -w ../ crossBuild
|
|
||||||
- go run mage.go -v -w ../ lint
|
|
||||||
- go run mage.go -v -w ../ test
|
|
||||||
259
vendor/github.com/sirupsen/logrus/CHANGELOG.md
generated
vendored
259
vendor/github.com/sirupsen/logrus/CHANGELOG.md
generated
vendored
@@ -1,259 +0,0 @@
|
|||||||
# 1.8.1
|
|
||||||
Code quality:
|
|
||||||
* move magefile in its own subdir/submodule to remove magefile dependency on logrus consumer
|
|
||||||
* improve timestamp format documentation
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
* fix race condition on logger hooks
|
|
||||||
|
|
||||||
|
|
||||||
# 1.8.0
|
|
||||||
|
|
||||||
Correct versioning number replacing v1.7.1.
|
|
||||||
|
|
||||||
# 1.7.1
|
|
||||||
|
|
||||||
Beware this release has introduced a new public API and its semver is therefore incorrect.
|
|
||||||
|
|
||||||
Code quality:
|
|
||||||
* use go 1.15 in travis
|
|
||||||
* use magefile as task runner
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
* small fixes about new go 1.13 error formatting system
|
|
||||||
* Fix for long time race condiction with mutating data hooks
|
|
||||||
|
|
||||||
Features:
|
|
||||||
* build support for zos
|
|
||||||
|
|
||||||
# 1.7.0
|
|
||||||
Fixes:
|
|
||||||
* the dependency toward a windows terminal library has been removed
|
|
||||||
|
|
||||||
Features:
|
|
||||||
* a new buffer pool management API has been added
|
|
||||||
* a set of `<LogLevel>Fn()` functions have been added
|
|
||||||
|
|
||||||
# 1.6.0
|
|
||||||
Fixes:
|
|
||||||
* end of line cleanup
|
|
||||||
* revert the entry concurrency bug fix whic leads to deadlock under some circumstances
|
|
||||||
* update dependency on go-windows-terminal-sequences to fix a crash with go 1.14
|
|
||||||
|
|
||||||
Features:
|
|
||||||
* add an option to the `TextFormatter` to completely disable fields quoting
|
|
||||||
|
|
||||||
# 1.5.0
|
|
||||||
Code quality:
|
|
||||||
* add golangci linter run on travis
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
* add mutex for hooks concurrent access on `Entry` data
|
|
||||||
* caller function field for go1.14
|
|
||||||
* fix build issue for gopherjs target
|
|
||||||
|
|
||||||
Feature:
|
|
||||||
* add an hooks/writer sub-package whose goal is to split output on different stream depending on the trace level
|
|
||||||
* add a `DisableHTMLEscape` option in the `JSONFormatter`
|
|
||||||
* add `ForceQuote` and `PadLevelText` options in the `TextFormatter`
|
|
||||||
|
|
||||||
# 1.4.2
|
|
||||||
* Fixes build break for plan9, nacl, solaris
|
|
||||||
# 1.4.1
|
|
||||||
This new release introduces:
|
|
||||||
* Enhance TextFormatter to not print caller information when they are empty (#944)
|
|
||||||
* Remove dependency on golang.org/x/crypto (#932, #943)
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
* Fix Entry.WithContext method to return a copy of the initial entry (#941)
|
|
||||||
|
|
||||||
# 1.4.0
|
|
||||||
This new release introduces:
|
|
||||||
* Add `DeferExitHandler`, similar to `RegisterExitHandler` but prepending the handler to the list of handlers (semantically like `defer`) (#848).
|
|
||||||
* Add `CallerPrettyfier` to `JSONFormatter` and `TextFormatter` (#909, #911)
|
|
||||||
* Add `Entry.WithContext()` and `Entry.Context`, to set a context on entries to be used e.g. in hooks (#919).
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
* Fix wrong method calls `Logger.Print` and `Logger.Warningln` (#893).
|
|
||||||
* Update `Entry.Logf` to not do string formatting unless the log level is enabled (#903)
|
|
||||||
* Fix infinite recursion on unknown `Level.String()` (#907)
|
|
||||||
* Fix race condition in `getCaller` (#916).
|
|
||||||
|
|
||||||
|
|
||||||
# 1.3.0
|
|
||||||
This new release introduces:
|
|
||||||
* Log, Logf, Logln functions for Logger and Entry that take a Level
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
* Building prometheus node_exporter on AIX (#840)
|
|
||||||
* Race condition in TextFormatter (#468)
|
|
||||||
* Travis CI import path (#868)
|
|
||||||
* Remove coloured output on Windows (#862)
|
|
||||||
* Pointer to func as field in JSONFormatter (#870)
|
|
||||||
* Properly marshal Levels (#873)
|
|
||||||
|
|
||||||
# 1.2.0
|
|
||||||
This new release introduces:
|
|
||||||
* A new method `SetReportCaller` in the `Logger` to enable the file, line and calling function from which the trace has been issued
|
|
||||||
* A new trace level named `Trace` whose level is below `Debug`
|
|
||||||
* A configurable exit function to be called upon a Fatal trace
|
|
||||||
* The `Level` object now implements `encoding.TextUnmarshaler` interface
|
|
||||||
|
|
||||||
# 1.1.1
|
|
||||||
This is a bug fix release.
|
|
||||||
* fix the build break on Solaris
|
|
||||||
* don't drop a whole trace in JSONFormatter when a field param is a function pointer which can not be serialized
|
|
||||||
|
|
||||||
# 1.1.0
|
|
||||||
This new release introduces:
|
|
||||||
* several fixes:
|
|
||||||
* a fix for a race condition on entry formatting
|
|
||||||
* proper cleanup of previously used entries before putting them back in the pool
|
|
||||||
* the extra new line at the end of message in text formatter has been removed
|
|
||||||
* a new global public API to check if a level is activated: IsLevelEnabled
|
|
||||||
* the following methods have been added to the Logger object
|
|
||||||
* IsLevelEnabled
|
|
||||||
* SetFormatter
|
|
||||||
* SetOutput
|
|
||||||
* ReplaceHooks
|
|
||||||
* introduction of go module
|
|
||||||
* an indent configuration for the json formatter
|
|
||||||
* output colour support for windows
|
|
||||||
* the field sort function is now configurable for text formatter
|
|
||||||
* the CLICOLOR and CLICOLOR\_FORCE environment variable support in text formater
|
|
||||||
|
|
||||||
# 1.0.6
|
|
||||||
|
|
||||||
This new release introduces:
|
|
||||||
* a new api WithTime which allows to easily force the time of the log entry
|
|
||||||
which is mostly useful for logger wrapper
|
|
||||||
* a fix reverting the immutability of the entry given as parameter to the hooks
|
|
||||||
a new configuration field of the json formatter in order to put all the fields
|
|
||||||
in a nested dictionnary
|
|
||||||
* a new SetOutput method in the Logger
|
|
||||||
* a new configuration of the textformatter to configure the name of the default keys
|
|
||||||
* a new configuration of the text formatter to disable the level truncation
|
|
||||||
|
|
||||||
# 1.0.5
|
|
||||||
|
|
||||||
* Fix hooks race (#707)
|
|
||||||
* Fix panic deadlock (#695)
|
|
||||||
|
|
||||||
# 1.0.4
|
|
||||||
|
|
||||||
* Fix race when adding hooks (#612)
|
|
||||||
* Fix terminal check in AppEngine (#635)
|
|
||||||
|
|
||||||
# 1.0.3
|
|
||||||
|
|
||||||
* Replace example files with testable examples
|
|
||||||
|
|
||||||
# 1.0.2
|
|
||||||
|
|
||||||
* bug: quote non-string values in text formatter (#583)
|
|
||||||
* Make (*Logger) SetLevel a public method
|
|
||||||
|
|
||||||
# 1.0.1
|
|
||||||
|
|
||||||
* bug: fix escaping in text formatter (#575)
|
|
||||||
|
|
||||||
# 1.0.0
|
|
||||||
|
|
||||||
* Officially changed name to lower-case
|
|
||||||
* bug: colors on Windows 10 (#541)
|
|
||||||
* bug: fix race in accessing level (#512)
|
|
||||||
|
|
||||||
# 0.11.5
|
|
||||||
|
|
||||||
* feature: add writer and writerlevel to entry (#372)
|
|
||||||
|
|
||||||
# 0.11.4
|
|
||||||
|
|
||||||
* bug: fix undefined variable on solaris (#493)
|
|
||||||
|
|
||||||
# 0.11.3
|
|
||||||
|
|
||||||
* formatter: configure quoting of empty values (#484)
|
|
||||||
* formatter: configure quoting character (default is `"`) (#484)
|
|
||||||
* bug: fix not importing io correctly in non-linux environments (#481)
|
|
||||||
|
|
||||||
# 0.11.2
|
|
||||||
|
|
||||||
* bug: fix windows terminal detection (#476)
|
|
||||||
|
|
||||||
# 0.11.1
|
|
||||||
|
|
||||||
* bug: fix tty detection with custom out (#471)
|
|
||||||
|
|
||||||
# 0.11.0
|
|
||||||
|
|
||||||
* performance: Use bufferpool to allocate (#370)
|
|
||||||
* terminal: terminal detection for app-engine (#343)
|
|
||||||
* feature: exit handler (#375)
|
|
||||||
|
|
||||||
# 0.10.0
|
|
||||||
|
|
||||||
* feature: Add a test hook (#180)
|
|
||||||
* feature: `ParseLevel` is now case-insensitive (#326)
|
|
||||||
* feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308)
|
|
||||||
* performance: avoid re-allocations on `WithFields` (#335)
|
|
||||||
|
|
||||||
# 0.9.0
|
|
||||||
|
|
||||||
* logrus/text_formatter: don't emit empty msg
|
|
||||||
* logrus/hooks/airbrake: move out of main repository
|
|
||||||
* logrus/hooks/sentry: move out of main repository
|
|
||||||
* logrus/hooks/papertrail: move out of main repository
|
|
||||||
* logrus/hooks/bugsnag: move out of main repository
|
|
||||||
* logrus/core: run tests with `-race`
|
|
||||||
* logrus/core: detect TTY based on `stderr`
|
|
||||||
* logrus/core: support `WithError` on logger
|
|
||||||
* logrus/core: Solaris support
|
|
||||||
|
|
||||||
# 0.8.7
|
|
||||||
|
|
||||||
* logrus/core: fix possible race (#216)
|
|
||||||
* logrus/doc: small typo fixes and doc improvements
|
|
||||||
|
|
||||||
|
|
||||||
# 0.8.6
|
|
||||||
|
|
||||||
* hooks/raven: allow passing an initialized client
|
|
||||||
|
|
||||||
# 0.8.5
|
|
||||||
|
|
||||||
* logrus/core: revert #208
|
|
||||||
|
|
||||||
# 0.8.4
|
|
||||||
|
|
||||||
* formatter/text: fix data race (#218)
|
|
||||||
|
|
||||||
# 0.8.3
|
|
||||||
|
|
||||||
* logrus/core: fix entry log level (#208)
|
|
||||||
* logrus/core: improve performance of text formatter by 40%
|
|
||||||
* logrus/core: expose `LevelHooks` type
|
|
||||||
* logrus/core: add support for DragonflyBSD and NetBSD
|
|
||||||
* formatter/text: print structs more verbosely
|
|
||||||
|
|
||||||
# 0.8.2
|
|
||||||
|
|
||||||
* logrus: fix more Fatal family functions
|
|
||||||
|
|
||||||
# 0.8.1
|
|
||||||
|
|
||||||
* logrus: fix not exiting on `Fatalf` and `Fatalln`
|
|
||||||
|
|
||||||
# 0.8.0
|
|
||||||
|
|
||||||
* logrus: defaults to stderr instead of stdout
|
|
||||||
* hooks/sentry: add special field for `*http.Request`
|
|
||||||
* formatter/text: ignore Windows for colors
|
|
||||||
|
|
||||||
# 0.7.3
|
|
||||||
|
|
||||||
* formatter/\*: allow configuration of timestamp layout
|
|
||||||
|
|
||||||
# 0.7.2
|
|
||||||
|
|
||||||
* formatter/text: Add configuration option for time format (#158)
|
|
||||||
21
vendor/github.com/sirupsen/logrus/LICENSE
generated
vendored
21
vendor/github.com/sirupsen/logrus/LICENSE
generated
vendored
@@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2014 Simon Eskildsen
|
|
||||||
|
|
||||||
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.
|
|
||||||
515
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
515
vendor/github.com/sirupsen/logrus/README.md
generated
vendored
@@ -1,515 +0,0 @@
|
|||||||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [](https://github.com/sirupsen/logrus/actions?query=workflow%3ACI) [](https://travis-ci.org/sirupsen/logrus) [](https://pkg.go.dev/github.com/sirupsen/logrus)
|
|
||||||
|
|
||||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
|
||||||
the standard library logger.
|
|
||||||
|
|
||||||
**Logrus is in maintenance-mode.** We will not be introducing new features. It's
|
|
||||||
simply too hard to do in a way that won't break many people's projects, which is
|
|
||||||
the last thing you want from your Logging library (again...).
|
|
||||||
|
|
||||||
This does not mean Logrus is dead. Logrus will continue to be maintained for
|
|
||||||
security, (backwards compatible) bug fixes, and performance (where we are
|
|
||||||
limited by the interface).
|
|
||||||
|
|
||||||
I believe Logrus' biggest contribution is to have played a part in today's
|
|
||||||
widespread use of structured logging in Golang. There doesn't seem to be a
|
|
||||||
reason to do a major, breaking iteration into Logrus V2, since the fantastic Go
|
|
||||||
community has built those independently. Many fantastic alternatives have sprung
|
|
||||||
up. Logrus would look like those, had it been re-designed with what we know
|
|
||||||
about structured logging in Go today. Check out, for example,
|
|
||||||
[Zerolog][zerolog], [Zap][zap], and [Apex][apex].
|
|
||||||
|
|
||||||
[zerolog]: https://github.com/rs/zerolog
|
|
||||||
[zap]: https://github.com/uber-go/zap
|
|
||||||
[apex]: https://github.com/apex/log
|
|
||||||
|
|
||||||
**Seeing weird case-sensitive problems?** It's in the past been possible to
|
|
||||||
import Logrus as both upper- and lower-case. Due to the Go package environment,
|
|
||||||
this caused issues in the community and we needed a standard. Some environments
|
|
||||||
experienced problems with the upper-case variant, so the lower-case was decided.
|
|
||||||
Everything using `logrus` will need to use the lower-case:
|
|
||||||
`github.com/sirupsen/logrus`. Any package that isn't, should be changed.
|
|
||||||
|
|
||||||
To fix Glide, see [these
|
|
||||||
comments](https://github.com/sirupsen/logrus/issues/553#issuecomment-306591437).
|
|
||||||
For an in-depth explanation of the casing issue, see [this
|
|
||||||
comment](https://github.com/sirupsen/logrus/issues/570#issuecomment-313933276).
|
|
||||||
|
|
||||||
Nicely color-coded in development (when a TTY is attached, otherwise just
|
|
||||||
plain text):
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash
|
|
||||||
or Splunk:
|
|
||||||
|
|
||||||
```text
|
|
||||||
{"animal":"walrus","level":"info","msg":"A group of walrus emerges from the
|
|
||||||
ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"}
|
|
||||||
|
|
||||||
{"level":"warning","msg":"The group's number increased tremendously!",
|
|
||||||
"number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"}
|
|
||||||
|
|
||||||
{"animal":"walrus","level":"info","msg":"A giant walrus appears!",
|
|
||||||
"size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"}
|
|
||||||
|
|
||||||
{"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.",
|
|
||||||
"size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"}
|
|
||||||
|
|
||||||
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,
|
|
||||||
"time":"2014-03-10 19:57:38.562543128 -0400 EDT"}
|
|
||||||
```
|
|
||||||
|
|
||||||
With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not
|
|
||||||
attached, the output is compatible with the
|
|
||||||
[logfmt](http://godoc.org/github.com/kr/logfmt) format:
|
|
||||||
|
|
||||||
```text
|
|
||||||
time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8
|
|
||||||
time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10
|
|
||||||
time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true
|
|
||||||
time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4
|
|
||||||
time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009
|
|
||||||
time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true
|
|
||||||
```
|
|
||||||
To ensure this behaviour even if a TTY is attached, set your formatter as follows:
|
|
||||||
|
|
||||||
```go
|
|
||||||
log.SetFormatter(&log.TextFormatter{
|
|
||||||
DisableColors: true,
|
|
||||||
FullTimestamp: true,
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Logging Method Name
|
|
||||||
|
|
||||||
If you wish to add the calling method as a field, instruct the logger via:
|
|
||||||
```go
|
|
||||||
log.SetReportCaller(true)
|
|
||||||
```
|
|
||||||
This adds the caller as 'method' like so:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{"animal":"penguin","level":"fatal","method":"github.com/sirupsen/arcticcreatures.migrate","msg":"a penguin swims by",
|
|
||||||
"time":"2014-03-10 19:57:38.562543129 -0400 EDT"}
|
|
||||||
```
|
|
||||||
|
|
||||||
```text
|
|
||||||
time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcreatures.migrate msg="a penguin swims by" animal=penguin
|
|
||||||
```
|
|
||||||
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
|
|
||||||
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
|
|
||||||
environment via benchmarks:
|
|
||||||
```
|
|
||||||
go test -bench=.*CallerTracing
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### Case-sensitivity
|
|
||||||
|
|
||||||
The organization's name was changed to lower-case--and this will not be changed
|
|
||||||
back. If you are getting import conflicts due to case sensitivity, please use
|
|
||||||
the lower-case import: `github.com/sirupsen/logrus`.
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
|
|
||||||
The simplest way to use Logrus is simply the package-level exported logger:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
}).Info("A walrus appears")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that it's completely api-compatible with the stdlib logger, so you can
|
|
||||||
replace your `log` imports everywhere with `log "github.com/sirupsen/logrus"`
|
|
||||||
and you'll now have the flexibility of Logrus. You can customize it all you
|
|
||||||
want:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Log as JSON instead of the default ASCII formatter.
|
|
||||||
log.SetFormatter(&log.JSONFormatter{})
|
|
||||||
|
|
||||||
// Output to stdout instead of the default stderr
|
|
||||||
// Can be any io.Writer, see below for File example
|
|
||||||
log.SetOutput(os.Stdout)
|
|
||||||
|
|
||||||
// Only log the warning severity or above.
|
|
||||||
log.SetLevel(log.WarnLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
"size": 10,
|
|
||||||
}).Info("A group of walrus emerges from the ocean")
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"omg": true,
|
|
||||||
"number": 122,
|
|
||||||
}).Warn("The group's number increased tremendously!")
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"omg": true,
|
|
||||||
"number": 100,
|
|
||||||
}).Fatal("The ice breaks!")
|
|
||||||
|
|
||||||
// A common pattern is to re-use fields between logging statements by re-using
|
|
||||||
// the logrus.Entry returned from WithFields()
|
|
||||||
contextLogger := log.WithFields(log.Fields{
|
|
||||||
"common": "this is a common field",
|
|
||||||
"other": "I also should be logged always",
|
|
||||||
})
|
|
||||||
|
|
||||||
contextLogger.Info("I'll be logged with common and other field")
|
|
||||||
contextLogger.Info("Me too")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For more advanced usage such as logging to multiple locations from the same
|
|
||||||
application, you can also create an instance of the `logrus` Logger:
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create a new instance of the logger. You can have any number of instances.
|
|
||||||
var log = logrus.New()
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// The API for setting attributes is a little different than the package level
|
|
||||||
// exported logger. See Godoc.
|
|
||||||
log.Out = os.Stdout
|
|
||||||
|
|
||||||
// You could set this to any `io.Writer` such as a file
|
|
||||||
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
||||||
// if err == nil {
|
|
||||||
// log.Out = file
|
|
||||||
// } else {
|
|
||||||
// log.Info("Failed to log to file, using default stderr")
|
|
||||||
// }
|
|
||||||
|
|
||||||
log.WithFields(logrus.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
"size": 10,
|
|
||||||
}).Info("A group of walrus emerges from the ocean")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Fields
|
|
||||||
|
|
||||||
Logrus encourages careful, structured logging through logging fields instead of
|
|
||||||
long, unparseable error messages. For example, instead of: `log.Fatalf("Failed
|
|
||||||
to send event %s to topic %s with key %d")`, you should log the much more
|
|
||||||
discoverable:
|
|
||||||
|
|
||||||
```go
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event": event,
|
|
||||||
"topic": topic,
|
|
||||||
"key": key,
|
|
||||||
}).Fatal("Failed to send event")
|
|
||||||
```
|
|
||||||
|
|
||||||
We've found this API forces you to think about logging in a way that produces
|
|
||||||
much more useful logging messages. We've been in countless situations where just
|
|
||||||
a single added field to a log statement that was already there would've saved us
|
|
||||||
hours. The `WithFields` call is optional.
|
|
||||||
|
|
||||||
In general, with Logrus using any of the `printf`-family functions should be
|
|
||||||
seen as a hint you should add a field, however, you can still use the
|
|
||||||
`printf`-family functions with Logrus.
|
|
||||||
|
|
||||||
#### Default Fields
|
|
||||||
|
|
||||||
Often it's helpful to have fields _always_ attached to log statements in an
|
|
||||||
application or parts of one. For example, you may want to always log the
|
|
||||||
`request_id` and `user_ip` in the context of a request. Instead of writing
|
|
||||||
`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on
|
|
||||||
every line, you can create a `logrus.Entry` to pass around instead:
|
|
||||||
|
|
||||||
```go
|
|
||||||
requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})
|
|
||||||
requestLogger.Info("something happened on that request") # will log request_id and user_ip
|
|
||||||
requestLogger.Warn("something not great happened")
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Hooks
|
|
||||||
|
|
||||||
You can add hooks for logging levels. For example to send errors to an exception
|
|
||||||
tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to
|
|
||||||
multiple places simultaneously, e.g. syslog.
|
|
||||||
|
|
||||||
Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
|
|
||||||
`init`:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
|
|
||||||
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
|
|
||||||
"log/syslog"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
|
|
||||||
// Use the Airbrake hook to report errors that have Error severity or above to
|
|
||||||
// an exception tracker. You can create custom hooks, see the Hooks section.
|
|
||||||
log.AddHook(airbrake.NewHook(123, "xyz", "production"))
|
|
||||||
|
|
||||||
hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Unable to connect to local syslog daemon")
|
|
||||||
} else {
|
|
||||||
log.AddHook(hook)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
|
|
||||||
|
|
||||||
A list of currently known service hooks can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
|
|
||||||
|
|
||||||
|
|
||||||
#### Level logging
|
|
||||||
|
|
||||||
Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic.
|
|
||||||
|
|
||||||
```go
|
|
||||||
log.Trace("Something very low level.")
|
|
||||||
log.Debug("Useful debugging information.")
|
|
||||||
log.Info("Something noteworthy happened!")
|
|
||||||
log.Warn("You should probably take a look at this.")
|
|
||||||
log.Error("Something failed but I'm not quitting.")
|
|
||||||
// Calls os.Exit(1) after logging
|
|
||||||
log.Fatal("Bye.")
|
|
||||||
// Calls panic() after logging
|
|
||||||
log.Panic("I'm bailing.")
|
|
||||||
```
|
|
||||||
|
|
||||||
You can set the logging level on a `Logger`, then it will only log entries with
|
|
||||||
that severity or anything above it:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Will log anything that is info or above (warn, error, fatal, panic). Default.
|
|
||||||
log.SetLevel(log.InfoLevel)
|
|
||||||
```
|
|
||||||
|
|
||||||
It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose
|
|
||||||
environment if your application has that.
|
|
||||||
|
|
||||||
Note: If you want different log levels for global (`log.SetLevel(...)`) and syslog logging, please check the [syslog hook README](hooks/syslog/README.md#different-log-levels-for-local-and-remote-logging).
|
|
||||||
|
|
||||||
#### Entries
|
|
||||||
|
|
||||||
Besides the fields added with `WithField` or `WithFields` some fields are
|
|
||||||
automatically added to all logging events:
|
|
||||||
|
|
||||||
1. `time`. The timestamp when the entry was created.
|
|
||||||
2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after
|
|
||||||
the `AddFields` call. E.g. `Failed to send event.`
|
|
||||||
3. `level`. The logging level. E.g. `info`.
|
|
||||||
|
|
||||||
#### Environments
|
|
||||||
|
|
||||||
Logrus has no notion of environment.
|
|
||||||
|
|
||||||
If you wish for hooks and formatters to only be used in specific environments,
|
|
||||||
you should handle that yourself. For example, if your application has a global
|
|
||||||
variable `Environment`, which is a string representation of the environment you
|
|
||||||
could do:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// do something here to set environment depending on an environment variable
|
|
||||||
// or command-line flag
|
|
||||||
if Environment == "production" {
|
|
||||||
log.SetFormatter(&log.JSONFormatter{})
|
|
||||||
} else {
|
|
||||||
// The TextFormatter is default, you don't actually have to do this.
|
|
||||||
log.SetFormatter(&log.TextFormatter{})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This configuration is how `logrus` was intended to be used, but JSON in
|
|
||||||
production is mostly only useful if you do log aggregation with tools like
|
|
||||||
Splunk or Logstash.
|
|
||||||
|
|
||||||
#### Formatters
|
|
||||||
|
|
||||||
The built-in logging formatters are:
|
|
||||||
|
|
||||||
* `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise
|
|
||||||
without colors.
|
|
||||||
* *Note:* to force colored output when there is no TTY, set the `ForceColors`
|
|
||||||
field to `true`. To force no colored output even if there is a TTY set the
|
|
||||||
`DisableColors` field to `true`. For Windows, see
|
|
||||||
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
|
|
||||||
* When colors are enabled, levels are truncated to 4 characters by default. To disable
|
|
||||||
truncation set the `DisableLevelTruncation` field to `true`.
|
|
||||||
* When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text.
|
|
||||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
|
|
||||||
* `logrus.JSONFormatter`. Logs fields as JSON.
|
|
||||||
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
|
|
||||||
|
|
||||||
Third party logging formatters:
|
|
||||||
|
|
||||||
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
|
|
||||||
* [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html).
|
|
||||||
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
|
|
||||||
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
|
|
||||||
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the Power of Zalgo.
|
|
||||||
* [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure.
|
|
||||||
* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Sava log to files.
|
|
||||||
* [`caption-json-formatter`](https://github.com/nolleh/caption_json_formatter). logrus's message json formatter with human-readable caption added.
|
|
||||||
|
|
||||||
You can define your formatter by implementing the `Formatter` interface,
|
|
||||||
requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a
|
|
||||||
`Fields` type (`map[string]interface{}`) with all your fields as well as the
|
|
||||||
default ones (see Entries section above):
|
|
||||||
|
|
||||||
```go
|
|
||||||
type MyJSONFormatter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
log.SetFormatter(new(MyJSONFormatter))
|
|
||||||
|
|
||||||
func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|
||||||
// Note this doesn't include Time, Level and Message which are available on
|
|
||||||
// the Entry. Consult `godoc` on information about those fields or read the
|
|
||||||
// source of the official loggers.
|
|
||||||
serialized, err := json.Marshal(entry.Data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Failed to marshal fields to JSON, %w", err)
|
|
||||||
}
|
|
||||||
return append(serialized, '\n'), nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Logger as an `io.Writer`
|
|
||||||
|
|
||||||
Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it.
|
|
||||||
|
|
||||||
```go
|
|
||||||
w := logger.Writer()
|
|
||||||
defer w.Close()
|
|
||||||
|
|
||||||
srv := http.Server{
|
|
||||||
// create a stdlib log.Logger that writes to
|
|
||||||
// logrus.Logger.
|
|
||||||
ErrorLog: log.New(w, "", 0),
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Each line written to that writer will be printed the usual way, using formatters
|
|
||||||
and hooks. The level for those entries is `info`.
|
|
||||||
|
|
||||||
This means that we can override the standard library logger easily:
|
|
||||||
|
|
||||||
```go
|
|
||||||
logger := logrus.New()
|
|
||||||
logger.Formatter = &logrus.JSONFormatter{}
|
|
||||||
|
|
||||||
// Use logrus for standard log output
|
|
||||||
// Note that `log` here references stdlib's log
|
|
||||||
// Not logrus imported under the name `log`.
|
|
||||||
log.SetOutput(logger.Writer())
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Rotation
|
|
||||||
|
|
||||||
Log rotation is not provided with Logrus. Log rotation should be done by an
|
|
||||||
external program (like `logrotate(8)`) that can compress and delete old log
|
|
||||||
entries. It should not be a feature of the application-level logger.
|
|
||||||
|
|
||||||
#### Tools
|
|
||||||
|
|
||||||
| Tool | Description |
|
|
||||||
| ---- | ----------- |
|
|
||||||
|[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will be generated with different configs in different environments.|
|
|
||||||
|[Logrus Viper Helper](https://github.com/heirko/go-contrib/tree/master/logrusHelper)|An Helper around Logrus to wrap with spf13/Viper to load configuration with fangs! And to simplify Logrus configuration use some behavior of [Logrus Mate](https://github.com/gogap/logrus_mate). [sample](https://github.com/heirko/iris-contrib/blob/master/middleware/logrus-logger/example) |
|
|
||||||
|
|
||||||
#### Testing
|
|
||||||
|
|
||||||
Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides:
|
|
||||||
|
|
||||||
* decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just adds the `test` hook
|
|
||||||
* a test logger (`test.NewNullLogger`) that just records log messages (and does not output any):
|
|
||||||
|
|
||||||
```go
|
|
||||||
import(
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/sirupsen/logrus/hooks/test"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSomething(t*testing.T){
|
|
||||||
logger, hook := test.NewNullLogger()
|
|
||||||
logger.Error("Helloerror")
|
|
||||||
|
|
||||||
assert.Equal(t, 1, len(hook.Entries))
|
|
||||||
assert.Equal(t, logrus.ErrorLevel, hook.LastEntry().Level)
|
|
||||||
assert.Equal(t, "Helloerror", hook.LastEntry().Message)
|
|
||||||
|
|
||||||
hook.Reset()
|
|
||||||
assert.Nil(t, hook.LastEntry())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Fatal handlers
|
|
||||||
|
|
||||||
Logrus can register one or more functions that will be called when any `fatal`
|
|
||||||
level message is logged. The registered handlers will be executed before
|
|
||||||
logrus performs an `os.Exit(1)`. This behavior may be helpful if callers need
|
|
||||||
to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted.
|
|
||||||
|
|
||||||
```
|
|
||||||
...
|
|
||||||
handler := func() {
|
|
||||||
// gracefully shutdown something...
|
|
||||||
}
|
|
||||||
logrus.RegisterExitHandler(handler)
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Thread safety
|
|
||||||
|
|
||||||
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
|
|
||||||
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
|
|
||||||
|
|
||||||
Situation when locking is not needed includes:
|
|
||||||
|
|
||||||
* You have no hooks registered, or hooks calling is already thread-safe.
|
|
||||||
|
|
||||||
* Writing to logger.Out is already thread-safe, for example:
|
|
||||||
|
|
||||||
1) logger.Out is protected by locks.
|
|
||||||
|
|
||||||
2) logger.Out is an os.File handler opened with `O_APPEND` flag, and every write is smaller than 4k. (This allows multi-thread/multi-process writing)
|
|
||||||
|
|
||||||
(Refer to http://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/)
|
|
||||||
76
vendor/github.com/sirupsen/logrus/alt_exit.go
generated
vendored
76
vendor/github.com/sirupsen/logrus/alt_exit.go
generated
vendored
@@ -1,76 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
// The following code was sourced and modified from the
|
|
||||||
// https://github.com/tebeka/atexit package governed by the following license:
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012 Miki Tebeka <miki.tebeka@gmail.com>.
|
|
||||||
//
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
var handlers = []func(){}
|
|
||||||
|
|
||||||
func runHandler(handler func()) {
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "Error: Logrus exit handler error:", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
handler()
|
|
||||||
}
|
|
||||||
|
|
||||||
func runHandlers() {
|
|
||||||
for _, handler := range handlers {
|
|
||||||
runHandler(handler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit runs all the Logrus atexit handlers and then terminates the program using os.Exit(code)
|
|
||||||
func Exit(code int) {
|
|
||||||
runHandlers()
|
|
||||||
os.Exit(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterExitHandler appends a Logrus Exit handler to the list of handlers,
|
|
||||||
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
|
|
||||||
// any Fatal log entry is made.
|
|
||||||
//
|
|
||||||
// This method is useful when a caller wishes to use logrus to log a fatal
|
|
||||||
// message but also needs to gracefully shutdown. An example usecase could be
|
|
||||||
// closing database connections, or sending a alert that the application is
|
|
||||||
// closing.
|
|
||||||
func RegisterExitHandler(handler func()) {
|
|
||||||
handlers = append(handlers, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeferExitHandler prepends a Logrus Exit handler to the list of handlers,
|
|
||||||
// call logrus.Exit to invoke all handlers. The handlers will also be invoked when
|
|
||||||
// any Fatal log entry is made.
|
|
||||||
//
|
|
||||||
// This method is useful when a caller wishes to use logrus to log a fatal
|
|
||||||
// message but also needs to gracefully shutdown. An example usecase could be
|
|
||||||
// closing database connections, or sending a alert that the application is
|
|
||||||
// closing.
|
|
||||||
func DeferExitHandler(handler func()) {
|
|
||||||
handlers = append([]func(){handler}, handlers...)
|
|
||||||
}
|
|
||||||
14
vendor/github.com/sirupsen/logrus/appveyor.yml
generated
vendored
14
vendor/github.com/sirupsen/logrus/appveyor.yml
generated
vendored
@@ -1,14 +0,0 @@
|
|||||||
version: "{build}"
|
|
||||||
platform: x64
|
|
||||||
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
|
|
||||||
environment:
|
|
||||||
GOPATH: c:\gopath
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
install:
|
|
||||||
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
|
|
||||||
- go version
|
|
||||||
build_script:
|
|
||||||
- go get -t
|
|
||||||
- go test
|
|
||||||
43
vendor/github.com/sirupsen/logrus/buffer_pool.go
generated
vendored
43
vendor/github.com/sirupsen/logrus/buffer_pool.go
generated
vendored
@@ -1,43 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
bufferPool BufferPool
|
|
||||||
)
|
|
||||||
|
|
||||||
type BufferPool interface {
|
|
||||||
Put(*bytes.Buffer)
|
|
||||||
Get() *bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
type defaultPool struct {
|
|
||||||
pool *sync.Pool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *defaultPool) Put(buf *bytes.Buffer) {
|
|
||||||
p.pool.Put(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *defaultPool) Get() *bytes.Buffer {
|
|
||||||
return p.pool.Get().(*bytes.Buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBufferPool allows to replace the default logrus buffer pool
|
|
||||||
// to better meets the specific needs of an application.
|
|
||||||
func SetBufferPool(bp BufferPool) {
|
|
||||||
bufferPool = bp
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
SetBufferPool(&defaultPool{
|
|
||||||
pool: &sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return new(bytes.Buffer)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
26
vendor/github.com/sirupsen/logrus/doc.go
generated
vendored
26
vendor/github.com/sirupsen/logrus/doc.go
generated
vendored
@@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
Package logrus is a structured logger for Go, completely API compatible with the standard library logger.
|
|
||||||
|
|
||||||
|
|
||||||
The simplest way to use Logrus is simply the package-level exported logger:
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"animal": "walrus",
|
|
||||||
"number": 1,
|
|
||||||
"size": 10,
|
|
||||||
}).Info("A walrus appears")
|
|
||||||
}
|
|
||||||
|
|
||||||
Output:
|
|
||||||
time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10
|
|
||||||
|
|
||||||
For a full guide visit https://github.com/sirupsen/logrus
|
|
||||||
*/
|
|
||||||
package logrus
|
|
||||||
442
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
442
vendor/github.com/sirupsen/logrus/entry.go
generated
vendored
@@ -1,442 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
|
|
||||||
// qualified package name, cached at first use
|
|
||||||
logrusPackage string
|
|
||||||
|
|
||||||
// Positions in the call stack when tracing to report the calling method
|
|
||||||
minimumCallerDepth int
|
|
||||||
|
|
||||||
// Used for caller information initialisation
|
|
||||||
callerInitOnce sync.Once
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
maximumCallerDepth int = 25
|
|
||||||
knownLogrusFrames int = 4
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// start at the bottom of the stack before the package-name cache is primed
|
|
||||||
minimumCallerDepth = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defines the key when adding errors using WithError.
|
|
||||||
var ErrorKey = "error"
|
|
||||||
|
|
||||||
// An entry is the final or intermediate Logrus logging entry. It contains all
|
|
||||||
// the fields passed with WithField{,s}. It's finally logged when Trace, Debug,
|
|
||||||
// Info, Warn, Error, Fatal or Panic is called on it. These objects can be
|
|
||||||
// reused and passed around as much as you wish to avoid field duplication.
|
|
||||||
type Entry struct {
|
|
||||||
Logger *Logger
|
|
||||||
|
|
||||||
// Contains all the fields set by the user.
|
|
||||||
Data Fields
|
|
||||||
|
|
||||||
// Time at which the log entry was created
|
|
||||||
Time time.Time
|
|
||||||
|
|
||||||
// Level the log entry was logged at: Trace, Debug, Info, Warn, Error, Fatal or Panic
|
|
||||||
// This field will be set on entry firing and the value will be equal to the one in Logger struct field.
|
|
||||||
Level Level
|
|
||||||
|
|
||||||
// Calling method, with package name
|
|
||||||
Caller *runtime.Frame
|
|
||||||
|
|
||||||
// Message passed to Trace, Debug, Info, Warn, Error, Fatal or Panic
|
|
||||||
Message string
|
|
||||||
|
|
||||||
// When formatter is called in entry.log(), a Buffer may be set to entry
|
|
||||||
Buffer *bytes.Buffer
|
|
||||||
|
|
||||||
// Contains the context set by the user. Useful for hook processing etc.
|
|
||||||
Context context.Context
|
|
||||||
|
|
||||||
// err may contain a field formatting error
|
|
||||||
err string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEntry(logger *Logger) *Entry {
|
|
||||||
return &Entry{
|
|
||||||
Logger: logger,
|
|
||||||
// Default is three fields, plus one optional. Give a little extra room.
|
|
||||||
Data: make(Fields, 6),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Dup() *Entry {
|
|
||||||
data := make(Fields, len(entry.Data))
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, Context: entry.Context, err: entry.err}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the bytes representation of this entry from the formatter.
|
|
||||||
func (entry *Entry) Bytes() ([]byte, error) {
|
|
||||||
return entry.Logger.Formatter.Format(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the string representation from the reader and ultimately the
|
|
||||||
// formatter.
|
|
||||||
func (entry *Entry) String() (string, error) {
|
|
||||||
serialized, err := entry.Bytes()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
str := string(serialized)
|
|
||||||
return str, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an error as single field (using the key defined in ErrorKey) to the Entry.
|
|
||||||
func (entry *Entry) WithError(err error) *Entry {
|
|
||||||
return entry.WithField(ErrorKey, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a context to the Entry.
|
|
||||||
func (entry *Entry) WithContext(ctx context.Context) *Entry {
|
|
||||||
dataCopy := make(Fields, len(entry.Data))
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
dataCopy[k] = v
|
|
||||||
}
|
|
||||||
return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a single field to the Entry.
|
|
||||||
func (entry *Entry) WithField(key string, value interface{}) *Entry {
|
|
||||||
return entry.WithFields(Fields{key: value})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a map of fields to the Entry.
|
|
||||||
func (entry *Entry) WithFields(fields Fields) *Entry {
|
|
||||||
data := make(Fields, len(entry.Data)+len(fields))
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
fieldErr := entry.err
|
|
||||||
for k, v := range fields {
|
|
||||||
isErrField := false
|
|
||||||
if t := reflect.TypeOf(v); t != nil {
|
|
||||||
switch {
|
|
||||||
case t.Kind() == reflect.Func, t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Func:
|
|
||||||
isErrField = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isErrField {
|
|
||||||
tmp := fmt.Sprintf("can not add field %q", k)
|
|
||||||
if fieldErr != "" {
|
|
||||||
fieldErr = entry.err + ", " + tmp
|
|
||||||
} else {
|
|
||||||
fieldErr = tmp
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overrides the time of the Entry.
|
|
||||||
func (entry *Entry) WithTime(t time.Time) *Entry {
|
|
||||||
dataCopy := make(Fields, len(entry.Data))
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
dataCopy[k] = v
|
|
||||||
}
|
|
||||||
return &Entry{Logger: entry.Logger, Data: dataCopy, Time: t, err: entry.err, Context: entry.Context}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPackageName reduces a fully qualified function name to the package name
|
|
||||||
// There really ought to be to be a better way...
|
|
||||||
func getPackageName(f string) string {
|
|
||||||
for {
|
|
||||||
lastPeriod := strings.LastIndex(f, ".")
|
|
||||||
lastSlash := strings.LastIndex(f, "/")
|
|
||||||
if lastPeriod > lastSlash {
|
|
||||||
f = f[:lastPeriod]
|
|
||||||
} else {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCaller retrieves the name of the first non-logrus calling function
|
|
||||||
func getCaller() *runtime.Frame {
|
|
||||||
// cache this package's fully-qualified name
|
|
||||||
callerInitOnce.Do(func() {
|
|
||||||
pcs := make([]uintptr, maximumCallerDepth)
|
|
||||||
_ = runtime.Callers(0, pcs)
|
|
||||||
|
|
||||||
// dynamic get the package name and the minimum caller depth
|
|
||||||
for i := 0; i < maximumCallerDepth; i++ {
|
|
||||||
funcName := runtime.FuncForPC(pcs[i]).Name()
|
|
||||||
if strings.Contains(funcName, "getCaller") {
|
|
||||||
logrusPackage = getPackageName(funcName)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
minimumCallerDepth = knownLogrusFrames
|
|
||||||
})
|
|
||||||
|
|
||||||
// Restrict the lookback frames to avoid runaway lookups
|
|
||||||
pcs := make([]uintptr, maximumCallerDepth)
|
|
||||||
depth := runtime.Callers(minimumCallerDepth, pcs)
|
|
||||||
frames := runtime.CallersFrames(pcs[:depth])
|
|
||||||
|
|
||||||
for f, again := frames.Next(); again; f, again = frames.Next() {
|
|
||||||
pkg := getPackageName(f.Function)
|
|
||||||
|
|
||||||
// If the caller isn't part of this package, we're done
|
|
||||||
if pkg != logrusPackage {
|
|
||||||
return &f //nolint:scopelint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we got here, we failed to find the caller's context
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry Entry) HasCaller() (has bool) {
|
|
||||||
return entry.Logger != nil &&
|
|
||||||
entry.Logger.ReportCaller &&
|
|
||||||
entry.Caller != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) log(level Level, msg string) {
|
|
||||||
var buffer *bytes.Buffer
|
|
||||||
|
|
||||||
newEntry := entry.Dup()
|
|
||||||
|
|
||||||
if newEntry.Time.IsZero() {
|
|
||||||
newEntry.Time = time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
newEntry.Level = level
|
|
||||||
newEntry.Message = msg
|
|
||||||
|
|
||||||
newEntry.Logger.mu.Lock()
|
|
||||||
reportCaller := newEntry.Logger.ReportCaller
|
|
||||||
bufPool := newEntry.getBufferPool()
|
|
||||||
newEntry.Logger.mu.Unlock()
|
|
||||||
|
|
||||||
if reportCaller {
|
|
||||||
newEntry.Caller = getCaller()
|
|
||||||
}
|
|
||||||
|
|
||||||
newEntry.fireHooks()
|
|
||||||
buffer = bufPool.Get()
|
|
||||||
defer func() {
|
|
||||||
newEntry.Buffer = nil
|
|
||||||
buffer.Reset()
|
|
||||||
bufPool.Put(buffer)
|
|
||||||
}()
|
|
||||||
buffer.Reset()
|
|
||||||
newEntry.Buffer = buffer
|
|
||||||
|
|
||||||
newEntry.write()
|
|
||||||
|
|
||||||
newEntry.Buffer = nil
|
|
||||||
|
|
||||||
// To avoid Entry#log() returning a value that only would make sense for
|
|
||||||
// panic() to use in Entry#Panic(), we avoid the allocation by checking
|
|
||||||
// directly here.
|
|
||||||
if level <= PanicLevel {
|
|
||||||
panic(newEntry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) getBufferPool() (pool BufferPool) {
|
|
||||||
if entry.Logger.BufferPool != nil {
|
|
||||||
return entry.Logger.BufferPool
|
|
||||||
}
|
|
||||||
return bufferPool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) fireHooks() {
|
|
||||||
var tmpHooks LevelHooks
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
tmpHooks = make(LevelHooks, len(entry.Logger.Hooks))
|
|
||||||
for k, v := range entry.Logger.Hooks {
|
|
||||||
tmpHooks[k] = v
|
|
||||||
}
|
|
||||||
entry.Logger.mu.Unlock()
|
|
||||||
|
|
||||||
err := tmpHooks.Fire(entry.Level, entry)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) write() {
|
|
||||||
entry.Logger.mu.Lock()
|
|
||||||
defer entry.Logger.mu.Unlock()
|
|
||||||
serialized, err := entry.Logger.Formatter.Format(entry)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := entry.Logger.Out.Write(serialized); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log will log a message at the level given as parameter.
|
|
||||||
// Warning: using Log at Panic or Fatal level will not respectively Panic nor Exit.
|
|
||||||
// For this behaviour Entry.Panic or Entry.Fatal should be used instead.
|
|
||||||
func (entry *Entry) Log(level Level, args ...interface{}) {
|
|
||||||
if entry.Logger.IsLevelEnabled(level) {
|
|
||||||
entry.log(level, fmt.Sprint(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Trace(args ...interface{}) {
|
|
||||||
entry.Log(TraceLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Debug(args ...interface{}) {
|
|
||||||
entry.Log(DebugLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Print(args ...interface{}) {
|
|
||||||
entry.Info(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Info(args ...interface{}) {
|
|
||||||
entry.Log(InfoLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warn(args ...interface{}) {
|
|
||||||
entry.Log(WarnLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warning(args ...interface{}) {
|
|
||||||
entry.Warn(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Error(args ...interface{}) {
|
|
||||||
entry.Log(ErrorLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Fatal(args ...interface{}) {
|
|
||||||
entry.Log(FatalLevel, args...)
|
|
||||||
entry.Logger.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Panic(args ...interface{}) {
|
|
||||||
entry.Log(PanicLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry Printf family functions
|
|
||||||
|
|
||||||
func (entry *Entry) Logf(level Level, format string, args ...interface{}) {
|
|
||||||
if entry.Logger.IsLevelEnabled(level) {
|
|
||||||
entry.Log(level, fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Tracef(format string, args ...interface{}) {
|
|
||||||
entry.Logf(TraceLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Debugf(format string, args ...interface{}) {
|
|
||||||
entry.Logf(DebugLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Infof(format string, args ...interface{}) {
|
|
||||||
entry.Logf(InfoLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Printf(format string, args ...interface{}) {
|
|
||||||
entry.Infof(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warnf(format string, args ...interface{}) {
|
|
||||||
entry.Logf(WarnLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warningf(format string, args ...interface{}) {
|
|
||||||
entry.Warnf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Errorf(format string, args ...interface{}) {
|
|
||||||
entry.Logf(ErrorLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Fatalf(format string, args ...interface{}) {
|
|
||||||
entry.Logf(FatalLevel, format, args...)
|
|
||||||
entry.Logger.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Panicf(format string, args ...interface{}) {
|
|
||||||
entry.Logf(PanicLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry Println family functions
|
|
||||||
|
|
||||||
func (entry *Entry) Logln(level Level, args ...interface{}) {
|
|
||||||
if entry.Logger.IsLevelEnabled(level) {
|
|
||||||
entry.Log(level, entry.sprintlnn(args...))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Traceln(args ...interface{}) {
|
|
||||||
entry.Logln(TraceLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Debugln(args ...interface{}) {
|
|
||||||
entry.Logln(DebugLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Infoln(args ...interface{}) {
|
|
||||||
entry.Logln(InfoLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Println(args ...interface{}) {
|
|
||||||
entry.Infoln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warnln(args ...interface{}) {
|
|
||||||
entry.Logln(WarnLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Warningln(args ...interface{}) {
|
|
||||||
entry.Warnln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Errorln(args ...interface{}) {
|
|
||||||
entry.Logln(ErrorLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Fatalln(args ...interface{}) {
|
|
||||||
entry.Logln(FatalLevel, args...)
|
|
||||||
entry.Logger.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (entry *Entry) Panicln(args ...interface{}) {
|
|
||||||
entry.Logln(PanicLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sprintlnn => Sprint no newline. This is to get the behavior of how
|
|
||||||
// fmt.Sprintln where spaces are always added between operands, regardless of
|
|
||||||
// their type. Instead of vendoring the Sprintln implementation to spare a
|
|
||||||
// string allocation, we do the simplest thing.
|
|
||||||
func (entry *Entry) sprintlnn(args ...interface{}) string {
|
|
||||||
msg := fmt.Sprintln(args...)
|
|
||||||
return msg[:len(msg)-1]
|
|
||||||
}
|
|
||||||
270
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
270
vendor/github.com/sirupsen/logrus/exported.go
generated
vendored
@@ -1,270 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// std is the name of the standard logger in stdlib `log`
|
|
||||||
std = New()
|
|
||||||
)
|
|
||||||
|
|
||||||
func StandardLogger() *Logger {
|
|
||||||
return std
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOutput sets the standard logger output.
|
|
||||||
func SetOutput(out io.Writer) {
|
|
||||||
std.SetOutput(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFormatter sets the standard logger formatter.
|
|
||||||
func SetFormatter(formatter Formatter) {
|
|
||||||
std.SetFormatter(formatter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetReportCaller sets whether the standard logger will include the calling
|
|
||||||
// method as a field.
|
|
||||||
func SetReportCaller(include bool) {
|
|
||||||
std.SetReportCaller(include)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetLevel sets the standard logger level.
|
|
||||||
func SetLevel(level Level) {
|
|
||||||
std.SetLevel(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLevel returns the standard logger level.
|
|
||||||
func GetLevel() Level {
|
|
||||||
return std.GetLevel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsLevelEnabled checks if the log level of the standard logger is greater than the level param
|
|
||||||
func IsLevelEnabled(level Level) bool {
|
|
||||||
return std.IsLevelEnabled(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHook adds a hook to the standard logger hooks.
|
|
||||||
func AddHook(hook Hook) {
|
|
||||||
std.AddHook(hook)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key.
|
|
||||||
func WithError(err error) *Entry {
|
|
||||||
return std.WithField(ErrorKey, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithContext creates an entry from the standard logger and adds a context to it.
|
|
||||||
func WithContext(ctx context.Context) *Entry {
|
|
||||||
return std.WithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithField creates an entry from the standard logger and adds a field to
|
|
||||||
// it. If you want multiple fields, use `WithFields`.
|
|
||||||
//
|
|
||||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
|
||||||
// or Panic on the Entry it returns.
|
|
||||||
func WithField(key string, value interface{}) *Entry {
|
|
||||||
return std.WithField(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithFields creates an entry from the standard logger and adds multiple
|
|
||||||
// fields to it. This is simply a helper for `WithField`, invoking it
|
|
||||||
// once for each field.
|
|
||||||
//
|
|
||||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
|
||||||
// or Panic on the Entry it returns.
|
|
||||||
func WithFields(fields Fields) *Entry {
|
|
||||||
return std.WithFields(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithTime creates an entry from the standard logger and overrides the time of
|
|
||||||
// logs generated with it.
|
|
||||||
//
|
|
||||||
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
|
|
||||||
// or Panic on the Entry it returns.
|
|
||||||
func WithTime(t time.Time) *Entry {
|
|
||||||
return std.WithTime(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trace logs a message at level Trace on the standard logger.
|
|
||||||
func Trace(args ...interface{}) {
|
|
||||||
std.Trace(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug logs a message at level Debug on the standard logger.
|
|
||||||
func Debug(args ...interface{}) {
|
|
||||||
std.Debug(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print logs a message at level Info on the standard logger.
|
|
||||||
func Print(args ...interface{}) {
|
|
||||||
std.Print(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info logs a message at level Info on the standard logger.
|
|
||||||
func Info(args ...interface{}) {
|
|
||||||
std.Info(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warn logs a message at level Warn on the standard logger.
|
|
||||||
func Warn(args ...interface{}) {
|
|
||||||
std.Warn(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warning logs a message at level Warn on the standard logger.
|
|
||||||
func Warning(args ...interface{}) {
|
|
||||||
std.Warning(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error logs a message at level Error on the standard logger.
|
|
||||||
func Error(args ...interface{}) {
|
|
||||||
std.Error(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panic logs a message at level Panic on the standard logger.
|
|
||||||
func Panic(args ...interface{}) {
|
|
||||||
std.Panic(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
|
||||||
func Fatal(args ...interface{}) {
|
|
||||||
std.Fatal(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TraceFn logs a message from a func at level Trace on the standard logger.
|
|
||||||
func TraceFn(fn LogFunction) {
|
|
||||||
std.TraceFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DebugFn logs a message from a func at level Debug on the standard logger.
|
|
||||||
func DebugFn(fn LogFunction) {
|
|
||||||
std.DebugFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrintFn logs a message from a func at level Info on the standard logger.
|
|
||||||
func PrintFn(fn LogFunction) {
|
|
||||||
std.PrintFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InfoFn logs a message from a func at level Info on the standard logger.
|
|
||||||
func InfoFn(fn LogFunction) {
|
|
||||||
std.InfoFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WarnFn logs a message from a func at level Warn on the standard logger.
|
|
||||||
func WarnFn(fn LogFunction) {
|
|
||||||
std.WarnFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WarningFn logs a message from a func at level Warn on the standard logger.
|
|
||||||
func WarningFn(fn LogFunction) {
|
|
||||||
std.WarningFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorFn logs a message from a func at level Error on the standard logger.
|
|
||||||
func ErrorFn(fn LogFunction) {
|
|
||||||
std.ErrorFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PanicFn logs a message from a func at level Panic on the standard logger.
|
|
||||||
func PanicFn(fn LogFunction) {
|
|
||||||
std.PanicFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FatalFn logs a message from a func at level Fatal on the standard logger then the process will exit with status set to 1.
|
|
||||||
func FatalFn(fn LogFunction) {
|
|
||||||
std.FatalFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tracef logs a message at level Trace on the standard logger.
|
|
||||||
func Tracef(format string, args ...interface{}) {
|
|
||||||
std.Tracef(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debugf logs a message at level Debug on the standard logger.
|
|
||||||
func Debugf(format string, args ...interface{}) {
|
|
||||||
std.Debugf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Printf logs a message at level Info on the standard logger.
|
|
||||||
func Printf(format string, args ...interface{}) {
|
|
||||||
std.Printf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infof logs a message at level Info on the standard logger.
|
|
||||||
func Infof(format string, args ...interface{}) {
|
|
||||||
std.Infof(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warnf logs a message at level Warn on the standard logger.
|
|
||||||
func Warnf(format string, args ...interface{}) {
|
|
||||||
std.Warnf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warningf logs a message at level Warn on the standard logger.
|
|
||||||
func Warningf(format string, args ...interface{}) {
|
|
||||||
std.Warningf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf logs a message at level Error on the standard logger.
|
|
||||||
func Errorf(format string, args ...interface{}) {
|
|
||||||
std.Errorf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panicf logs a message at level Panic on the standard logger.
|
|
||||||
func Panicf(format string, args ...interface{}) {
|
|
||||||
std.Panicf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
|
||||||
func Fatalf(format string, args ...interface{}) {
|
|
||||||
std.Fatalf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Traceln logs a message at level Trace on the standard logger.
|
|
||||||
func Traceln(args ...interface{}) {
|
|
||||||
std.Traceln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debugln logs a message at level Debug on the standard logger.
|
|
||||||
func Debugln(args ...interface{}) {
|
|
||||||
std.Debugln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Println logs a message at level Info on the standard logger.
|
|
||||||
func Println(args ...interface{}) {
|
|
||||||
std.Println(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Infoln logs a message at level Info on the standard logger.
|
|
||||||
func Infoln(args ...interface{}) {
|
|
||||||
std.Infoln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warnln logs a message at level Warn on the standard logger.
|
|
||||||
func Warnln(args ...interface{}) {
|
|
||||||
std.Warnln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warningln logs a message at level Warn on the standard logger.
|
|
||||||
func Warningln(args ...interface{}) {
|
|
||||||
std.Warningln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorln logs a message at level Error on the standard logger.
|
|
||||||
func Errorln(args ...interface{}) {
|
|
||||||
std.Errorln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panicln logs a message at level Panic on the standard logger.
|
|
||||||
func Panicln(args ...interface{}) {
|
|
||||||
std.Panicln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
|
|
||||||
func Fatalln(args ...interface{}) {
|
|
||||||
std.Fatalln(args...)
|
|
||||||
}
|
|
||||||
78
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
78
vendor/github.com/sirupsen/logrus/formatter.go
generated
vendored
@@ -1,78 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// Default key names for the default fields
|
|
||||||
const (
|
|
||||||
defaultTimestampFormat = time.RFC3339
|
|
||||||
FieldKeyMsg = "msg"
|
|
||||||
FieldKeyLevel = "level"
|
|
||||||
FieldKeyTime = "time"
|
|
||||||
FieldKeyLogrusError = "logrus_error"
|
|
||||||
FieldKeyFunc = "func"
|
|
||||||
FieldKeyFile = "file"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
|
||||||
// `Entry`. It exposes all the fields, including the default ones:
|
|
||||||
//
|
|
||||||
// * `entry.Data["msg"]`. The message passed from Info, Warn, Error ..
|
|
||||||
// * `entry.Data["time"]`. The timestamp.
|
|
||||||
// * `entry.Data["level"]. The level the entry was logged at.
|
|
||||||
//
|
|
||||||
// Any additional fields added with `WithField` or `WithFields` are also in
|
|
||||||
// `entry.Data`. Format is expected to return an array of bytes which are then
|
|
||||||
// logged to `logger.Out`.
|
|
||||||
type Formatter interface {
|
|
||||||
Format(*Entry) ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is to not silently overwrite `time`, `msg`, `func` and `level` fields when
|
|
||||||
// dumping it. If this code wasn't there doing:
|
|
||||||
//
|
|
||||||
// logrus.WithField("level", 1).Info("hello")
|
|
||||||
//
|
|
||||||
// Would just silently drop the user provided level. Instead with this code
|
|
||||||
// it'll logged as:
|
|
||||||
//
|
|
||||||
// {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
|
|
||||||
//
|
|
||||||
// It's not exported because it's still using Data in an opinionated way. It's to
|
|
||||||
// avoid code duplication between the two default formatters.
|
|
||||||
func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) {
|
|
||||||
timeKey := fieldMap.resolve(FieldKeyTime)
|
|
||||||
if t, ok := data[timeKey]; ok {
|
|
||||||
data["fields."+timeKey] = t
|
|
||||||
delete(data, timeKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
msgKey := fieldMap.resolve(FieldKeyMsg)
|
|
||||||
if m, ok := data[msgKey]; ok {
|
|
||||||
data["fields."+msgKey] = m
|
|
||||||
delete(data, msgKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
levelKey := fieldMap.resolve(FieldKeyLevel)
|
|
||||||
if l, ok := data[levelKey]; ok {
|
|
||||||
data["fields."+levelKey] = l
|
|
||||||
delete(data, levelKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
logrusErrKey := fieldMap.resolve(FieldKeyLogrusError)
|
|
||||||
if l, ok := data[logrusErrKey]; ok {
|
|
||||||
data["fields."+logrusErrKey] = l
|
|
||||||
delete(data, logrusErrKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If reportCaller is not set, 'func' will not conflict.
|
|
||||||
if reportCaller {
|
|
||||||
funcKey := fieldMap.resolve(FieldKeyFunc)
|
|
||||||
if l, ok := data[funcKey]; ok {
|
|
||||||
data["fields."+funcKey] = l
|
|
||||||
}
|
|
||||||
fileKey := fieldMap.resolve(FieldKeyFile)
|
|
||||||
if l, ok := data[fileKey]; ok {
|
|
||||||
data["fields."+fileKey] = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
34
vendor/github.com/sirupsen/logrus/hooks.go
generated
vendored
34
vendor/github.com/sirupsen/logrus/hooks.go
generated
vendored
@@ -1,34 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
// A hook to be fired when logging on the logging levels returned from
|
|
||||||
// `Levels()` on your implementation of the interface. Note that this is not
|
|
||||||
// fired in a goroutine or a channel with workers, you should handle such
|
|
||||||
// functionality yourself if your call is non-blocking and you don't wish for
|
|
||||||
// the logging calls for levels returned from `Levels()` to block.
|
|
||||||
type Hook interface {
|
|
||||||
Levels() []Level
|
|
||||||
Fire(*Entry) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal type for storing the hooks on a logger instance.
|
|
||||||
type LevelHooks map[Level][]Hook
|
|
||||||
|
|
||||||
// Add a hook to an instance of logger. This is called with
|
|
||||||
// `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface.
|
|
||||||
func (hooks LevelHooks) Add(hook Hook) {
|
|
||||||
for _, level := range hook.Levels() {
|
|
||||||
hooks[level] = append(hooks[level], hook)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire all the hooks for the passed level. Used by `entry.log` to fire
|
|
||||||
// appropriate hooks for a log entry.
|
|
||||||
func (hooks LevelHooks) Fire(level Level, entry *Entry) error {
|
|
||||||
for _, hook := range hooks[level] {
|
|
||||||
if err := hook.Fire(entry); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
128
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
128
vendor/github.com/sirupsen/logrus/json_formatter.go
generated
vendored
@@ -1,128 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
type fieldKey string
|
|
||||||
|
|
||||||
// FieldMap allows customization of the key names for default fields.
|
|
||||||
type FieldMap map[fieldKey]string
|
|
||||||
|
|
||||||
func (f FieldMap) resolve(key fieldKey) string {
|
|
||||||
if k, ok := f[key]; ok {
|
|
||||||
return k
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONFormatter formats logs into parsable json
|
|
||||||
type JSONFormatter struct {
|
|
||||||
// TimestampFormat sets the format used for marshaling timestamps.
|
|
||||||
// The format to use is the same than for time.Format or time.Parse from the standard
|
|
||||||
// library.
|
|
||||||
// The standard Library already provides a set of predefined format.
|
|
||||||
TimestampFormat string
|
|
||||||
|
|
||||||
// DisableTimestamp allows disabling automatic timestamps in output
|
|
||||||
DisableTimestamp bool
|
|
||||||
|
|
||||||
// DisableHTMLEscape allows disabling html escaping in output
|
|
||||||
DisableHTMLEscape bool
|
|
||||||
|
|
||||||
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
|
|
||||||
DataKey string
|
|
||||||
|
|
||||||
// FieldMap allows users to customize the names of keys for default fields.
|
|
||||||
// As an example:
|
|
||||||
// formatter := &JSONFormatter{
|
|
||||||
// FieldMap: FieldMap{
|
|
||||||
// FieldKeyTime: "@timestamp",
|
|
||||||
// FieldKeyLevel: "@level",
|
|
||||||
// FieldKeyMsg: "@message",
|
|
||||||
// FieldKeyFunc: "@caller",
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
FieldMap FieldMap
|
|
||||||
|
|
||||||
// CallerPrettyfier can be set by the user to modify the content
|
|
||||||
// of the function and file keys in the json data when ReportCaller is
|
|
||||||
// activated. If any of the returned value is the empty string the
|
|
||||||
// corresponding key will be removed from json fields.
|
|
||||||
CallerPrettyfier func(*runtime.Frame) (function string, file string)
|
|
||||||
|
|
||||||
// PrettyPrint will indent all json logs
|
|
||||||
PrettyPrint bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format renders a single log entry
|
|
||||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|
||||||
data := make(Fields, len(entry.Data)+4)
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case error:
|
|
||||||
// Otherwise errors are ignored by `encoding/json`
|
|
||||||
// https://github.com/sirupsen/logrus/issues/137
|
|
||||||
data[k] = v.Error()
|
|
||||||
default:
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.DataKey != "" {
|
|
||||||
newData := make(Fields, 4)
|
|
||||||
newData[f.DataKey] = data
|
|
||||||
data = newData
|
|
||||||
}
|
|
||||||
|
|
||||||
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
|
||||||
if timestampFormat == "" {
|
|
||||||
timestampFormat = defaultTimestampFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
if entry.err != "" {
|
|
||||||
data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err
|
|
||||||
}
|
|
||||||
if !f.DisableTimestamp {
|
|
||||||
data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)
|
|
||||||
}
|
|
||||||
data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message
|
|
||||||
data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()
|
|
||||||
if entry.HasCaller() {
|
|
||||||
funcVal := entry.Caller.Function
|
|
||||||
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
|
||||||
if f.CallerPrettyfier != nil {
|
|
||||||
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
|
||||||
}
|
|
||||||
if funcVal != "" {
|
|
||||||
data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal
|
|
||||||
}
|
|
||||||
if fileVal != "" {
|
|
||||||
data[f.FieldMap.resolve(FieldKeyFile)] = fileVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var b *bytes.Buffer
|
|
||||||
if entry.Buffer != nil {
|
|
||||||
b = entry.Buffer
|
|
||||||
} else {
|
|
||||||
b = &bytes.Buffer{}
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder := json.NewEncoder(b)
|
|
||||||
encoder.SetEscapeHTML(!f.DisableHTMLEscape)
|
|
||||||
if f.PrettyPrint {
|
|
||||||
encoder.SetIndent("", " ")
|
|
||||||
}
|
|
||||||
if err := encoder.Encode(data); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to marshal fields to JSON, %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.Bytes(), nil
|
|
||||||
}
|
|
||||||
417
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
417
vendor/github.com/sirupsen/logrus/logger.go
generated
vendored
@@ -1,417 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LogFunction For big messages, it can be more efficient to pass a function
|
|
||||||
// and only call it if the log level is actually enables rather than
|
|
||||||
// generating the log message and then checking if the level is enabled
|
|
||||||
type LogFunction func() []interface{}
|
|
||||||
|
|
||||||
type Logger struct {
|
|
||||||
// The logs are `io.Copy`'d to this in a mutex. It's common to set this to a
|
|
||||||
// file, or leave it default which is `os.Stderr`. You can also set this to
|
|
||||||
// something more adventurous, such as logging to Kafka.
|
|
||||||
Out io.Writer
|
|
||||||
// Hooks for the logger instance. These allow firing events based on logging
|
|
||||||
// levels and log entries. For example, to send errors to an error tracking
|
|
||||||
// service, log to StatsD or dump the core on fatal errors.
|
|
||||||
Hooks LevelHooks
|
|
||||||
// All log entries pass through the formatter before logged to Out. The
|
|
||||||
// included formatters are `TextFormatter` and `JSONFormatter` for which
|
|
||||||
// TextFormatter is the default. In development (when a TTY is attached) it
|
|
||||||
// logs with colors, but to a file it wouldn't. You can easily implement your
|
|
||||||
// own that implements the `Formatter` interface, see the `README` or included
|
|
||||||
// formatters for examples.
|
|
||||||
Formatter Formatter
|
|
||||||
|
|
||||||
// Flag for whether to log caller info (off by default)
|
|
||||||
ReportCaller bool
|
|
||||||
|
|
||||||
// The logging level the logger should log at. This is typically (and defaults
|
|
||||||
// to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be
|
|
||||||
// logged.
|
|
||||||
Level Level
|
|
||||||
// Used to sync writing to the log. Locking is enabled by Default
|
|
||||||
mu MutexWrap
|
|
||||||
// Reusable empty entry
|
|
||||||
entryPool sync.Pool
|
|
||||||
// Function to exit the application, defaults to `os.Exit()`
|
|
||||||
ExitFunc exitFunc
|
|
||||||
// The buffer pool used to format the log. If it is nil, the default global
|
|
||||||
// buffer pool will be used.
|
|
||||||
BufferPool BufferPool
|
|
||||||
}
|
|
||||||
|
|
||||||
type exitFunc func(int)
|
|
||||||
|
|
||||||
type MutexWrap struct {
|
|
||||||
lock sync.Mutex
|
|
||||||
disabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mw *MutexWrap) Lock() {
|
|
||||||
if !mw.disabled {
|
|
||||||
mw.lock.Lock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mw *MutexWrap) Unlock() {
|
|
||||||
if !mw.disabled {
|
|
||||||
mw.lock.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mw *MutexWrap) Disable() {
|
|
||||||
mw.disabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a new logger. Configuration should be set by changing `Formatter`,
|
|
||||||
// `Out` and `Hooks` directly on the default logger instance. You can also just
|
|
||||||
// instantiate your own:
|
|
||||||
//
|
|
||||||
// var log = &logrus.Logger{
|
|
||||||
// Out: os.Stderr,
|
|
||||||
// Formatter: new(logrus.TextFormatter),
|
|
||||||
// Hooks: make(logrus.LevelHooks),
|
|
||||||
// Level: logrus.DebugLevel,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// It's recommended to make this a global instance called `log`.
|
|
||||||
func New() *Logger {
|
|
||||||
return &Logger{
|
|
||||||
Out: os.Stderr,
|
|
||||||
Formatter: new(TextFormatter),
|
|
||||||
Hooks: make(LevelHooks),
|
|
||||||
Level: InfoLevel,
|
|
||||||
ExitFunc: os.Exit,
|
|
||||||
ReportCaller: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) newEntry() *Entry {
|
|
||||||
entry, ok := logger.entryPool.Get().(*Entry)
|
|
||||||
if ok {
|
|
||||||
return entry
|
|
||||||
}
|
|
||||||
return NewEntry(logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) releaseEntry(entry *Entry) {
|
|
||||||
entry.Data = map[string]interface{}{}
|
|
||||||
logger.entryPool.Put(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithField allocates a new entry and adds a field to it.
|
|
||||||
// Debug, Print, Info, Warn, Error, Fatal or Panic must be then applied to
|
|
||||||
// this new returned entry.
|
|
||||||
// If you want multiple fields, use `WithFields`.
|
|
||||||
func (logger *Logger) WithField(key string, value interface{}) *Entry {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
defer logger.releaseEntry(entry)
|
|
||||||
return entry.WithField(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds a struct of fields to the log entry. All it does is call `WithField` for
|
|
||||||
// each `Field`.
|
|
||||||
func (logger *Logger) WithFields(fields Fields) *Entry {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
defer logger.releaseEntry(entry)
|
|
||||||
return entry.WithFields(fields)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an error as single field to the log entry. All it does is call
|
|
||||||
// `WithError` for the given `error`.
|
|
||||||
func (logger *Logger) WithError(err error) *Entry {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
defer logger.releaseEntry(entry)
|
|
||||||
return entry.WithError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a context to the log entry.
|
|
||||||
func (logger *Logger) WithContext(ctx context.Context) *Entry {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
defer logger.releaseEntry(entry)
|
|
||||||
return entry.WithContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overrides the time of the log entry.
|
|
||||||
func (logger *Logger) WithTime(t time.Time) *Entry {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
defer logger.releaseEntry(entry)
|
|
||||||
return entry.WithTime(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Logf(level Level, format string, args ...interface{}) {
|
|
||||||
if logger.IsLevelEnabled(level) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Logf(level, format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Tracef(format string, args ...interface{}) {
|
|
||||||
logger.Logf(TraceLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Debugf(format string, args ...interface{}) {
|
|
||||||
logger.Logf(DebugLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Infof(format string, args ...interface{}) {
|
|
||||||
logger.Logf(InfoLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Printf(format string, args ...interface{}) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Printf(format, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warnf(format string, args ...interface{}) {
|
|
||||||
logger.Logf(WarnLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warningf(format string, args ...interface{}) {
|
|
||||||
logger.Warnf(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Errorf(format string, args ...interface{}) {
|
|
||||||
logger.Logf(ErrorLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Fatalf(format string, args ...interface{}) {
|
|
||||||
logger.Logf(FatalLevel, format, args...)
|
|
||||||
logger.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Panicf(format string, args ...interface{}) {
|
|
||||||
logger.Logf(PanicLevel, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log will log a message at the level given as parameter.
|
|
||||||
// Warning: using Log at Panic or Fatal level will not respectively Panic nor Exit.
|
|
||||||
// For this behaviour Logger.Panic or Logger.Fatal should be used instead.
|
|
||||||
func (logger *Logger) Log(level Level, args ...interface{}) {
|
|
||||||
if logger.IsLevelEnabled(level) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Log(level, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) LogFn(level Level, fn LogFunction) {
|
|
||||||
if logger.IsLevelEnabled(level) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Log(level, fn()...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Trace(args ...interface{}) {
|
|
||||||
logger.Log(TraceLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Debug(args ...interface{}) {
|
|
||||||
logger.Log(DebugLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Info(args ...interface{}) {
|
|
||||||
logger.Log(InfoLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Print(args ...interface{}) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Print(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warn(args ...interface{}) {
|
|
||||||
logger.Log(WarnLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warning(args ...interface{}) {
|
|
||||||
logger.Warn(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Error(args ...interface{}) {
|
|
||||||
logger.Log(ErrorLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Fatal(args ...interface{}) {
|
|
||||||
logger.Log(FatalLevel, args...)
|
|
||||||
logger.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Panic(args ...interface{}) {
|
|
||||||
logger.Log(PanicLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) TraceFn(fn LogFunction) {
|
|
||||||
logger.LogFn(TraceLevel, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) DebugFn(fn LogFunction) {
|
|
||||||
logger.LogFn(DebugLevel, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) InfoFn(fn LogFunction) {
|
|
||||||
logger.LogFn(InfoLevel, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) PrintFn(fn LogFunction) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Print(fn()...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) WarnFn(fn LogFunction) {
|
|
||||||
logger.LogFn(WarnLevel, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) WarningFn(fn LogFunction) {
|
|
||||||
logger.WarnFn(fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) ErrorFn(fn LogFunction) {
|
|
||||||
logger.LogFn(ErrorLevel, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) FatalFn(fn LogFunction) {
|
|
||||||
logger.LogFn(FatalLevel, fn)
|
|
||||||
logger.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) PanicFn(fn LogFunction) {
|
|
||||||
logger.LogFn(PanicLevel, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Logln(level Level, args ...interface{}) {
|
|
||||||
if logger.IsLevelEnabled(level) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Logln(level, args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Traceln(args ...interface{}) {
|
|
||||||
logger.Logln(TraceLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Debugln(args ...interface{}) {
|
|
||||||
logger.Logln(DebugLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Infoln(args ...interface{}) {
|
|
||||||
logger.Logln(InfoLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Println(args ...interface{}) {
|
|
||||||
entry := logger.newEntry()
|
|
||||||
entry.Println(args...)
|
|
||||||
logger.releaseEntry(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warnln(args ...interface{}) {
|
|
||||||
logger.Logln(WarnLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Warningln(args ...interface{}) {
|
|
||||||
logger.Warnln(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Errorln(args ...interface{}) {
|
|
||||||
logger.Logln(ErrorLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Fatalln(args ...interface{}) {
|
|
||||||
logger.Logln(FatalLevel, args...)
|
|
||||||
logger.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Panicln(args ...interface{}) {
|
|
||||||
logger.Logln(PanicLevel, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) Exit(code int) {
|
|
||||||
runHandlers()
|
|
||||||
if logger.ExitFunc == nil {
|
|
||||||
logger.ExitFunc = os.Exit
|
|
||||||
}
|
|
||||||
logger.ExitFunc(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
//When file is opened with appending mode, it's safe to
|
|
||||||
//write concurrently to a file (within 4k message on Linux).
|
|
||||||
//In these cases user can choose to disable the lock.
|
|
||||||
func (logger *Logger) SetNoLock() {
|
|
||||||
logger.mu.Disable()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) level() Level {
|
|
||||||
return Level(atomic.LoadUint32((*uint32)(&logger.Level)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetLevel sets the logger level.
|
|
||||||
func (logger *Logger) SetLevel(level Level) {
|
|
||||||
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLevel returns the logger level.
|
|
||||||
func (logger *Logger) GetLevel() Level {
|
|
||||||
return logger.level()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHook adds a hook to the logger hooks.
|
|
||||||
func (logger *Logger) AddHook(hook Hook) {
|
|
||||||
logger.mu.Lock()
|
|
||||||
defer logger.mu.Unlock()
|
|
||||||
logger.Hooks.Add(hook)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsLevelEnabled checks if the log level of the logger is greater than the level param
|
|
||||||
func (logger *Logger) IsLevelEnabled(level Level) bool {
|
|
||||||
return logger.level() >= level
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFormatter sets the logger formatter.
|
|
||||||
func (logger *Logger) SetFormatter(formatter Formatter) {
|
|
||||||
logger.mu.Lock()
|
|
||||||
defer logger.mu.Unlock()
|
|
||||||
logger.Formatter = formatter
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetOutput sets the logger output.
|
|
||||||
func (logger *Logger) SetOutput(output io.Writer) {
|
|
||||||
logger.mu.Lock()
|
|
||||||
defer logger.mu.Unlock()
|
|
||||||
logger.Out = output
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logger *Logger) SetReportCaller(reportCaller bool) {
|
|
||||||
logger.mu.Lock()
|
|
||||||
defer logger.mu.Unlock()
|
|
||||||
logger.ReportCaller = reportCaller
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplaceHooks replaces the logger hooks and returns the old ones
|
|
||||||
func (logger *Logger) ReplaceHooks(hooks LevelHooks) LevelHooks {
|
|
||||||
logger.mu.Lock()
|
|
||||||
oldHooks := logger.Hooks
|
|
||||||
logger.Hooks = hooks
|
|
||||||
logger.mu.Unlock()
|
|
||||||
return oldHooks
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetBufferPool sets the logger buffer pool.
|
|
||||||
func (logger *Logger) SetBufferPool(pool BufferPool) {
|
|
||||||
logger.mu.Lock()
|
|
||||||
defer logger.mu.Unlock()
|
|
||||||
logger.BufferPool = pool
|
|
||||||
}
|
|
||||||
186
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
186
vendor/github.com/sirupsen/logrus/logrus.go
generated
vendored
@@ -1,186 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fields type, used to pass to `WithFields`.
|
|
||||||
type Fields map[string]interface{}
|
|
||||||
|
|
||||||
// Level type
|
|
||||||
type Level uint32
|
|
||||||
|
|
||||||
// Convert the Level to a string. E.g. PanicLevel becomes "panic".
|
|
||||||
func (level Level) String() string {
|
|
||||||
if b, err := level.MarshalText(); err == nil {
|
|
||||||
return string(b)
|
|
||||||
} else {
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseLevel takes a string level and returns the Logrus log level constant.
|
|
||||||
func ParseLevel(lvl string) (Level, error) {
|
|
||||||
switch strings.ToLower(lvl) {
|
|
||||||
case "panic":
|
|
||||||
return PanicLevel, nil
|
|
||||||
case "fatal":
|
|
||||||
return FatalLevel, nil
|
|
||||||
case "error":
|
|
||||||
return ErrorLevel, nil
|
|
||||||
case "warn", "warning":
|
|
||||||
return WarnLevel, nil
|
|
||||||
case "info":
|
|
||||||
return InfoLevel, nil
|
|
||||||
case "debug":
|
|
||||||
return DebugLevel, nil
|
|
||||||
case "trace":
|
|
||||||
return TraceLevel, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var l Level
|
|
||||||
return l, fmt.Errorf("not a valid logrus Level: %q", lvl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
|
||||||
func (level *Level) UnmarshalText(text []byte) error {
|
|
||||||
l, err := ParseLevel(string(text))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
*level = l
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (level Level) MarshalText() ([]byte, error) {
|
|
||||||
switch level {
|
|
||||||
case TraceLevel:
|
|
||||||
return []byte("trace"), nil
|
|
||||||
case DebugLevel:
|
|
||||||
return []byte("debug"), nil
|
|
||||||
case InfoLevel:
|
|
||||||
return []byte("info"), nil
|
|
||||||
case WarnLevel:
|
|
||||||
return []byte("warning"), nil
|
|
||||||
case ErrorLevel:
|
|
||||||
return []byte("error"), nil
|
|
||||||
case FatalLevel:
|
|
||||||
return []byte("fatal"), nil
|
|
||||||
case PanicLevel:
|
|
||||||
return []byte("panic"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("not a valid logrus level %d", level)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A constant exposing all logging levels
|
|
||||||
var AllLevels = []Level{
|
|
||||||
PanicLevel,
|
|
||||||
FatalLevel,
|
|
||||||
ErrorLevel,
|
|
||||||
WarnLevel,
|
|
||||||
InfoLevel,
|
|
||||||
DebugLevel,
|
|
||||||
TraceLevel,
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are the different logging levels. You can set the logging level to log
|
|
||||||
// on your instance of logger, obtained with `logrus.New()`.
|
|
||||||
const (
|
|
||||||
// PanicLevel level, highest level of severity. Logs and then calls panic with the
|
|
||||||
// message passed to Debug, Info, ...
|
|
||||||
PanicLevel Level = iota
|
|
||||||
// FatalLevel level. Logs and then calls `logger.Exit(1)`. It will exit even if the
|
|
||||||
// logging level is set to Panic.
|
|
||||||
FatalLevel
|
|
||||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
|
||||||
// Commonly used for hooks to send errors to an error tracking service.
|
|
||||||
ErrorLevel
|
|
||||||
// WarnLevel level. Non-critical entries that deserve eyes.
|
|
||||||
WarnLevel
|
|
||||||
// InfoLevel level. General operational entries about what's going on inside the
|
|
||||||
// application.
|
|
||||||
InfoLevel
|
|
||||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
|
||||||
DebugLevel
|
|
||||||
// TraceLevel level. Designates finer-grained informational events than the Debug.
|
|
||||||
TraceLevel
|
|
||||||
)
|
|
||||||
|
|
||||||
// Won't compile if StdLogger can't be realized by a log.Logger
|
|
||||||
var (
|
|
||||||
_ StdLogger = &log.Logger{}
|
|
||||||
_ StdLogger = &Entry{}
|
|
||||||
_ StdLogger = &Logger{}
|
|
||||||
)
|
|
||||||
|
|
||||||
// StdLogger is what your logrus-enabled library should take, that way
|
|
||||||
// it'll accept a stdlib logger and a logrus logger. There's no standard
|
|
||||||
// interface, this is the closest we get, unfortunately.
|
|
||||||
type StdLogger interface {
|
|
||||||
Print(...interface{})
|
|
||||||
Printf(string, ...interface{})
|
|
||||||
Println(...interface{})
|
|
||||||
|
|
||||||
Fatal(...interface{})
|
|
||||||
Fatalf(string, ...interface{})
|
|
||||||
Fatalln(...interface{})
|
|
||||||
|
|
||||||
Panic(...interface{})
|
|
||||||
Panicf(string, ...interface{})
|
|
||||||
Panicln(...interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// The FieldLogger interface generalizes the Entry and Logger types
|
|
||||||
type FieldLogger interface {
|
|
||||||
WithField(key string, value interface{}) *Entry
|
|
||||||
WithFields(fields Fields) *Entry
|
|
||||||
WithError(err error) *Entry
|
|
||||||
|
|
||||||
Debugf(format string, args ...interface{})
|
|
||||||
Infof(format string, args ...interface{})
|
|
||||||
Printf(format string, args ...interface{})
|
|
||||||
Warnf(format string, args ...interface{})
|
|
||||||
Warningf(format string, args ...interface{})
|
|
||||||
Errorf(format string, args ...interface{})
|
|
||||||
Fatalf(format string, args ...interface{})
|
|
||||||
Panicf(format string, args ...interface{})
|
|
||||||
|
|
||||||
Debug(args ...interface{})
|
|
||||||
Info(args ...interface{})
|
|
||||||
Print(args ...interface{})
|
|
||||||
Warn(args ...interface{})
|
|
||||||
Warning(args ...interface{})
|
|
||||||
Error(args ...interface{})
|
|
||||||
Fatal(args ...interface{})
|
|
||||||
Panic(args ...interface{})
|
|
||||||
|
|
||||||
Debugln(args ...interface{})
|
|
||||||
Infoln(args ...interface{})
|
|
||||||
Println(args ...interface{})
|
|
||||||
Warnln(args ...interface{})
|
|
||||||
Warningln(args ...interface{})
|
|
||||||
Errorln(args ...interface{})
|
|
||||||
Fatalln(args ...interface{})
|
|
||||||
Panicln(args ...interface{})
|
|
||||||
|
|
||||||
// IsDebugEnabled() bool
|
|
||||||
// IsInfoEnabled() bool
|
|
||||||
// IsWarnEnabled() bool
|
|
||||||
// IsErrorEnabled() bool
|
|
||||||
// IsFatalEnabled() bool
|
|
||||||
// IsPanicEnabled() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is
|
|
||||||
// here for consistancy. Do not use. Use Logger or Entry instead.
|
|
||||||
type Ext1FieldLogger interface {
|
|
||||||
FieldLogger
|
|
||||||
Tracef(format string, args ...interface{})
|
|
||||||
Trace(args ...interface{})
|
|
||||||
Traceln(args ...interface{})
|
|
||||||
}
|
|
||||||
11
vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
11
vendor/github.com/sirupsen/logrus/terminal_check_appengine.go
generated
vendored
@@ -1,11 +0,0 @@
|
|||||||
// +build appengine
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
13
vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
generated
vendored
13
vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
generated
vendored
@@ -1,13 +0,0 @@
|
|||||||
// +build darwin dragonfly freebsd netbsd openbsd
|
|
||||||
// +build !js
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
const ioctlReadTermios = unix.TIOCGETA
|
|
||||||
|
|
||||||
func isTerminal(fd int) bool {
|
|
||||||
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
7
vendor/github.com/sirupsen/logrus/terminal_check_js.go
generated
vendored
7
vendor/github.com/sirupsen/logrus/terminal_check_js.go
generated
vendored
@@ -1,7 +0,0 @@
|
|||||||
// +build js
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
func isTerminal(fd int) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
11
vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go
generated
vendored
11
vendor/github.com/sirupsen/logrus/terminal_check_no_terminal.go
generated
vendored
@@ -1,11 +0,0 @@
|
|||||||
// +build js nacl plan9
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
17
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
17
vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go
generated
vendored
@@ -1,17 +0,0 @@
|
|||||||
// +build !appengine,!js,!windows,!nacl,!plan9
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
|
||||||
switch v := w.(type) {
|
|
||||||
case *os.File:
|
|
||||||
return isTerminal(int(v.Fd()))
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
11
vendor/github.com/sirupsen/logrus/terminal_check_solaris.go
generated
vendored
11
vendor/github.com/sirupsen/logrus/terminal_check_solaris.go
generated
vendored
@@ -1,11 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
|
||||||
func isTerminal(fd int) bool {
|
|
||||||
_, err := unix.IoctlGetTermio(fd, unix.TCGETA)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
13
vendor/github.com/sirupsen/logrus/terminal_check_unix.go
generated
vendored
13
vendor/github.com/sirupsen/logrus/terminal_check_unix.go
generated
vendored
@@ -1,13 +0,0 @@
|
|||||||
// +build linux aix zos
|
|
||||||
// +build !js
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import "golang.org/x/sys/unix"
|
|
||||||
|
|
||||||
const ioctlReadTermios = unix.TCGETS
|
|
||||||
|
|
||||||
func isTerminal(fd int) bool {
|
|
||||||
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
27
vendor/github.com/sirupsen/logrus/terminal_check_windows.go
generated
vendored
27
vendor/github.com/sirupsen/logrus/terminal_check_windows.go
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
// +build !appengine,!js,windows
|
|
||||||
|
|
||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkIfTerminal(w io.Writer) bool {
|
|
||||||
switch v := w.(type) {
|
|
||||||
case *os.File:
|
|
||||||
handle := windows.Handle(v.Fd())
|
|
||||||
var mode uint32
|
|
||||||
if err := windows.GetConsoleMode(handle, &mode); err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
||||||
if err := windows.SetConsoleMode(handle, mode); err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
339
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
339
vendor/github.com/sirupsen/logrus/text_formatter.go
generated
vendored
@@ -1,339 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
red = 31
|
|
||||||
yellow = 33
|
|
||||||
blue = 36
|
|
||||||
gray = 37
|
|
||||||
)
|
|
||||||
|
|
||||||
var baseTimestamp time.Time
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
baseTimestamp = time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TextFormatter formats logs into text
|
|
||||||
type TextFormatter struct {
|
|
||||||
// Set to true to bypass checking for a TTY before outputting colors.
|
|
||||||
ForceColors bool
|
|
||||||
|
|
||||||
// Force disabling colors.
|
|
||||||
DisableColors bool
|
|
||||||
|
|
||||||
// Force quoting of all values
|
|
||||||
ForceQuote bool
|
|
||||||
|
|
||||||
// DisableQuote disables quoting for all values.
|
|
||||||
// DisableQuote will have a lower priority than ForceQuote.
|
|
||||||
// If both of them are set to true, quote will be forced on all values.
|
|
||||||
DisableQuote bool
|
|
||||||
|
|
||||||
// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/
|
|
||||||
EnvironmentOverrideColors bool
|
|
||||||
|
|
||||||
// Disable timestamp logging. useful when output is redirected to logging
|
|
||||||
// system that already adds timestamps.
|
|
||||||
DisableTimestamp bool
|
|
||||||
|
|
||||||
// Enable logging the full timestamp when a TTY is attached instead of just
|
|
||||||
// the time passed since beginning of execution.
|
|
||||||
FullTimestamp bool
|
|
||||||
|
|
||||||
// TimestampFormat to use for display when a full timestamp is printed.
|
|
||||||
// The format to use is the same than for time.Format or time.Parse from the standard
|
|
||||||
// library.
|
|
||||||
// The standard Library already provides a set of predefined format.
|
|
||||||
TimestampFormat string
|
|
||||||
|
|
||||||
// The fields are sorted by default for a consistent output. For applications
|
|
||||||
// that log extremely frequently and don't use the JSON formatter this may not
|
|
||||||
// be desired.
|
|
||||||
DisableSorting bool
|
|
||||||
|
|
||||||
// The keys sorting function, when uninitialized it uses sort.Strings.
|
|
||||||
SortingFunc func([]string)
|
|
||||||
|
|
||||||
// Disables the truncation of the level text to 4 characters.
|
|
||||||
DisableLevelTruncation bool
|
|
||||||
|
|
||||||
// PadLevelText Adds padding the level text so that all the levels output at the same length
|
|
||||||
// PadLevelText is a superset of the DisableLevelTruncation option
|
|
||||||
PadLevelText bool
|
|
||||||
|
|
||||||
// QuoteEmptyFields will wrap empty fields in quotes if true
|
|
||||||
QuoteEmptyFields bool
|
|
||||||
|
|
||||||
// Whether the logger's out is to a terminal
|
|
||||||
isTerminal bool
|
|
||||||
|
|
||||||
// FieldMap allows users to customize the names of keys for default fields.
|
|
||||||
// As an example:
|
|
||||||
// formatter := &TextFormatter{
|
|
||||||
// FieldMap: FieldMap{
|
|
||||||
// FieldKeyTime: "@timestamp",
|
|
||||||
// FieldKeyLevel: "@level",
|
|
||||||
// FieldKeyMsg: "@message"}}
|
|
||||||
FieldMap FieldMap
|
|
||||||
|
|
||||||
// CallerPrettyfier can be set by the user to modify the content
|
|
||||||
// of the function and file keys in the data when ReportCaller is
|
|
||||||
// activated. If any of the returned value is the empty string the
|
|
||||||
// corresponding key will be removed from fields.
|
|
||||||
CallerPrettyfier func(*runtime.Frame) (function string, file string)
|
|
||||||
|
|
||||||
terminalInitOnce sync.Once
|
|
||||||
|
|
||||||
// The max length of the level text, generated dynamically on init
|
|
||||||
levelTextMaxLength int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) init(entry *Entry) {
|
|
||||||
if entry.Logger != nil {
|
|
||||||
f.isTerminal = checkIfTerminal(entry.Logger.Out)
|
|
||||||
}
|
|
||||||
// Get the max length of the level text
|
|
||||||
for _, level := range AllLevels {
|
|
||||||
levelTextLength := utf8.RuneCount([]byte(level.String()))
|
|
||||||
if levelTextLength > f.levelTextMaxLength {
|
|
||||||
f.levelTextMaxLength = levelTextLength
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) isColored() bool {
|
|
||||||
isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows"))
|
|
||||||
|
|
||||||
if f.EnvironmentOverrideColors {
|
|
||||||
switch force, ok := os.LookupEnv("CLICOLOR_FORCE"); {
|
|
||||||
case ok && force != "0":
|
|
||||||
isColored = true
|
|
||||||
case ok && force == "0", os.Getenv("CLICOLOR") == "0":
|
|
||||||
isColored = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return isColored && !f.DisableColors
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format renders a single log entry
|
|
||||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|
||||||
data := make(Fields)
|
|
||||||
for k, v := range entry.Data {
|
|
||||||
data[k] = v
|
|
||||||
}
|
|
||||||
prefixFieldClashes(data, f.FieldMap, entry.HasCaller())
|
|
||||||
keys := make([]string, 0, len(data))
|
|
||||||
for k := range data {
|
|
||||||
keys = append(keys, k)
|
|
||||||
}
|
|
||||||
|
|
||||||
var funcVal, fileVal string
|
|
||||||
|
|
||||||
fixedKeys := make([]string, 0, 4+len(data))
|
|
||||||
if !f.DisableTimestamp {
|
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime))
|
|
||||||
}
|
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel))
|
|
||||||
if entry.Message != "" {
|
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg))
|
|
||||||
}
|
|
||||||
if entry.err != "" {
|
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError))
|
|
||||||
}
|
|
||||||
if entry.HasCaller() {
|
|
||||||
if f.CallerPrettyfier != nil {
|
|
||||||
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
|
||||||
} else {
|
|
||||||
funcVal = entry.Caller.Function
|
|
||||||
fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
|
||||||
}
|
|
||||||
|
|
||||||
if funcVal != "" {
|
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc))
|
|
||||||
}
|
|
||||||
if fileVal != "" {
|
|
||||||
fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !f.DisableSorting {
|
|
||||||
if f.SortingFunc == nil {
|
|
||||||
sort.Strings(keys)
|
|
||||||
fixedKeys = append(fixedKeys, keys...)
|
|
||||||
} else {
|
|
||||||
if !f.isColored() {
|
|
||||||
fixedKeys = append(fixedKeys, keys...)
|
|
||||||
f.SortingFunc(fixedKeys)
|
|
||||||
} else {
|
|
||||||
f.SortingFunc(keys)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fixedKeys = append(fixedKeys, keys...)
|
|
||||||
}
|
|
||||||
|
|
||||||
var b *bytes.Buffer
|
|
||||||
if entry.Buffer != nil {
|
|
||||||
b = entry.Buffer
|
|
||||||
} else {
|
|
||||||
b = &bytes.Buffer{}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.terminalInitOnce.Do(func() { f.init(entry) })
|
|
||||||
|
|
||||||
timestampFormat := f.TimestampFormat
|
|
||||||
if timestampFormat == "" {
|
|
||||||
timestampFormat = defaultTimestampFormat
|
|
||||||
}
|
|
||||||
if f.isColored() {
|
|
||||||
f.printColored(b, entry, keys, data, timestampFormat)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
for _, key := range fixedKeys {
|
|
||||||
var value interface{}
|
|
||||||
switch {
|
|
||||||
case key == f.FieldMap.resolve(FieldKeyTime):
|
|
||||||
value = entry.Time.Format(timestampFormat)
|
|
||||||
case key == f.FieldMap.resolve(FieldKeyLevel):
|
|
||||||
value = entry.Level.String()
|
|
||||||
case key == f.FieldMap.resolve(FieldKeyMsg):
|
|
||||||
value = entry.Message
|
|
||||||
case key == f.FieldMap.resolve(FieldKeyLogrusError):
|
|
||||||
value = entry.err
|
|
||||||
case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller():
|
|
||||||
value = funcVal
|
|
||||||
case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller():
|
|
||||||
value = fileVal
|
|
||||||
default:
|
|
||||||
value = data[key]
|
|
||||||
}
|
|
||||||
f.appendKeyValue(b, key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.WriteByte('\n')
|
|
||||||
return b.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) {
|
|
||||||
var levelColor int
|
|
||||||
switch entry.Level {
|
|
||||||
case DebugLevel, TraceLevel:
|
|
||||||
levelColor = gray
|
|
||||||
case WarnLevel:
|
|
||||||
levelColor = yellow
|
|
||||||
case ErrorLevel, FatalLevel, PanicLevel:
|
|
||||||
levelColor = red
|
|
||||||
case InfoLevel:
|
|
||||||
levelColor = blue
|
|
||||||
default:
|
|
||||||
levelColor = blue
|
|
||||||
}
|
|
||||||
|
|
||||||
levelText := strings.ToUpper(entry.Level.String())
|
|
||||||
if !f.DisableLevelTruncation && !f.PadLevelText {
|
|
||||||
levelText = levelText[0:4]
|
|
||||||
}
|
|
||||||
if f.PadLevelText {
|
|
||||||
// Generates the format string used in the next line, for example "%-6s" or "%-7s".
|
|
||||||
// Based on the max level text length.
|
|
||||||
formatString := "%-" + strconv.Itoa(f.levelTextMaxLength) + "s"
|
|
||||||
// Formats the level text by appending spaces up to the max length, for example:
|
|
||||||
// - "INFO "
|
|
||||||
// - "WARNING"
|
|
||||||
levelText = fmt.Sprintf(formatString, levelText)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a single newline if it already exists in the message to keep
|
|
||||||
// the behavior of logrus text_formatter the same as the stdlib log package
|
|
||||||
entry.Message = strings.TrimSuffix(entry.Message, "\n")
|
|
||||||
|
|
||||||
caller := ""
|
|
||||||
if entry.HasCaller() {
|
|
||||||
funcVal := fmt.Sprintf("%s()", entry.Caller.Function)
|
|
||||||
fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)
|
|
||||||
|
|
||||||
if f.CallerPrettyfier != nil {
|
|
||||||
funcVal, fileVal = f.CallerPrettyfier(entry.Caller)
|
|
||||||
}
|
|
||||||
|
|
||||||
if fileVal == "" {
|
|
||||||
caller = funcVal
|
|
||||||
} else if funcVal == "" {
|
|
||||||
caller = fileVal
|
|
||||||
} else {
|
|
||||||
caller = fileVal + " " + funcVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case f.DisableTimestamp:
|
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message)
|
|
||||||
case !f.FullTimestamp:
|
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message)
|
|
||||||
default:
|
|
||||||
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message)
|
|
||||||
}
|
|
||||||
for _, k := range keys {
|
|
||||||
v := data[k]
|
|
||||||
fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k)
|
|
||||||
f.appendValue(b, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) needsQuoting(text string) bool {
|
|
||||||
if f.ForceQuote {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if f.QuoteEmptyFields && len(text) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if f.DisableQuote {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, ch := range text {
|
|
||||||
if !((ch >= 'a' && ch <= 'z') ||
|
|
||||||
(ch >= 'A' && ch <= 'Z') ||
|
|
||||||
(ch >= '0' && ch <= '9') ||
|
|
||||||
ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
|
||||||
if b.Len() > 0 {
|
|
||||||
b.WriteByte(' ')
|
|
||||||
}
|
|
||||||
b.WriteString(key)
|
|
||||||
b.WriteByte('=')
|
|
||||||
f.appendValue(b, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
|
|
||||||
stringVal, ok := value.(string)
|
|
||||||
if !ok {
|
|
||||||
stringVal = fmt.Sprint(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !f.needsQuoting(stringVal) {
|
|
||||||
b.WriteString(stringVal)
|
|
||||||
} else {
|
|
||||||
b.WriteString(fmt.Sprintf("%q", stringVal))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
102
vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
102
vendor/github.com/sirupsen/logrus/writer.go
generated
vendored
@@ -1,102 +0,0 @@
|
|||||||
package logrus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"io"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Writer at INFO level. See WriterLevel for details.
|
|
||||||
func (logger *Logger) Writer() *io.PipeWriter {
|
|
||||||
return logger.WriterLevel(InfoLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriterLevel returns an io.Writer that can be used to write arbitrary text to
|
|
||||||
// the logger at the given log level. Each line written to the writer will be
|
|
||||||
// printed in the usual way using formatters and hooks. The writer is part of an
|
|
||||||
// io.Pipe and it is the callers responsibility to close the writer when done.
|
|
||||||
// This can be used to override the standard library logger easily.
|
|
||||||
func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
|
|
||||||
return NewEntry(logger).WriterLevel(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writer returns an io.Writer that writes to the logger at the info log level
|
|
||||||
func (entry *Entry) Writer() *io.PipeWriter {
|
|
||||||
return entry.WriterLevel(InfoLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriterLevel returns an io.Writer that writes to the logger at the given log level
|
|
||||||
func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
|
|
||||||
reader, writer := io.Pipe()
|
|
||||||
|
|
||||||
var printFunc func(args ...interface{})
|
|
||||||
|
|
||||||
// Determine which log function to use based on the specified log level
|
|
||||||
switch level {
|
|
||||||
case TraceLevel:
|
|
||||||
printFunc = entry.Trace
|
|
||||||
case DebugLevel:
|
|
||||||
printFunc = entry.Debug
|
|
||||||
case InfoLevel:
|
|
||||||
printFunc = entry.Info
|
|
||||||
case WarnLevel:
|
|
||||||
printFunc = entry.Warn
|
|
||||||
case ErrorLevel:
|
|
||||||
printFunc = entry.Error
|
|
||||||
case FatalLevel:
|
|
||||||
printFunc = entry.Fatal
|
|
||||||
case PanicLevel:
|
|
||||||
printFunc = entry.Panic
|
|
||||||
default:
|
|
||||||
printFunc = entry.Print
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start a new goroutine to scan the input and write it to the logger using the specified print function.
|
|
||||||
// It splits the input into chunks of up to 64KB to avoid buffer overflows.
|
|
||||||
go entry.writerScanner(reader, printFunc)
|
|
||||||
|
|
||||||
// Set a finalizer function to close the writer when it is garbage collected
|
|
||||||
runtime.SetFinalizer(writer, writerFinalizer)
|
|
||||||
|
|
||||||
return writer
|
|
||||||
}
|
|
||||||
|
|
||||||
// writerScanner scans the input from the reader and writes it to the logger
|
|
||||||
func (entry *Entry) writerScanner(reader *io.PipeReader, printFunc func(args ...interface{})) {
|
|
||||||
scanner := bufio.NewScanner(reader)
|
|
||||||
|
|
||||||
// Set the buffer size to the maximum token size to avoid buffer overflows
|
|
||||||
scanner.Buffer(make([]byte, bufio.MaxScanTokenSize), bufio.MaxScanTokenSize)
|
|
||||||
|
|
||||||
// Define a split function to split the input into chunks of up to 64KB
|
|
||||||
chunkSize := bufio.MaxScanTokenSize // 64KB
|
|
||||||
splitFunc := func(data []byte, atEOF bool) (int, []byte, error) {
|
|
||||||
if len(data) >= chunkSize {
|
|
||||||
return chunkSize, data[:chunkSize], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return bufio.ScanLines(data, atEOF)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the custom split function to split the input
|
|
||||||
scanner.Split(splitFunc)
|
|
||||||
|
|
||||||
// Scan the input and write it to the logger using the specified print function
|
|
||||||
for scanner.Scan() {
|
|
||||||
printFunc(strings.TrimRight(scanner.Text(), "\r\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there was an error while scanning the input, log an error
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
entry.Errorf("Error while reading from Writer: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the reader when we are done
|
|
||||||
reader.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriterFinalizer is a finalizer function that closes then given writer when it is garbage collected
|
|
||||||
func writerFinalizer(writer *io.PipeWriter) {
|
|
||||||
writer.Close()
|
|
||||||
}
|
|
||||||
27
vendor/golang.org/x/exp/LICENSE
generated
vendored
27
vendor/golang.org/x/exp/LICENSE
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
Copyright 2009 The Go Authors.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google LLC nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
22
vendor/golang.org/x/exp/PATENTS
generated
vendored
22
vendor/golang.org/x/exp/PATENTS
generated
vendored
@@ -1,22 +0,0 @@
|
|||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
||||||
182
vendor/golang.org/x/exp/slices/slices.go
generated
vendored
182
vendor/golang.org/x/exp/slices/slices.go
generated
vendored
@@ -1,182 +0,0 @@
|
|||||||
// Copyright 2021 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package slices defines various functions useful with slices of any type.
|
|
||||||
package slices
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cmp"
|
|
||||||
"slices"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Equal reports whether two slices are equal: the same length and all
|
|
||||||
// elements equal. If the lengths are different, Equal returns false.
|
|
||||||
// Otherwise, the elements are compared in increasing index order, and the
|
|
||||||
// comparison stops at the first unequal pair.
|
|
||||||
// Floating point NaNs are not considered equal.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Equal[S ~[]E, E comparable](s1, s2 S) bool {
|
|
||||||
return slices.Equal(s1, s2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EqualFunc reports whether two slices are equal using an equality
|
|
||||||
// function on each pair of elements. If the lengths are different,
|
|
||||||
// EqualFunc returns false. Otherwise, the elements are compared in
|
|
||||||
// increasing index order, and the comparison stops at the first index
|
|
||||||
// for which eq returns false.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
|
|
||||||
return slices.EqualFunc(s1, s2, eq)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair
|
|
||||||
// of elements. The elements are compared sequentially, starting at index 0,
|
|
||||||
// until one element is not equal to the other.
|
|
||||||
// The result of comparing the first non-matching elements is returned.
|
|
||||||
// If both slices are equal until one of them ends, the shorter slice is
|
|
||||||
// considered less than the longer one.
|
|
||||||
// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) int {
|
|
||||||
return slices.Compare(s1, s2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompareFunc is like [Compare] but uses a custom comparison function on each
|
|
||||||
// pair of elements.
|
|
||||||
// The result is the first non-zero result of cmp; if cmp always
|
|
||||||
// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
|
|
||||||
// and +1 if len(s1) > len(s2).
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int {
|
|
||||||
return slices.CompareFunc(s1, s2, cmp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Index returns the index of the first occurrence of v in s,
|
|
||||||
// or -1 if not present.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Index[S ~[]E, E comparable](s S, v E) int {
|
|
||||||
return slices.Index(s, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IndexFunc returns the first index i satisfying f(s[i]),
|
|
||||||
// or -1 if none do.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
|
|
||||||
return slices.IndexFunc(s, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains reports whether v is present in s.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Contains[S ~[]E, E comparable](s S, v E) bool {
|
|
||||||
return slices.Contains(s, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainsFunc reports whether at least one
|
|
||||||
// element e of s satisfies f(e).
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
|
|
||||||
return slices.ContainsFunc(s, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert inserts the values v... into s at index i,
|
|
||||||
// returning the modified slice.
|
|
||||||
// The elements at s[i:] are shifted up to make room.
|
|
||||||
// In the returned slice r, r[i] == v[0],
|
|
||||||
// and r[i+len(v)] == value originally at r[i].
|
|
||||||
// Insert panics if i is out of range.
|
|
||||||
// This function is O(len(s) + len(v)).
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Insert[S ~[]E, E any](s S, i int, v ...E) S {
|
|
||||||
return slices.Insert(s, i, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete removes the elements s[i:j] from s, returning the modified slice.
|
|
||||||
// Delete panics if j > len(s) or s[i:j] is not a valid slice of s.
|
|
||||||
// Delete is O(len(s)-i), so if many items must be deleted, it is better to
|
|
||||||
// make a single call deleting them all together than to delete one at a time.
|
|
||||||
// Delete zeroes the elements s[len(s)-(j-i):len(s)].
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Delete[S ~[]E, E any](s S, i, j int) S {
|
|
||||||
return slices.Delete(s, i, j)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteFunc removes any elements from s for which del returns true,
|
|
||||||
// returning the modified slice.
|
|
||||||
// DeleteFunc zeroes the elements between the new length and the original length.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
|
|
||||||
return slices.DeleteFunc(s, del)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace replaces the elements s[i:j] by the given v, and returns the
|
|
||||||
// modified slice. Replace panics if s[i:j] is not a valid slice of s.
|
|
||||||
// When len(v) < (j-i), Replace zeroes the elements between the new length and the original length.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
|
|
||||||
return slices.Replace(s, i, j, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone returns a copy of the slice.
|
|
||||||
// The elements are copied using assignment, so this is a shallow clone.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Clone[S ~[]E, E any](s S) S {
|
|
||||||
return slices.Clone(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compact replaces consecutive runs of equal elements with a single copy.
|
|
||||||
// This is like the uniq command found on Unix.
|
|
||||||
// Compact modifies the contents of the slice s and returns the modified slice,
|
|
||||||
// which may have a smaller length.
|
|
||||||
// Compact zeroes the elements between the new length and the original length.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Compact[S ~[]E, E comparable](s S) S {
|
|
||||||
return slices.Compact(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompactFunc is like [Compact] but uses an equality function to compare elements.
|
|
||||||
// For runs of elements that compare equal, CompactFunc keeps the first one.
|
|
||||||
// CompactFunc zeroes the elements between the new length and the original length.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
|
|
||||||
return slices.CompactFunc(s, eq)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grow increases the slice's capacity, if necessary, to guarantee space for
|
|
||||||
// another n elements. After Grow(n), at least n elements can be appended
|
|
||||||
// to the slice without another allocation. If n is negative or too large to
|
|
||||||
// allocate the memory, Grow panics.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Grow[S ~[]E, E any](s S, n int) S {
|
|
||||||
return slices.Grow(s, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Clip[S ~[]E, E any](s S) S {
|
|
||||||
return slices.Clip(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reverse reverses the elements of the slice in place.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Reverse[S ~[]E, E any](s S) {
|
|
||||||
slices.Reverse(s)
|
|
||||||
}
|
|
||||||
115
vendor/golang.org/x/exp/slices/sort.go
generated
vendored
115
vendor/golang.org/x/exp/slices/sort.go
generated
vendored
@@ -1,115 +0,0 @@
|
|||||||
// Copyright 2022 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package slices
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cmp"
|
|
||||||
"slices"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Sort sorts a slice of any ordered type in ascending order.
|
|
||||||
// When sorting floating-point numbers, NaNs are ordered before other values.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Sort[S ~[]E, E cmp.Ordered](x S) {
|
|
||||||
slices.Sort(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SortFunc sorts the slice x in ascending order as determined by the cmp
|
|
||||||
// function. This sort is not guaranteed to be stable.
|
|
||||||
// cmp(a, b) should return a negative number when a < b, a positive number when
|
|
||||||
// a > b and zero when a == b or when a is not comparable to b in the sense
|
|
||||||
// of the formal definition of Strict Weak Ordering.
|
|
||||||
//
|
|
||||||
// SortFunc requires that cmp is a strict weak ordering.
|
|
||||||
// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
|
|
||||||
// To indicate 'uncomparable', return 0 from the function.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
|
|
||||||
slices.SortFunc(x, cmp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SortStableFunc sorts the slice x while keeping the original order of equal
|
|
||||||
// elements, using cmp to compare elements in the same way as [SortFunc].
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
|
|
||||||
slices.SortStableFunc(x, cmp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSorted reports whether x is sorted in ascending order.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func IsSorted[S ~[]E, E cmp.Ordered](x S) bool {
|
|
||||||
return slices.IsSorted(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
|
|
||||||
// comparison function as defined by [SortFunc].
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
|
|
||||||
return slices.IsSortedFunc(x, cmp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Min returns the minimal value in x. It panics if x is empty.
|
|
||||||
// For floating-point numbers, Min propagates NaNs (any NaN value in x
|
|
||||||
// forces the output to be NaN).
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Min[S ~[]E, E cmp.Ordered](x S) E {
|
|
||||||
return slices.Min(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MinFunc returns the minimal value in x, using cmp to compare elements.
|
|
||||||
// It panics if x is empty. If there is more than one minimal element
|
|
||||||
// according to the cmp function, MinFunc returns the first one.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
|
|
||||||
return slices.MinFunc(x, cmp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max returns the maximal value in x. It panics if x is empty.
|
|
||||||
// For floating-point E, Max propagates NaNs (any NaN value in x
|
|
||||||
// forces the output to be NaN).
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func Max[S ~[]E, E cmp.Ordered](x S) E {
|
|
||||||
return slices.Max(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxFunc returns the maximal value in x, using cmp to compare elements.
|
|
||||||
// It panics if x is empty. If there is more than one maximal element
|
|
||||||
// according to the cmp function, MaxFunc returns the first one.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
|
|
||||||
return slices.MaxFunc(x, cmp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinarySearch searches for target in a sorted slice and returns the position
|
|
||||||
// where target is found, or the position where target would appear in the
|
|
||||||
// sort order; it also returns a bool saying whether the target is really found
|
|
||||||
// in the slice. The slice must be sorted in increasing order.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) {
|
|
||||||
return slices.BinarySearch(x, target)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinarySearchFunc works like [BinarySearch], but uses a custom comparison
|
|
||||||
// function. The slice must be sorted in increasing order, where "increasing"
|
|
||||||
// is defined by cmp. cmp should return 0 if the slice element matches
|
|
||||||
// the target, a negative number if the slice element precedes the target,
|
|
||||||
// or a positive number if the slice element follows the target.
|
|
||||||
// cmp must implement the same ordering as the slice, such that if
|
|
||||||
// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
|
|
||||||
//
|
|
||||||
//go:fix inline
|
|
||||||
func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
|
|
||||||
return slices.BinarySearchFunc(x, target, cmp)
|
|
||||||
}
|
|
||||||
22
vendor/golang.org/x/sys/PATENTS
generated
vendored
22
vendor/golang.org/x/sys/PATENTS
generated
vendored
@@ -1,22 +0,0 @@
|
|||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
||||||
2
vendor/golang.org/x/sys/unix/.gitignore
generated
vendored
2
vendor/golang.org/x/sys/unix/.gitignore
generated
vendored
@@ -1,2 +0,0 @@
|
|||||||
_obj/
|
|
||||||
unix.test
|
|
||||||
184
vendor/golang.org/x/sys/unix/README.md
generated
vendored
184
vendor/golang.org/x/sys/unix/README.md
generated
vendored
@@ -1,184 +0,0 @@
|
|||||||
# Building `sys/unix`
|
|
||||||
|
|
||||||
The sys/unix package provides access to the raw system call interface of the
|
|
||||||
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
|
|
||||||
|
|
||||||
Porting Go to a new architecture/OS combination or adding syscalls, types, or
|
|
||||||
constants to an existing architecture/OS pair requires some manual effort;
|
|
||||||
however, there are tools that automate much of the process.
|
|
||||||
|
|
||||||
## Build Systems
|
|
||||||
|
|
||||||
There are currently two ways we generate the necessary files. We are currently
|
|
||||||
migrating the build system to use containers so the builds are reproducible.
|
|
||||||
This is being done on an OS-by-OS basis. Please update this documentation as
|
|
||||||
components of the build system change.
|
|
||||||
|
|
||||||
### Old Build System (currently for `GOOS != "linux"`)
|
|
||||||
|
|
||||||
The old build system generates the Go files based on the C header files
|
|
||||||
present on your system. This means that files
|
|
||||||
for a given GOOS/GOARCH pair must be generated on a system with that OS and
|
|
||||||
architecture. This also means that the generated code can differ from system
|
|
||||||
to system, based on differences in the header files.
|
|
||||||
|
|
||||||
To avoid this, if you are using the old build system, only generate the Go
|
|
||||||
files on an installation with unmodified header files. It is also important to
|
|
||||||
keep track of which version of the OS the files were generated from (ex.
|
|
||||||
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
|
|
||||||
and have each OS upgrade correspond to a single change.
|
|
||||||
|
|
||||||
To build the files for your current OS and architecture, make sure GOOS and
|
|
||||||
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
|
|
||||||
your specific system. Running `mkall.sh -n` shows the commands that will be run.
|
|
||||||
|
|
||||||
Requirements: bash, go
|
|
||||||
|
|
||||||
### New Build System (currently for `GOOS == "linux"`)
|
|
||||||
|
|
||||||
The new build system uses a Docker container to generate the go files directly
|
|
||||||
from source checkouts of the kernel and various system libraries. This means
|
|
||||||
that on any platform that supports Docker, all the files using the new build
|
|
||||||
system can be generated at once, and generated files will not change based on
|
|
||||||
what the person running the scripts has installed on their computer.
|
|
||||||
|
|
||||||
The OS specific files for the new build system are located in the `${GOOS}`
|
|
||||||
directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
|
|
||||||
the kernel or system library updates, modify the Dockerfile at
|
|
||||||
`${GOOS}/Dockerfile` to checkout the new release of the source.
|
|
||||||
|
|
||||||
To build all the files under the new build system, you must be on an amd64/Linux
|
|
||||||
system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
|
|
||||||
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
|
|
||||||
system. Running `mkall.sh -n` shows the commands that will be run.
|
|
||||||
|
|
||||||
Requirements: bash, go, docker
|
|
||||||
|
|
||||||
## Component files
|
|
||||||
|
|
||||||
This section describes the various files used in the code generation process.
|
|
||||||
It also contains instructions on how to modify these files to add a new
|
|
||||||
architecture/OS or to add additional syscalls, types, or constants. Note that
|
|
||||||
if you are using the new build system, the scripts/programs cannot be called normally.
|
|
||||||
They must be called from within the docker container.
|
|
||||||
|
|
||||||
### asm files
|
|
||||||
|
|
||||||
The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
|
|
||||||
call dispatch. There are three entry points:
|
|
||||||
```
|
|
||||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
|
|
||||||
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
|
|
||||||
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
|
|
||||||
```
|
|
||||||
The first and second are the standard ones; they differ only in how many
|
|
||||||
arguments can be passed to the kernel. The third is for low-level use by the
|
|
||||||
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
|
|
||||||
let it know that a system call is running.
|
|
||||||
|
|
||||||
When porting Go to a new architecture/OS, this file must be implemented for
|
|
||||||
each GOOS/GOARCH pair.
|
|
||||||
|
|
||||||
### mksysnum
|
|
||||||
|
|
||||||
Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
|
|
||||||
for the old system). This program takes in a list of header files containing the
|
|
||||||
syscall number declarations and parses them to produce the corresponding list of
|
|
||||||
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
|
|
||||||
constants.
|
|
||||||
|
|
||||||
Adding new syscall numbers is mostly done by running the build on a sufficiently
|
|
||||||
new installation of the target OS (or updating the source checkouts for the
|
|
||||||
new build system). However, depending on the OS, you may need to update the
|
|
||||||
parsing in mksysnum.
|
|
||||||
|
|
||||||
### mksyscall.go
|
|
||||||
|
|
||||||
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
|
|
||||||
hand-written Go files which implement system calls (for unix, the specific OS,
|
|
||||||
or the specific OS/Architecture pair respectively) that need special handling
|
|
||||||
and list `//sys` comments giving prototypes for ones that can be generated.
|
|
||||||
|
|
||||||
The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
|
|
||||||
them into syscalls. This requires the name of the prototype in the comment to
|
|
||||||
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
|
|
||||||
prototype can be exported (capitalized) or not.
|
|
||||||
|
|
||||||
Adding a new syscall often just requires adding a new `//sys` function prototype
|
|
||||||
with the desired arguments and a capitalized name so it is exported. However, if
|
|
||||||
you want the interface to the syscall to be different, often one will make an
|
|
||||||
unexported `//sys` prototype, and then write a custom wrapper in
|
|
||||||
`syscall_${GOOS}.go`.
|
|
||||||
|
|
||||||
### types files
|
|
||||||
|
|
||||||
For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
|
|
||||||
`types_${GOOS}.go` on the old system). This file includes standard C headers and
|
|
||||||
creates Go type aliases to the corresponding C types. The file is then fed
|
|
||||||
through godef to get the Go compatible definitions. Finally, the generated code
|
|
||||||
is fed though mkpost.go to format the code correctly and remove any hidden or
|
|
||||||
private identifiers. This cleaned-up code is written to
|
|
||||||
`ztypes_${GOOS}_${GOARCH}.go`.
|
|
||||||
|
|
||||||
The hardest part about preparing this file is figuring out which headers to
|
|
||||||
include and which symbols need to be `#define`d to get the actual data
|
|
||||||
structures that pass through to the kernel system calls. Some C libraries
|
|
||||||
preset alternate versions for binary compatibility and translate them on the
|
|
||||||
way in and out of system calls, but there is almost always a `#define` that can
|
|
||||||
get the real ones.
|
|
||||||
See `types_darwin.go` and `linux/types.go` for examples.
|
|
||||||
|
|
||||||
To add a new type, add in the necessary include statement at the top of the
|
|
||||||
file (if it is not already there) and add in a type alias line. Note that if
|
|
||||||
your type is significantly different on different architectures, you may need
|
|
||||||
some `#if/#elif` macros in your include statements.
|
|
||||||
|
|
||||||
### mkerrors.sh
|
|
||||||
|
|
||||||
This script is used to generate the system's various constants. This doesn't
|
|
||||||
just include the error numbers and error strings, but also the signal numbers
|
|
||||||
and a wide variety of miscellaneous constants. The constants come from the list
|
|
||||||
of include files in the `includes_${uname}` variable. A regex then picks out
|
|
||||||
the desired `#define` statements, and generates the corresponding Go constants.
|
|
||||||
The error numbers and strings are generated from `#include <errno.h>`, and the
|
|
||||||
signal numbers and strings are generated from `#include <signal.h>`. All of
|
|
||||||
these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
|
|
||||||
`_errors.c`, which prints out all the constants.
|
|
||||||
|
|
||||||
To add a constant, add the header that includes it to the appropriate variable.
|
|
||||||
Then, edit the regex (if necessary) to match the desired constant. Avoid making
|
|
||||||
the regex too broad to avoid matching unintended constants.
|
|
||||||
|
|
||||||
### internal/mkmerge
|
|
||||||
|
|
||||||
This program is used to extract duplicate const, func, and type declarations
|
|
||||||
from the generated architecture-specific files listed below, and merge these
|
|
||||||
into a common file for each OS.
|
|
||||||
|
|
||||||
The merge is performed in the following steps:
|
|
||||||
1. Construct the set of common code that is identical in all architecture-specific files.
|
|
||||||
2. Write this common code to the merged file.
|
|
||||||
3. Remove the common code from all architecture-specific files.
|
|
||||||
|
|
||||||
|
|
||||||
## Generated files
|
|
||||||
|
|
||||||
### `zerrors_${GOOS}_${GOARCH}.go`
|
|
||||||
|
|
||||||
A file containing all of the system's generated error numbers, error strings,
|
|
||||||
signal numbers, and constants. Generated by `mkerrors.sh` (see above).
|
|
||||||
|
|
||||||
### `zsyscall_${GOOS}_${GOARCH}.go`
|
|
||||||
|
|
||||||
A file containing all the generated syscalls for a specific GOOS and GOARCH.
|
|
||||||
Generated by `mksyscall.go` (see above).
|
|
||||||
|
|
||||||
### `zsysnum_${GOOS}_${GOARCH}.go`
|
|
||||||
|
|
||||||
A list of numeric constants for all the syscall number of the specific GOOS
|
|
||||||
and GOARCH. Generated by mksysnum (see above).
|
|
||||||
|
|
||||||
### `ztypes_${GOOS}_${GOARCH}.go`
|
|
||||||
|
|
||||||
A file containing Go types for passing into (or returning from) syscalls.
|
|
||||||
Generated by godefs and the types file (see above).
|
|
||||||
86
vendor/golang.org/x/sys/unix/affinity_linux.go
generated
vendored
86
vendor/golang.org/x/sys/unix/affinity_linux.go
generated
vendored
@@ -1,86 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// CPU affinity functions
|
|
||||||
|
|
||||||
package unix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/bits"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
|
|
||||||
|
|
||||||
// CPUSet represents a CPU affinity mask.
|
|
||||||
type CPUSet [cpuSetSize]cpuMask
|
|
||||||
|
|
||||||
func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
|
|
||||||
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
|
|
||||||
if e != 0 {
|
|
||||||
return errnoErr(e)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
|
|
||||||
// If pid is 0 the calling thread is used.
|
|
||||||
func SchedGetaffinity(pid int, set *CPUSet) error {
|
|
||||||
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
|
|
||||||
// If pid is 0 the calling thread is used.
|
|
||||||
func SchedSetaffinity(pid int, set *CPUSet) error {
|
|
||||||
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zero clears the set s, so that it contains no CPUs.
|
|
||||||
func (s *CPUSet) Zero() {
|
|
||||||
for i := range s {
|
|
||||||
s[i] = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cpuBitsIndex(cpu int) int {
|
|
||||||
return cpu / _NCPUBITS
|
|
||||||
}
|
|
||||||
|
|
||||||
func cpuBitsMask(cpu int) cpuMask {
|
|
||||||
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set adds cpu to the set s.
|
|
||||||
func (s *CPUSet) Set(cpu int) {
|
|
||||||
i := cpuBitsIndex(cpu)
|
|
||||||
if i < len(s) {
|
|
||||||
s[i] |= cpuBitsMask(cpu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear removes cpu from the set s.
|
|
||||||
func (s *CPUSet) Clear(cpu int) {
|
|
||||||
i := cpuBitsIndex(cpu)
|
|
||||||
if i < len(s) {
|
|
||||||
s[i] &^= cpuBitsMask(cpu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSet reports whether cpu is in the set s.
|
|
||||||
func (s *CPUSet) IsSet(cpu int) bool {
|
|
||||||
i := cpuBitsIndex(cpu)
|
|
||||||
if i < len(s) {
|
|
||||||
return s[i]&cpuBitsMask(cpu) != 0
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count returns the number of CPUs in the set s.
|
|
||||||
func (s *CPUSet) Count() int {
|
|
||||||
c := 0
|
|
||||||
for _, b := range s {
|
|
||||||
c += bits.OnesCount64(uint64(b))
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
13
vendor/golang.org/x/sys/unix/aliases.go
generated
vendored
13
vendor/golang.org/x/sys/unix/aliases.go
generated
vendored
@@ -1,13 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
|
||||||
|
|
||||||
package unix
|
|
||||||
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
type Signal = syscall.Signal
|
|
||||||
type Errno = syscall.Errno
|
|
||||||
type SysProcAttr = syscall.SysProcAttr
|
|
||||||
17
vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
generated
vendored
17
vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
generated
vendored
@@ -1,17 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
|
|
||||||
//
|
|
||||||
|
|
||||||
TEXT ·syscall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·rawSyscall6(SB)
|
|
||||||
27
vendor/golang.org/x/sys/unix/asm_bsd_386.s
generated
vendored
27
vendor/golang.org/x/sys/unix/asm_bsd_386.s
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
// Copyright 2021 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build (freebsd || netbsd || openbsd) && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// System call support for 386 BSD
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
|
||||||
JMP syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
27
vendor/golang.org/x/sys/unix/asm_bsd_amd64.s
generated
vendored
27
vendor/golang.org/x/sys/unix/asm_bsd_amd64.s
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
// Copyright 2021 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// System call support for AMD64 BSD
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
|
||||||
JMP syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
27
vendor/golang.org/x/sys/unix/asm_bsd_arm.s
generated
vendored
27
vendor/golang.org/x/sys/unix/asm_bsd_arm.s
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
// Copyright 2021 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build (freebsd || netbsd || openbsd) && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// System call support for ARM BSD
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
|
||||||
B syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
|
||||||
B syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
|
||||||
B syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
|
||||||
B syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
|
||||||
B syscall·RawSyscall6(SB)
|
|
||||||
27
vendor/golang.org/x/sys/unix/asm_bsd_arm64.s
generated
vendored
27
vendor/golang.org/x/sys/unix/asm_bsd_arm64.s
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
// Copyright 2021 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build (darwin || freebsd || netbsd || openbsd) && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// System call support for ARM64 BSD
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
|
||||||
JMP syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
29
vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s
generated
vendored
29
vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s
generated
vendored
@@ -1,29 +0,0 @@
|
|||||||
// Copyright 2022 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build (darwin || freebsd || netbsd || openbsd) && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System call support for ppc64, BSD
|
|
||||||
//
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
|
||||||
JMP syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
27
vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s
generated
vendored
27
vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
// Copyright 2021 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build (darwin || freebsd || netbsd || openbsd) && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// System call support for RISCV64 BSD
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
|
||||||
JMP syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
65
vendor/golang.org/x/sys/unix/asm_linux_386.s
generated
vendored
65
vendor/golang.org/x/sys/unix/asm_linux_386.s
generated
vendored
@@ -1,65 +0,0 @@
|
|||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for 386, Linux
|
|
||||||
//
|
|
||||||
|
|
||||||
// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
|
|
||||||
// instead of the glibc-specific "CALL 0x10(GS)".
|
|
||||||
#define INVOKE_SYSCALL INT $0x80
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
|
|
||||||
CALL runtime·entersyscall(SB)
|
|
||||||
MOVL trap+0(FP), AX // syscall entry
|
|
||||||
MOVL a1+4(FP), BX
|
|
||||||
MOVL a2+8(FP), CX
|
|
||||||
MOVL a3+12(FP), DX
|
|
||||||
MOVL $0, SI
|
|
||||||
MOVL $0, DI
|
|
||||||
INVOKE_SYSCALL
|
|
||||||
MOVL AX, r1+16(FP)
|
|
||||||
MOVL DX, r2+20(FP)
|
|
||||||
CALL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
|
|
||||||
MOVL trap+0(FP), AX // syscall entry
|
|
||||||
MOVL a1+4(FP), BX
|
|
||||||
MOVL a2+8(FP), CX
|
|
||||||
MOVL a3+12(FP), DX
|
|
||||||
MOVL $0, SI
|
|
||||||
MOVL $0, DI
|
|
||||||
INVOKE_SYSCALL
|
|
||||||
MOVL AX, r1+16(FP)
|
|
||||||
MOVL DX, r2+20(FP)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·socketcall(SB),NOSPLIT,$0-36
|
|
||||||
JMP syscall·socketcall(SB)
|
|
||||||
|
|
||||||
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
|
|
||||||
JMP syscall·rawsocketcall(SB)
|
|
||||||
|
|
||||||
TEXT ·seek(SB),NOSPLIT,$0-28
|
|
||||||
JMP syscall·seek(SB)
|
|
||||||
57
vendor/golang.org/x/sys/unix/asm_linux_amd64.s
generated
vendored
57
vendor/golang.org/x/sys/unix/asm_linux_amd64.s
generated
vendored
@@ -1,57 +0,0 @@
|
|||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for AMD64, Linux
|
|
||||||
//
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
CALL runtime·entersyscall(SB)
|
|
||||||
MOVQ a1+8(FP), DI
|
|
||||||
MOVQ a2+16(FP), SI
|
|
||||||
MOVQ a3+24(FP), DX
|
|
||||||
MOVQ $0, R10
|
|
||||||
MOVQ $0, R8
|
|
||||||
MOVQ $0, R9
|
|
||||||
MOVQ trap+0(FP), AX // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVQ AX, r1+32(FP)
|
|
||||||
MOVQ DX, r2+40(FP)
|
|
||||||
CALL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
MOVQ a1+8(FP), DI
|
|
||||||
MOVQ a2+16(FP), SI
|
|
||||||
MOVQ a3+24(FP), DX
|
|
||||||
MOVQ $0, R10
|
|
||||||
MOVQ $0, R8
|
|
||||||
MOVQ $0, R9
|
|
||||||
MOVQ trap+0(FP), AX // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVQ AX, r1+32(FP)
|
|
||||||
MOVQ DX, r2+40(FP)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
|
|
||||||
JMP syscall·gettimeofday(SB)
|
|
||||||
56
vendor/golang.org/x/sys/unix/asm_linux_arm.s
generated
vendored
56
vendor/golang.org/x/sys/unix/asm_linux_arm.s
generated
vendored
@@ -1,56 +0,0 @@
|
|||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for arm, Linux
|
|
||||||
//
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
|
||||||
B syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
|
||||||
B syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
|
|
||||||
BL runtime·entersyscall(SB)
|
|
||||||
MOVW trap+0(FP), R7
|
|
||||||
MOVW a1+4(FP), R0
|
|
||||||
MOVW a2+8(FP), R1
|
|
||||||
MOVW a3+12(FP), R2
|
|
||||||
MOVW $0, R3
|
|
||||||
MOVW $0, R4
|
|
||||||
MOVW $0, R5
|
|
||||||
SWI $0
|
|
||||||
MOVW R0, r1+16(FP)
|
|
||||||
MOVW $0, R0
|
|
||||||
MOVW R0, r2+20(FP)
|
|
||||||
BL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
|
||||||
B syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
|
||||||
B syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
|
|
||||||
MOVW trap+0(FP), R7 // syscall entry
|
|
||||||
MOVW a1+4(FP), R0
|
|
||||||
MOVW a2+8(FP), R1
|
|
||||||
MOVW a3+12(FP), R2
|
|
||||||
SWI $0
|
|
||||||
MOVW R0, r1+16(FP)
|
|
||||||
MOVW $0, R0
|
|
||||||
MOVW R0, r2+20(FP)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·seek(SB),NOSPLIT,$0-28
|
|
||||||
B syscall·seek(SB)
|
|
||||||
50
vendor/golang.org/x/sys/unix/asm_linux_arm64.s
generated
vendored
50
vendor/golang.org/x/sys/unix/asm_linux_arm64.s
generated
vendored
@@ -1,50 +0,0 @@
|
|||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build linux && arm64 && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
B syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
B syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
BL runtime·entersyscall(SB)
|
|
||||||
MOVD a1+8(FP), R0
|
|
||||||
MOVD a2+16(FP), R1
|
|
||||||
MOVD a3+24(FP), R2
|
|
||||||
MOVD $0, R3
|
|
||||||
MOVD $0, R4
|
|
||||||
MOVD $0, R5
|
|
||||||
MOVD trap+0(FP), R8 // syscall entry
|
|
||||||
SVC
|
|
||||||
MOVD R0, r1+32(FP) // r1
|
|
||||||
MOVD R1, r2+40(FP) // r2
|
|
||||||
BL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
B syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
B syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
MOVD a1+8(FP), R0
|
|
||||||
MOVD a2+16(FP), R1
|
|
||||||
MOVD a3+24(FP), R2
|
|
||||||
MOVD $0, R3
|
|
||||||
MOVD $0, R4
|
|
||||||
MOVD $0, R5
|
|
||||||
MOVD trap+0(FP), R8 // syscall entry
|
|
||||||
SVC
|
|
||||||
MOVD R0, r1+32(FP)
|
|
||||||
MOVD R1, r2+40(FP)
|
|
||||||
RET
|
|
||||||
51
vendor/golang.org/x/sys/unix/asm_linux_loong64.s
generated
vendored
51
vendor/golang.org/x/sys/unix/asm_linux_loong64.s
generated
vendored
@@ -1,51 +0,0 @@
|
|||||||
// Copyright 2022 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build linux && loong64 && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
JAL runtime·entersyscall(SB)
|
|
||||||
MOVV a1+8(FP), R4
|
|
||||||
MOVV a2+16(FP), R5
|
|
||||||
MOVV a3+24(FP), R6
|
|
||||||
MOVV R0, R7
|
|
||||||
MOVV R0, R8
|
|
||||||
MOVV R0, R9
|
|
||||||
MOVV trap+0(FP), R11 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVV R4, r1+32(FP)
|
|
||||||
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
|
|
||||||
JAL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
MOVV a1+8(FP), R4
|
|
||||||
MOVV a2+16(FP), R5
|
|
||||||
MOVV a3+24(FP), R6
|
|
||||||
MOVV R0, R7
|
|
||||||
MOVV R0, R8
|
|
||||||
MOVV R0, R9
|
|
||||||
MOVV trap+0(FP), R11 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVV R4, r1+32(FP)
|
|
||||||
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
|
|
||||||
RET
|
|
||||||
54
vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
generated
vendored
54
vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
generated
vendored
@@ -1,54 +0,0 @@
|
|||||||
// Copyright 2015 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build linux && (mips64 || mips64le) && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for mips64, Linux
|
|
||||||
//
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
JAL runtime·entersyscall(SB)
|
|
||||||
MOVV a1+8(FP), R4
|
|
||||||
MOVV a2+16(FP), R5
|
|
||||||
MOVV a3+24(FP), R6
|
|
||||||
MOVV R0, R7
|
|
||||||
MOVV R0, R8
|
|
||||||
MOVV R0, R9
|
|
||||||
MOVV trap+0(FP), R2 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVV R2, r1+32(FP)
|
|
||||||
MOVV R3, r2+40(FP)
|
|
||||||
JAL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
MOVV a1+8(FP), R4
|
|
||||||
MOVV a2+16(FP), R5
|
|
||||||
MOVV a3+24(FP), R6
|
|
||||||
MOVV R0, R7
|
|
||||||
MOVV R0, R8
|
|
||||||
MOVV R0, R9
|
|
||||||
MOVV trap+0(FP), R2 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVV R2, r1+32(FP)
|
|
||||||
MOVV R3, r2+40(FP)
|
|
||||||
RET
|
|
||||||
52
vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
generated
vendored
52
vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
generated
vendored
@@ -1,52 +0,0 @@
|
|||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build linux && (mips || mipsle) && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for mips, Linux
|
|
||||||
//
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
|
||||||
JMP syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
|
|
||||||
JAL runtime·entersyscall(SB)
|
|
||||||
MOVW a1+4(FP), R4
|
|
||||||
MOVW a2+8(FP), R5
|
|
||||||
MOVW a3+12(FP), R6
|
|
||||||
MOVW R0, R7
|
|
||||||
MOVW trap+0(FP), R2 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVW R2, r1+16(FP) // r1
|
|
||||||
MOVW R3, r2+20(FP) // r2
|
|
||||||
JAL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
|
|
||||||
MOVW a1+4(FP), R4
|
|
||||||
MOVW a2+8(FP), R5
|
|
||||||
MOVW a3+12(FP), R6
|
|
||||||
MOVW trap+0(FP), R2 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVW R2, r1+16(FP)
|
|
||||||
MOVW R3, r2+20(FP)
|
|
||||||
RET
|
|
||||||
42
vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
generated
vendored
42
vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
generated
vendored
@@ -1,42 +0,0 @@
|
|||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build linux && (ppc64 || ppc64le) && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for ppc64, Linux
|
|
||||||
//
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
BL runtime·entersyscall(SB)
|
|
||||||
MOVD a1+8(FP), R3
|
|
||||||
MOVD a2+16(FP), R4
|
|
||||||
MOVD a3+24(FP), R5
|
|
||||||
MOVD R0, R6
|
|
||||||
MOVD R0, R7
|
|
||||||
MOVD R0, R8
|
|
||||||
MOVD trap+0(FP), R9 // syscall entry
|
|
||||||
SYSCALL R9
|
|
||||||
MOVD R3, r1+32(FP)
|
|
||||||
MOVD R4, r2+40(FP)
|
|
||||||
BL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
MOVD a1+8(FP), R3
|
|
||||||
MOVD a2+16(FP), R4
|
|
||||||
MOVD a3+24(FP), R5
|
|
||||||
MOVD R0, R6
|
|
||||||
MOVD R0, R7
|
|
||||||
MOVD R0, R8
|
|
||||||
MOVD trap+0(FP), R9 // syscall entry
|
|
||||||
SYSCALL R9
|
|
||||||
MOVD R3, r1+32(FP)
|
|
||||||
MOVD R4, r2+40(FP)
|
|
||||||
RET
|
|
||||||
47
vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
generated
vendored
47
vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
generated
vendored
@@ -1,47 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build riscv64 && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for linux/riscv64.
|
|
||||||
//
|
|
||||||
// Where available, just jump to package syscall's implementation of
|
|
||||||
// these functions.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
CALL runtime·entersyscall(SB)
|
|
||||||
MOV a1+8(FP), A0
|
|
||||||
MOV a2+16(FP), A1
|
|
||||||
MOV a3+24(FP), A2
|
|
||||||
MOV trap+0(FP), A7 // syscall entry
|
|
||||||
ECALL
|
|
||||||
MOV A0, r1+32(FP) // r1
|
|
||||||
MOV A1, r2+40(FP) // r2
|
|
||||||
CALL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
MOV a1+8(FP), A0
|
|
||||||
MOV a2+16(FP), A1
|
|
||||||
MOV a3+24(FP), A2
|
|
||||||
MOV trap+0(FP), A7 // syscall entry
|
|
||||||
ECALL
|
|
||||||
MOV A0, r1+32(FP)
|
|
||||||
MOV A1, r2+40(FP)
|
|
||||||
RET
|
|
||||||
54
vendor/golang.org/x/sys/unix/asm_linux_s390x.s
generated
vendored
54
vendor/golang.org/x/sys/unix/asm_linux_s390x.s
generated
vendored
@@ -1,54 +0,0 @@
|
|||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build linux && s390x && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for s390x, Linux
|
|
||||||
//
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
BR syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
BR syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
BL runtime·entersyscall(SB)
|
|
||||||
MOVD a1+8(FP), R2
|
|
||||||
MOVD a2+16(FP), R3
|
|
||||||
MOVD a3+24(FP), R4
|
|
||||||
MOVD $0, R5
|
|
||||||
MOVD $0, R6
|
|
||||||
MOVD $0, R7
|
|
||||||
MOVD trap+0(FP), R1 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVD R2, r1+32(FP)
|
|
||||||
MOVD R3, r2+40(FP)
|
|
||||||
BL runtime·exitsyscall(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
BR syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
BR syscall·RawSyscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
|
||||||
MOVD a1+8(FP), R2
|
|
||||||
MOVD a2+16(FP), R3
|
|
||||||
MOVD a3+24(FP), R4
|
|
||||||
MOVD $0, R5
|
|
||||||
MOVD $0, R6
|
|
||||||
MOVD $0, R7
|
|
||||||
MOVD trap+0(FP), R1 // syscall entry
|
|
||||||
SYSCALL
|
|
||||||
MOVD R2, r1+32(FP)
|
|
||||||
MOVD R3, r2+40(FP)
|
|
||||||
RET
|
|
||||||
29
vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
generated
vendored
29
vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
generated
vendored
@@ -1,29 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System call support for mips64, OpenBSD
|
|
||||||
//
|
|
||||||
|
|
||||||
// Just jump to package syscall's implementation for all these functions.
|
|
||||||
// The runtime may know about them.
|
|
||||||
|
|
||||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·Syscall(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·Syscall6(SB)
|
|
||||||
|
|
||||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
|
||||||
JMP syscall·Syscall9(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
|
||||||
JMP syscall·RawSyscall(SB)
|
|
||||||
|
|
||||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
|
||||||
JMP syscall·RawSyscall6(SB)
|
|
||||||
17
vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
generated
vendored
17
vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
generated
vendored
@@ -1,17 +0,0 @@
|
|||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go
|
|
||||||
//
|
|
||||||
|
|
||||||
TEXT ·sysvicall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·sysvicall6(SB)
|
|
||||||
|
|
||||||
TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88
|
|
||||||
JMP syscall·rawSysvicall6(SB)
|
|
||||||
382
vendor/golang.org/x/sys/unix/asm_zos_s390x.s
generated
vendored
382
vendor/golang.org/x/sys/unix/asm_zos_s390x.s
generated
vendored
@@ -1,382 +0,0 @@
|
|||||||
// Copyright 2020 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build zos && s390x && gc
|
|
||||||
|
|
||||||
#include "textflag.h"
|
|
||||||
|
|
||||||
#define PSALAA 1208(R0)
|
|
||||||
#define GTAB64(x) 80(x)
|
|
||||||
#define LCA64(x) 88(x)
|
|
||||||
#define SAVSTACK_ASYNC(x) 336(x) // in the LCA
|
|
||||||
#define CAA(x) 8(x)
|
|
||||||
#define CEECAATHDID(x) 976(x) // in the CAA
|
|
||||||
#define EDCHPXV(x) 1016(x) // in the CAA
|
|
||||||
#define GOCB(x) 1104(x) // in the CAA
|
|
||||||
|
|
||||||
// SS_*, where x=SAVSTACK_ASYNC
|
|
||||||
#define SS_LE(x) 0(x)
|
|
||||||
#define SS_GO(x) 8(x)
|
|
||||||
#define SS_ERRNO(x) 16(x)
|
|
||||||
#define SS_ERRNOJR(x) 20(x)
|
|
||||||
|
|
||||||
// Function Descriptor Offsets
|
|
||||||
#define __errno 0x156*16
|
|
||||||
#define __err2ad 0x16C*16
|
|
||||||
|
|
||||||
// Call Instructions
|
|
||||||
#define LE_CALL BYTE $0x0D; BYTE $0x76 // BL R7, R6
|
|
||||||
#define SVC_LOAD BYTE $0x0A; BYTE $0x08 // SVC 08 LOAD
|
|
||||||
#define SVC_DELETE BYTE $0x0A; BYTE $0x09 // SVC 09 DELETE
|
|
||||||
|
|
||||||
DATA zosLibVec<>(SB)/8, $0
|
|
||||||
GLOBL zosLibVec<>(SB), NOPTR, $8
|
|
||||||
|
|
||||||
TEXT ·initZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
|
|
||||||
MOVW PSALAA, R8
|
|
||||||
MOVD LCA64(R8), R8
|
|
||||||
MOVD CAA(R8), R8
|
|
||||||
MOVD EDCHPXV(R8), R8
|
|
||||||
MOVD R8, zosLibVec<>(SB)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·GetZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
|
|
||||||
MOVD zosLibVec<>(SB), R8
|
|
||||||
MOVD R8, ret+0(FP)
|
|
||||||
RET
|
|
||||||
|
|
||||||
TEXT ·clearErrno(SB), NOSPLIT, $0-0
|
|
||||||
BL addrerrno<>(SB)
|
|
||||||
MOVD $0, 0(R3)
|
|
||||||
RET
|
|
||||||
|
|
||||||
// Returns the address of errno in R3.
|
|
||||||
TEXT addrerrno<>(SB), NOSPLIT|NOFRAME, $0-0
|
|
||||||
// Get library control area (LCA).
|
|
||||||
MOVW PSALAA, R8
|
|
||||||
MOVD LCA64(R8), R8
|
|
||||||
|
|
||||||
// Get __errno FuncDesc.
|
|
||||||
MOVD CAA(R8), R9
|
|
||||||
MOVD EDCHPXV(R9), R9
|
|
||||||
ADD $(__errno), R9
|
|
||||||
LMG 0(R9), R5, R6
|
|
||||||
|
|
||||||
// Switch to saved LE stack.
|
|
||||||
MOVD SAVSTACK_ASYNC(R8), R9
|
|
||||||
MOVD 0(R9), R4
|
|
||||||
MOVD $0, 0(R9)
|
|
||||||
|
|
||||||
// Call __errno function.
|
|
||||||
LE_CALL
|
|
||||||
NOPH
|
|
||||||
|
|
||||||
// Switch back to Go stack.
|
|
||||||
XOR R0, R0 // Restore R0 to $0.
|
|
||||||
MOVD R4, 0(R9) // Save stack pointer.
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64)
|
|
||||||
TEXT ·svcCall(SB), NOSPLIT, $0
|
|
||||||
BL runtime·save_g(SB) // Save g and stack pointer
|
|
||||||
MOVW PSALAA, R8
|
|
||||||
MOVD LCA64(R8), R8
|
|
||||||
MOVD SAVSTACK_ASYNC(R8), R9
|
|
||||||
MOVD R15, 0(R9)
|
|
||||||
|
|
||||||
MOVD argv+8(FP), R1 // Move function arguments into registers
|
|
||||||
MOVD dsa+16(FP), g
|
|
||||||
MOVD fnptr+0(FP), R15
|
|
||||||
|
|
||||||
BYTE $0x0D // Branch to function
|
|
||||||
BYTE $0xEF
|
|
||||||
|
|
||||||
BL runtime·load_g(SB) // Restore g and stack pointer
|
|
||||||
MOVW PSALAA, R8
|
|
||||||
MOVD LCA64(R8), R8
|
|
||||||
MOVD SAVSTACK_ASYNC(R8), R9
|
|
||||||
MOVD 0(R9), R15
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func svcLoad(name *byte) unsafe.Pointer
|
|
||||||
TEXT ·svcLoad(SB), NOSPLIT, $0
|
|
||||||
MOVD R15, R2 // Save go stack pointer
|
|
||||||
MOVD name+0(FP), R0 // Move SVC args into registers
|
|
||||||
MOVD $0x80000000, R1
|
|
||||||
MOVD $0, R15
|
|
||||||
SVC_LOAD
|
|
||||||
MOVW R15, R3 // Save return code from SVC
|
|
||||||
MOVD R2, R15 // Restore go stack pointer
|
|
||||||
CMP R3, $0 // Check SVC return code
|
|
||||||
BNE error
|
|
||||||
|
|
||||||
MOVD $-2, R3 // Reset last bit of entry point to zero
|
|
||||||
AND R0, R3
|
|
||||||
MOVD R3, ret+8(FP) // Return entry point returned by SVC
|
|
||||||
CMP R0, R3 // Check if last bit of entry point was set
|
|
||||||
BNE done
|
|
||||||
|
|
||||||
MOVD R15, R2 // Save go stack pointer
|
|
||||||
MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08)
|
|
||||||
SVC_DELETE
|
|
||||||
MOVD R2, R15 // Restore go stack pointer
|
|
||||||
|
|
||||||
error:
|
|
||||||
MOVD $0, ret+8(FP) // Return 0 on failure
|
|
||||||
|
|
||||||
done:
|
|
||||||
XOR R0, R0 // Reset r0 to 0
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func svcUnload(name *byte, fnptr unsafe.Pointer) int64
|
|
||||||
TEXT ·svcUnload(SB), NOSPLIT, $0
|
|
||||||
MOVD R15, R2 // Save go stack pointer
|
|
||||||
MOVD name+0(FP), R0 // Move SVC args into registers
|
|
||||||
MOVD fnptr+8(FP), R15
|
|
||||||
SVC_DELETE
|
|
||||||
XOR R0, R0 // Reset r0 to 0
|
|
||||||
MOVD R15, R1 // Save SVC return code
|
|
||||||
MOVD R2, R15 // Restore go stack pointer
|
|
||||||
MOVD R1, ret+16(FP) // Return SVC return code
|
|
||||||
RET
|
|
||||||
|
|
||||||
// func gettid() uint64
|
|
||||||
TEXT ·gettid(SB), NOSPLIT, $0
|
|
||||||
// Get library control area (LCA).
|
|
||||||
MOVW PSALAA, R8
|
|
||||||
MOVD LCA64(R8), R8
|
|
||||||
|
|
||||||
// Get CEECAATHDID
|
|
||||||
MOVD CAA(R8), R9
|
|
||||||
MOVD CEECAATHDID(R9), R9
|
|
||||||
MOVD R9, ret+0(FP)
|
|
||||||
|
|
||||||
RET
|
|
||||||
|
|
||||||
//
|
|
||||||
// Call LE function, if the return is -1
|
|
||||||
// errno and errno2 is retrieved
|
|
||||||
//
|
|
||||||
TEXT ·CallLeFuncWithErr(SB), NOSPLIT, $0
|
|
||||||
MOVW PSALAA, R8
|
|
||||||
MOVD LCA64(R8), R8
|
|
||||||
MOVD CAA(R8), R9
|
|
||||||
MOVD g, GOCB(R9)
|
|
||||||
|
|
||||||
// Restore LE stack.
|
|
||||||
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
|
|
||||||
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
|
|
||||||
|
|
||||||
MOVD parms_base+8(FP), R7 // R7 -> argument array
|
|
||||||
MOVD parms_len+16(FP), R8 // R8 number of arguments
|
|
||||||
|
|
||||||
// arg 1 ---> R1
|
|
||||||
CMP R8, $0
|
|
||||||
BEQ docall
|
|
||||||
SUB $1, R8
|
|
||||||
MOVD 0(R7), R1
|
|
||||||
|
|
||||||
// arg 2 ---> R2
|
|
||||||
CMP R8, $0
|
|
||||||
BEQ docall
|
|
||||||
SUB $1, R8
|
|
||||||
ADD $8, R7
|
|
||||||
MOVD 0(R7), R2
|
|
||||||
|
|
||||||
// arg 3 --> R3
|
|
||||||
CMP R8, $0
|
|
||||||
BEQ docall
|
|
||||||
SUB $1, R8
|
|
||||||
ADD $8, R7
|
|
||||||
MOVD 0(R7), R3
|
|
||||||
|
|
||||||
CMP R8, $0
|
|
||||||
BEQ docall
|
|
||||||
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
|
|
||||||
|
|
||||||
repeat:
|
|
||||||
ADD $8, R7
|
|
||||||
MOVD 0(R7), R0 // advance arg pointer by 8 byte
|
|
||||||
ADD $8, R6 // advance LE argument address by 8 byte
|
|
||||||
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
|
|
||||||
SUB $1, R8
|
|
||||||
CMP R8, $0
|
|
||||||
BNE repeat
|
|
||||||
|
|
||||||
docall:
|
|
||||||
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
|
|
||||||
LMG 0(R8), R5, R6
|
|
||||||
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
|
|
||||||
LE_CALL // balr R7, R6 (return #1)
|
|
||||||
NOPH
|
|
||||||
MOVD R3, ret+32(FP)
|
|
||||||
CMP R3, $-1 // compare result to -1
|
|
||||||
BNE done
|
|
||||||
|
|
||||||
// retrieve errno and errno2
|
|
||||||
MOVD zosLibVec<>(SB), R8
|
|
||||||
ADD $(__errno), R8
|
|
||||||
LMG 0(R8), R5, R6
|
|
||||||
LE_CALL // balr R7, R6 __errno (return #3)
|
|
||||||
NOPH
|
|
||||||
MOVWZ 0(R3), R3
|
|
||||||
MOVD R3, err+48(FP)
|
|
||||||
MOVD zosLibVec<>(SB), R8
|
|
||||||
ADD $(__err2ad), R8
|
|
||||||
LMG 0(R8), R5, R6
|
|
||||||
LE_CALL // balr R7, R6 __err2ad (return #2)
|
|
||||||
NOPH
|
|
||||||
MOVW (R3), R2 // retrieve errno2
|
|
||||||
MOVD R2, errno2+40(FP) // store in return area
|
|
||||||
|
|
||||||
done:
|
|
||||||
MOVD R4, 0(R9) // Save stack pointer.
|
|
||||||
RET
|
|
||||||
|
|
||||||
//
|
|
||||||
// Call LE function, if the return is 0
|
|
||||||
// errno and errno2 is retrieved
|
|
||||||
//
|
|
||||||
TEXT ·CallLeFuncWithPtrReturn(SB), NOSPLIT, $0
|
|
||||||
MOVW PSALAA, R8
|
|
||||||
MOVD LCA64(R8), R8
|
|
||||||
MOVD CAA(R8), R9
|
|
||||||
MOVD g, GOCB(R9)
|
|
||||||
|
|
||||||
// Restore LE stack.
|
|
||||||
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
|
|
||||||
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
|
|
||||||
|
|
||||||
MOVD parms_base+8(FP), R7 // R7 -> argument array
|
|
||||||
MOVD parms_len+16(FP), R8 // R8 number of arguments
|
|
||||||
|
|
||||||
// arg 1 ---> R1
|
|
||||||
CMP R8, $0
|
|
||||||
BEQ docall
|
|
||||||
SUB $1, R8
|
|
||||||
MOVD 0(R7), R1
|
|
||||||
|
|
||||||
// arg 2 ---> R2
|
|
||||||
CMP R8, $0
|
|
||||||
BEQ docall
|
|
||||||
SUB $1, R8
|
|
||||||
ADD $8, R7
|
|
||||||
MOVD 0(R7), R2
|
|
||||||
|
|
||||||
// arg 3 --> R3
|
|
||||||
CMP R8, $0
|
|
||||||
BEQ docall
|
|
||||||
SUB $1, R8
|
|
||||||
ADD $8, R7
|
|
||||||
MOVD 0(R7), R3
|
|
||||||
|
|
||||||
CMP R8, $0
|
|
||||||
BEQ docall
|
|
||||||
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
|
|
||||||
|
|
||||||
repeat:
|
|
||||||
ADD $8, R7
|
|
||||||
MOVD 0(R7), R0 // advance arg pointer by 8 byte
|
|
||||||
ADD $8, R6 // advance LE argument address by 8 byte
|
|
||||||
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
|
|
||||||
SUB $1, R8
|
|
||||||
CMP R8, $0
|
|
||||||
BNE repeat
|
|
||||||
|
|
||||||
docall:
|
|
||||||
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
|
|
||||||
LMG 0(R8), R5, R6
|
|
||||||
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
|
|
||||||
LE_CALL // balr R7, R6 (return #1)
|
|
||||||
NOPH
|
|
||||||
MOVD R3, ret+32(FP)
|
|
||||||
CMP R3, $0 // compare result to 0
|
|
||||||
BNE done
|
|
||||||
|
|
||||||
// retrieve errno and errno2
|
|
||||||
MOVD zosLibVec<>(SB), R8
|
|
||||||
ADD $(__errno), R8
|
|
||||||
LMG 0(R8), R5, R6
|
|
||||||
LE_CALL // balr R7, R6 __errno (return #3)
|
|
||||||
NOPH
|
|
||||||
MOVWZ 0(R3), R3
|
|
||||||
MOVD R3, err+48(FP)
|
|
||||||
MOVD zosLibVec<>(SB), R8
|
|
||||||
ADD $(__err2ad), R8
|
|
||||||
LMG 0(R8), R5, R6
|
|
||||||
LE_CALL // balr R7, R6 __err2ad (return #2)
|
|
||||||
NOPH
|
|
||||||
MOVW (R3), R2 // retrieve errno2
|
|
||||||
MOVD R2, errno2+40(FP) // store in return area
|
|
||||||
XOR R2, R2
|
|
||||||
MOVWZ R2, (R3) // clear errno2
|
|
||||||
|
|
||||||
done:
|
|
||||||
MOVD R4, 0(R9) // Save stack pointer.
|
|
||||||
RET
|
|
||||||
|
|
||||||
//
|
|
||||||
// function to test if a pointer can be safely dereferenced (content read)
|
|
||||||
// return 0 for succces
|
|
||||||
//
|
|
||||||
TEXT ·ptrtest(SB), NOSPLIT, $0-16
|
|
||||||
MOVD arg+0(FP), R10 // test pointer in R10
|
|
||||||
|
|
||||||
// set up R2 to point to CEECAADMC
|
|
||||||
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
|
|
||||||
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
|
|
||||||
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
|
|
||||||
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
|
|
||||||
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
|
|
||||||
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
|
|
||||||
|
|
||||||
// set up R5 to point to the "shunt" path which set 1 to R3 (failure)
|
|
||||||
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
|
|
||||||
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
|
|
||||||
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
|
|
||||||
|
|
||||||
// if r3 is not zero (failed) then branch to finish
|
|
||||||
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
|
|
||||||
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
|
|
||||||
|
|
||||||
// stomic store shunt address in R5 into CEECAADMC
|
|
||||||
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
|
|
||||||
|
|
||||||
// now try reading from the test pointer in R10, if it fails it branches to the "lghi" instruction above
|
|
||||||
BYTE $0xE3; BYTE $0x9A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 9,0(10)
|
|
||||||
|
|
||||||
// finish here, restore 0 into CEECAADMC
|
|
||||||
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
|
|
||||||
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
|
|
||||||
MOVD R3, ret+8(FP) // result in R3
|
|
||||||
RET
|
|
||||||
|
|
||||||
//
|
|
||||||
// function to test if a untptr can be loaded from a pointer
|
|
||||||
// return 1: the 8-byte content
|
|
||||||
// 2: 0 for success, 1 for failure
|
|
||||||
//
|
|
||||||
// func safeload(ptr uintptr) ( value uintptr, error uintptr)
|
|
||||||
TEXT ·safeload(SB), NOSPLIT, $0-24
|
|
||||||
MOVD ptr+0(FP), R10 // test pointer in R10
|
|
||||||
MOVD $0x0, R6
|
|
||||||
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
|
|
||||||
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
|
|
||||||
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
|
|
||||||
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
|
|
||||||
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
|
|
||||||
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
|
|
||||||
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
|
|
||||||
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
|
|
||||||
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
|
|
||||||
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
|
|
||||||
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
|
|
||||||
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
|
|
||||||
BYTE $0xE3; BYTE $0x6A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 6,0(10)
|
|
||||||
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
|
|
||||||
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
|
|
||||||
MOVD R6, value+8(FP) // result in R6
|
|
||||||
MOVD R3, error+16(FP) // error in R3
|
|
||||||
RET
|
|
||||||
36
vendor/golang.org/x/sys/unix/auxv.go
generated
vendored
36
vendor/golang.org/x/sys/unix/auxv.go
generated
vendored
@@ -1,36 +0,0 @@
|
|||||||
// Copyright 2025 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
//go:build go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos)
|
|
||||||
|
|
||||||
package unix
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:linkname runtime_getAuxv runtime.getAuxv
|
|
||||||
func runtime_getAuxv() []uintptr
|
|
||||||
|
|
||||||
// Auxv returns the ELF auxiliary vector as a sequence of key/value pairs.
|
|
||||||
// The returned slice is always a fresh copy, owned by the caller.
|
|
||||||
// It returns an error on non-ELF platforms, or if the auxiliary vector cannot be accessed,
|
|
||||||
// which happens in some locked-down environments and build modes.
|
|
||||||
func Auxv() ([][2]uintptr, error) {
|
|
||||||
vec := runtime_getAuxv()
|
|
||||||
vecLen := len(vec)
|
|
||||||
|
|
||||||
if vecLen == 0 {
|
|
||||||
return nil, syscall.ENOENT
|
|
||||||
}
|
|
||||||
|
|
||||||
if vecLen%2 != 0 {
|
|
||||||
return nil, syscall.EINVAL
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make([]uintptr, vecLen)
|
|
||||||
copy(result, vec)
|
|
||||||
return unsafe.Slice((*[2]uintptr)(unsafe.Pointer(&result[0])), vecLen/2), nil
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user