[WIP] update linter rules, fix many linter warnings
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@
|
|||||||
/data/cache
|
/data/cache
|
||||||
/aleesa-telegram-go
|
/aleesa-telegram-go
|
||||||
/*.log
|
/*.log
|
||||||
|
/*.bck.*
|
||||||
|
|||||||
743
.golangci.yml
743
.golangci.yml
@@ -1,28 +1,12 @@
|
|||||||
|
version: "2"
|
||||||
run:
|
run:
|
||||||
tests: false
|
go: "1.25"
|
||||||
skip-dirs:
|
|
||||||
- data
|
|
||||||
- vendor
|
|
||||||
modules-download-mode: readonly
|
modules-download-mode: readonly
|
||||||
|
tests: false
|
||||||
allow-parallel-runners: true
|
allow-parallel-runners: true
|
||||||
go: '1.21'
|
|
||||||
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
|
||||||
@@ -30,24 +14,30 @@ linters:
|
|||||||
- contextcheck
|
- contextcheck
|
||||||
- decorder
|
- decorder
|
||||||
- durationcheck
|
- durationcheck
|
||||||
|
- errcheck
|
||||||
- errchkjson
|
- errchkjson
|
||||||
- errorlint
|
- errorlint
|
||||||
- exhaustive
|
- exhaustive
|
||||||
- exportloopref
|
- exptostd
|
||||||
- gci
|
|
||||||
- ginkgolinter
|
- ginkgolinter
|
||||||
- gocheckcompilerdirectives
|
- gocheckcompilerdirectives
|
||||||
- gocritic
|
- gocritic
|
||||||
|
- godoclint
|
||||||
- godot
|
- godot
|
||||||
- gofmt
|
- godox
|
||||||
- goimports
|
- goprintffuncname
|
||||||
- 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
|
||||||
@@ -55,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
|
- whitespace
|
||||||
- wsl
|
- wsl_v5
|
||||||
|
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
|
||||||
|
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$
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
// Package main is the main package of aleesa-telegram-go.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -26,7 +26,7 @@ func init() {
|
|||||||
log.Fatalf("Unable to get current executable path: %s", err)
|
log.Fatalf("Unable to get current executable path: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
configJSONPath := fmt.Sprintf("%s/data/config.json", filepath.Dir(executablePath))
|
configJSONPath := filepath.Dir(executablePath) + "/data/config.json"
|
||||||
|
|
||||||
locations := []string{
|
locations := []string{
|
||||||
"~/.aleesa-telegram-go.json",
|
"~/.aleesa-telegram-go.json",
|
||||||
@@ -68,16 +68,15 @@ func main() {
|
|||||||
|
|
||||||
log.Init(tg.Config.Loglevel, logfile)
|
log.Init(tg.Config.Loglevel, logfile)
|
||||||
|
|
||||||
// Main context
|
|
||||||
var ctx = context.Background()
|
|
||||||
|
|
||||||
// Инициализируем redis-клиента.
|
// Инициализируем redis-клиента.
|
||||||
tg.RedisClient = redis.NewClient(&redis.Options{
|
tg.RedisClient = redis.NewClient(&redis.Options{
|
||||||
Addr: fmt.Sprintf("%s:%d", tg.Config.Redis.Server, tg.Config.Redis.Port),
|
Addr: fmt.Sprintf("%s:%d", tg.Config.Redis.Server, tg.Config.Redis.Port),
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Debugf("Lazy connect() to redis at %s:%d", tg.Config.Redis.Server, tg.Config.Redis.Port)
|
log.Debugf("Lazy connect() to redis at %s:%d", tg.Config.Redis.Server, tg.Config.Redis.Port)
|
||||||
tg.Subscriber = tg.RedisClient.Subscribe(ctx, tg.Config.Redis.MyChannel)
|
|
||||||
|
tg.Subscriber = tg.RedisClient.Subscribe(tg.Ctx, tg.Config.Redis.MyChannel)
|
||||||
|
|
||||||
redisMsgChan := tg.Subscriber.Channel()
|
redisMsgChan := tg.Subscriber.Channel()
|
||||||
|
|
||||||
// Самое время поставить траппер сигналов.
|
// Самое время поставить траппер сигналов.
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
|||||||
module aleesa-telegram-go
|
module aleesa-telegram-go
|
||||||
|
|
||||||
go 1.22
|
go 1.25
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/NicoNex/echotron/v3 v3.33.1
|
github.com/NicoNex/echotron/v3 v3.33.1
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package log wraps log/slog for more easier and convinient use.
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -11,17 +12,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler exposes slog handler struct.
|
var (
|
||||||
var Handler slog.Handler
|
// Handler exposes slog handler struct.
|
||||||
|
Handler slog.Handler
|
||||||
|
|
||||||
// Ctx log context. For now it is just sits here and do nothing.
|
// Ctx log context. For now it is just sits here and do nothing.
|
||||||
var Ctx = context.Background()
|
Ctx = context.Background()
|
||||||
|
|
||||||
// Writer go-writer eported for capturing other types of logs, even for std log go facility.
|
// Writer go-writer eported for capturing other types of logs, even for std log go facility.
|
||||||
var Writer io.Writer
|
Writer io.Writer
|
||||||
|
|
||||||
// reader is required for Writer to work properly. It is connected via io.Pipe() to Writer.
|
// reader is required for Writer to work properly. It is connected via io.Pipe() to Writer.
|
||||||
var reader io.Reader
|
reader io.Reader
|
||||||
|
)
|
||||||
|
|
||||||
// Init setup logger stuff.
|
// Init setup logger stuff.
|
||||||
// level can be error, warn, info, debug if something other supplied info level selected.
|
// level can be error, warn, info, debug if something other supplied info level selected.
|
||||||
@@ -29,7 +32,6 @@ var reader io.Reader
|
|||||||
func Init(level string, fileDescriptor *os.File) {
|
func Init(level string, fileDescriptor *os.File) {
|
||||||
var loglevel slog.Level
|
var loglevel slog.Level
|
||||||
|
|
||||||
// no panic, no trace.
|
|
||||||
switch level {
|
switch level {
|
||||||
case "debug":
|
case "debug":
|
||||||
loglevel = slog.LevelDebug
|
loglevel = slog.LevelDebug
|
||||||
@@ -48,18 +50,17 @@ func Init(level string, fileDescriptor *os.File) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts := &slog.HandlerOptions{ //nolint: exhaustruct
|
opts := &slog.HandlerOptions{ //nolint: exhaustruct
|
||||||
// Use the ReplaceAttr function on the handler options
|
// Use the ReplaceAttr function on the handler options to be able to replace any single attribute in the log
|
||||||
// to be able to replace any single attribute in the log output
|
// output.
|
||||||
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { //nolint: revive
|
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { //nolint: revive
|
||||||
// check that we are handling the time key
|
// Check that we are handling the time key.
|
||||||
if a.Key != slog.TimeKey {
|
if a.Key != slog.TimeKey {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
t := a.Value.Time()
|
t := a.Value.Time()
|
||||||
|
|
||||||
// change the value from a time.Time to a String
|
// Change the value from a time.Time to the String. The string has correct time format.
|
||||||
// where the string has the correct time format.
|
|
||||||
a.Value = slog.StringValue(t.Format(time.DateTime))
|
a.Value = slog.StringValue(t.Format(time.DateTime))
|
||||||
|
|
||||||
return a
|
return a
|
||||||
@@ -85,7 +86,7 @@ func readIoPipe() {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text() // Get the current line as a string
|
line := scanner.Text() // Get the current line as a string.
|
||||||
slog.Debug(line)
|
slog.Debug(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
// Package tg implements most of aleesa-telegram-go functionality.
|
||||||
package tg
|
package tg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/NicoNex/echotron/v3"
|
"github.com/NicoNex/echotron/v3"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
@@ -18,6 +20,7 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
switch {
|
switch {
|
||||||
case c == "admin" || c == "админ":
|
case c == "admin" || c == "админ":
|
||||||
answer = "```\n"
|
answer = "```\n"
|
||||||
|
|
||||||
answer += fmt.Sprintf("%sadmin censor - показать список состояния типов сообщений\n", Config.Csign)
|
answer += fmt.Sprintf("%sadmin censor - показать список состояния типов сообщений\n", Config.Csign)
|
||||||
answer += fmt.Sprintf("%sадмин ценз - показать список состояния типов сообщений\n", Config.Csign)
|
answer += fmt.Sprintf("%sадмин ценз - показать список состояния типов сообщений\n", Config.Csign)
|
||||||
answer += fmt.Sprintf("%sadmin censor type # - где 1 - вкл, 0 - выкл цензуры для означенного типа сообщений\n", Config.Csign)
|
answer += fmt.Sprintf("%sadmin censor type # - где 1 - вкл, 0 - выкл цензуры для означенного типа сообщений\n", Config.Csign)
|
||||||
@@ -64,67 +67,67 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
answer += "```"
|
answer += "```"
|
||||||
|
|
||||||
case regexp.MustCompile("^(admin|админ)[[:space:]](censor|ценз)$").MatchString(c):
|
case regexp.MustCompile("^(admin|админ)[[:space:]](censor|ценз)$").MatchString(c):
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "VoiceMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "VoiceMsg") == "1" {
|
||||||
answer += "Тип сообщения voice удаляется\n"
|
answer += "Тип сообщения voice удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения voice не удаляется\n"
|
answer += "Тип сообщения voice не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "AudioMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "AudioMsg") == "1" {
|
||||||
answer += "Тип сообщения audio удаляется\n"
|
answer += "Тип сообщения audio удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения audio не удаляется\n"
|
answer += "Тип сообщения audio не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "PhotoMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "PhotoMsg") == "1" {
|
||||||
answer += "Тип сообщения photo удаляется\n"
|
answer += "Тип сообщения photo удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения photo не удаляется\n"
|
answer += "Тип сообщения photo не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "VideoMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "VideoMsg") == "1" {
|
||||||
answer += "Тип сообщения video удаляется\n"
|
answer += "Тип сообщения video удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения video не удаляется\n"
|
answer += "Тип сообщения video не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "VideoNoteMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "VideoNoteMsg") == "1" {
|
||||||
answer += "Тип сообщения video_note удаляется\n"
|
answer += "Тип сообщения video_note удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения video_note не удаляется\n"
|
answer += "Тип сообщения video_note не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "AnimationMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "AnimationMsg") == "1" {
|
||||||
answer += "Тип сообщения animation удаляется\n"
|
answer += "Тип сообщения animation удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения animation не удаляется\n"
|
answer += "Тип сообщения animation не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "StickerMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "StickerMsg") == "1" {
|
||||||
answer += "Тип сообщения sticker удаляется\n"
|
answer += "Тип сообщения sticker удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения sticker не удаляется\n"
|
answer += "Тип сообщения sticker не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "DiceMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "DiceMsg") == "1" {
|
||||||
answer += "Тип сообщения dice удаляется\n"
|
answer += "Тип сообщения dice удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения dice не удаляется\n"
|
answer += "Тип сообщения dice не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GameMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GameMsg") == "1" {
|
||||||
answer += "Тип сообщения game удаляется\n"
|
answer += "Тип сообщения game удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения game не удаляется\n"
|
answer += "Тип сообщения game не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "PollMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "PollMsg") == "1" {
|
||||||
answer += "Тип сообщения poll удаляется\n"
|
answer += "Тип сообщения poll удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения poll не удаляется\n"
|
answer += "Тип сообщения poll не удаляется\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "DocumentMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "DocumentMsg") == "1" {
|
||||||
answer += "Тип сообщения document удаляется\n"
|
answer += "Тип сообщения document удаляется\n"
|
||||||
} else {
|
} else {
|
||||||
answer += "Тип сообщения document не удаляется\n"
|
answer += "Тип сообщения document не удаляется\n"
|
||||||
@@ -139,14 +142,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "voice":
|
case "voice":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "VoiceMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "VoiceMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с voice будут оставаться"
|
answer += "Теперь сообщения с voice будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "VoiceMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "VoiceMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,14 +162,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "audio":
|
case "audio":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "AudioMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "AudioMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с audio будут оставаться"
|
answer += "Теперь сообщения с audio будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "AudioMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "AudioMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,14 +182,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "photo":
|
case "photo":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "PhotoMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "PhotoMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с photo будут оставаться"
|
answer += "Теперь сообщения с photo будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "PhotoMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "PhotoMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,14 +202,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "video":
|
case "video":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "VideoMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "VideoMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с video будут оставаться"
|
answer += "Теперь сообщения с video будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "VideoMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "VideoMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,14 +222,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "video_note":
|
case "video_note":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "VideoNoteMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "VideoNoteMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с video_note будут оставаться"
|
answer += "Теперь сообщения с video_note будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "VideoNoteMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "VideoNoteMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,14 +242,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "animation":
|
case "animation":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "AnimationMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "AnimationMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с animation будут оставаться"
|
answer += "Теперь сообщения с animation будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "AnimationMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "AnimationMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,14 +262,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "sticker":
|
case "sticker":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "StickerMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "StickerMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с sticker будут оставаться"
|
answer += "Теперь сообщения с sticker будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "StickerMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "StickerMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,14 +282,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "dice":
|
case "dice":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "DiceMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "DiceMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с dice будут оставаться"
|
answer += "Теперь сообщения с dice будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "diceMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "diceMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,14 +302,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "game":
|
case "game":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GameMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GameMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с game будут оставаться"
|
answer += "Теперь сообщения с game будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GameMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GameMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,14 +322,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "poll":
|
case "poll":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "PollMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "PollMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с poll будут оставаться"
|
answer += "Теперь сообщения с poll будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "PollMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "PollMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,14 +342,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
case "document":
|
case "document":
|
||||||
switch cmdArray[3] {
|
switch cmdArray[3] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "DocumentMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "DocumentMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с document будут оставаться"
|
answer += "Теперь сообщения с document будут оставаться"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "DocumentMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "DocumentMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,7 +364,7 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case regexp.MustCompile("^(admin|админ)[[:space:]](fortune|фортунка)$").MatchString(c):
|
case regexp.MustCompile("^(admin|админ)[[:space:]](fortune|фортунка)$").MatchString(c):
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "FortuneMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "FortuneMsg") == "1" {
|
||||||
answer += "Фортунки с утра показываются"
|
answer += "Фортунки с утра показываются"
|
||||||
} else {
|
} else {
|
||||||
answer += "Фортунки с утра не показываются"
|
answer += "Фортунки с утра не показываются"
|
||||||
@@ -375,14 +378,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
// мы не сможем вытащить список чятиков.
|
// мы не сможем вытащить список чятиков.
|
||||||
switch cmdArray[2] {
|
switch cmdArray[2] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "FortuneMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "FortuneMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Теперь сообщения с фортункой будут отправляться с утра"
|
answer += "Теперь сообщения с фортункой будут отправляться с утра"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "FortuneMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "FortuneMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,7 +396,7 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case regexp.MustCompile("^(admin|админ)[[:space:]](greet|приветствие)$").MatchString(c):
|
case regexp.MustCompile("^(admin|админ)[[:space:]](greet|приветствие)$").MatchString(c):
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GreetMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GreetMsg") == "1" {
|
||||||
answer += "Приветствуем вновьприбывших участников чатика"
|
answer += "Приветствуем вновьприбывших участников чатика"
|
||||||
} else {
|
} else {
|
||||||
answer += "Не приветствуем вновьприбывших участников чатика"
|
answer += "Не приветствуем вновьприбывших участников чатика"
|
||||||
@@ -407,14 +410,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
// мы не сможем вытащить список чятиков.
|
// мы не сможем вытащить список чятиков.
|
||||||
switch cmdArray[2] {
|
switch cmdArray[2] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GreetMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GreetMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Будем приветствовать вновьприбывших участников чата"
|
answer += "Будем приветствовать вновьприбывших участников чата"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GreetMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GreetMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,7 +428,7 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case regexp.MustCompile("^(admin|админ)[[:space:]](goodbye|прощание)$").MatchString(c):
|
case regexp.MustCompile("^(admin|админ)[[:space:]](goodbye|прощание)$").MatchString(c):
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GoodbyeMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GoodbyeMsg") == "1" {
|
||||||
answer += "Прощаемся с ушедшими участниками чатика"
|
answer += "Прощаемся с ушедшими участниками чатика"
|
||||||
} else {
|
} else {
|
||||||
answer += "Не прощаемся с ушедшими участниками чатика"
|
answer += "Не прощаемся с ушедшими участниками чатика"
|
||||||
@@ -437,14 +440,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
|
|
||||||
switch cmdArray[2] {
|
switch cmdArray[2] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GoodbyeMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GoodbyeMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Будем прощаться с ушедшими участниками чата"
|
answer += "Будем прощаться с ушедшими участниками чата"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GoodbyeMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GoodbyeMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,14 +463,14 @@ func Admin(msg *echotron.Update) (bool, error) {
|
|||||||
|
|
||||||
switch cmdArray[2] {
|
switch cmdArray[2] {
|
||||||
case "1":
|
case "1":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "ChanMsg", "1"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "ChanMsg", "1"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
answer += "Будем удалять сообщения, написанные от имени канала"
|
answer += "Будем удалять сообщения, написанные от имени канала"
|
||||||
|
|
||||||
case "0":
|
case "0":
|
||||||
if err := SaveSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "ChanMsg", "0"); err != nil {
|
if err := SaveSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "ChanMsg", "0"); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package tg
|
package tg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"strconv"
|
||||||
|
|
||||||
"github.com/NicoNex/echotron/v3"
|
"github.com/NicoNex/echotron/v3"
|
||||||
)
|
)
|
||||||
@@ -10,10 +10,13 @@ import (
|
|||||||
// Непотребными могут быть аудиосообщения, аудиофайлы, видеосообщения, сообщения от имени других каналов итп.
|
// Непотребными могут быть аудиосообщения, аудиофайлы, видеосообщения, сообщения от имени других каналов итп.
|
||||||
// Это могут настроить админы чятика через команду !admin censor.
|
// Это могут настроить админы чятика через команду !admin censor.
|
||||||
func Censor(msg *echotron.Update) bool {
|
func Censor(msg *echotron.Update) bool {
|
||||||
result := false
|
var (
|
||||||
|
result bool
|
||||||
|
chatID = msg.ChatID()
|
||||||
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "VoiceMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "VoiceMsg") == "1":
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
// Предполагаем, что у voice-ов здесь всегда не ноль.
|
// Предполагаем, что у voice-ов здесь всегда не ноль.
|
||||||
@@ -23,7 +26,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "AudioMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "AudioMsg") == "1":
|
||||||
// Предполагаем, что у аудио здесь всегда не ноль.
|
// Предполагаем, что у аудио здесь всегда не ноль.
|
||||||
if msg.Message.Audio.Duration != 0 {
|
if msg.Message.Audio.Duration != 0 {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -31,7 +34,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "PhotoMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "PhotoMsg") == "1":
|
||||||
// Обычное сообщение не содержит фоток.
|
// Обычное сообщение не содержит фоток.
|
||||||
if len(msg.Message.Photo) != 0 {
|
if len(msg.Message.Photo) != 0 {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -39,7 +42,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "VideoMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "VideoMsg") == "1":
|
||||||
// Предполагаем, что у видео здесь всегда не ноль.
|
// Предполагаем, что у видео здесь всегда не ноль.
|
||||||
if msg.Message.Video.Duration != 0 {
|
if msg.Message.Video.Duration != 0 {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -47,7 +50,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "VideoNoteMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "VideoNoteMsg") == "1":
|
||||||
// Предполагаем, что у видео-заметки здесь всегда не ноль.
|
// Предполагаем, что у видео-заметки здесь всегда не ноль.
|
||||||
if msg.Message.VideoNote.Duration != 0 {
|
if msg.Message.VideoNote.Duration != 0 {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -55,7 +58,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "AnimationMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "AnimationMsg") == "1":
|
||||||
// Предполагаем, что у анимации здесь всегда не ноль.
|
// Предполагаем, что у анимации здесь всегда не ноль.
|
||||||
if msg.Message.Animation.Duration != 0 {
|
if msg.Message.Animation.Duration != 0 {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -63,7 +66,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "StickerMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "StickerMsg") == "1":
|
||||||
// Предполагаем, что FileID не пустое только у стикера.
|
// Предполагаем, что FileID не пустое только у стикера.
|
||||||
if msg.Message.Sticker.FileID != "" {
|
if msg.Message.Sticker.FileID != "" {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -71,7 +74,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "DiceMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "DiceMsg") == "1":
|
||||||
// Предполагаем, что Value > 0 только у дайса.
|
// Предполагаем, что Value > 0 только у дайса.
|
||||||
if msg.Message.Dice.Value != 0 {
|
if msg.Message.Dice.Value != 0 {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -79,7 +82,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "GameMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "GameMsg") == "1":
|
||||||
// Предполагаем, что title только у game-а.
|
// Предполагаем, что title только у game-а.
|
||||||
if msg.Message.Game.Title != "" {
|
if msg.Message.Game.Title != "" {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -87,7 +90,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "PollMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "PollMsg") == "1":
|
||||||
// Предполагаем, что title только у game-а.
|
// Предполагаем, что title только у game-а.
|
||||||
if msg.Message.Poll.Question != "" {
|
if msg.Message.Poll.Question != "" {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -95,7 +98,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "DocumentMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "DocumentMsg") == "1":
|
||||||
// Предполагаем, что FileID есть только у document-а.
|
// Предполагаем, что FileID есть только у document-а.
|
||||||
if msg.Message.Document.FileID != "" {
|
if msg.Message.Document.FileID != "" {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
@@ -107,7 +110,7 @@ func Censor(msg *echotron.Update) bool {
|
|||||||
// пидорство он будет удалять asap.
|
// пидорство он будет удалять asap.
|
||||||
// 136817688 - это специальный id пользователя, который принимает облик канала, на него можно нажать и попасть
|
// 136817688 - это специальный id пользователя, который принимает облик канала, на него можно нажать и попасть
|
||||||
// на рекламируемый канал.
|
// на рекламируемый канал.
|
||||||
case GetSetting(fmt.Sprintf("%d", msg.ChatID()), "ChanMsg") == "1":
|
case GetSetting(strconv.FormatInt(chatID, 10), "ChanMsg") == "1":
|
||||||
if msg.Message.From.ID == 136817688 {
|
if msg.Message.From.ID == 136817688 {
|
||||||
delMsg(msg)
|
delMsg(msg)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/NicoNex/echotron/v3"
|
"github.com/NicoNex/echotron/v3"
|
||||||
)
|
)
|
||||||
@@ -20,8 +22,8 @@ func cmdParser(me echotron.APIResponseUser, cmd *echotron.Update) (bool, error)
|
|||||||
|
|
||||||
smsg.From = "telegram"
|
smsg.From = "telegram"
|
||||||
smsg.Plugin = "telegram"
|
smsg.Plugin = "telegram"
|
||||||
smsg.Chatid = fmt.Sprintf("%d", cmd.Message.Chat.ID)
|
smsg.Chatid = strconv.FormatInt(cmd.Message.Chat.ID, 10)
|
||||||
smsg.Userid = fmt.Sprintf("%d", cmd.Message.From.ID)
|
smsg.Userid = strconv.FormatInt(cmd.Message.From.ID, 10)
|
||||||
smsg.Message = cmd.Message.Text
|
smsg.Message = cmd.Message.Text
|
||||||
smsg.Misc.Answer = 1
|
smsg.Misc.Answer = 1
|
||||||
|
|
||||||
@@ -60,12 +62,8 @@ func cmdParser(me echotron.APIResponseUser, cmd *echotron.Update) (bool, error)
|
|||||||
"рыба", "рыбка", "рыбалка", "karma", "карма", "fuck", "weather", "погода", "w", "п", "погодка", "погадка",
|
"рыба", "рыбка", "рыбалка", "karma", "карма", "fuck", "weather", "погода", "w", "п", "погодка", "погадка",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cmds {
|
if slices.Contains(cmds, command) {
|
||||||
if command == c {
|
bingo = true
|
||||||
bingo = true
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Не нашлось команды в одно слово. Поищем команды с одним аргументом.
|
// Не нашлось команды в одно слово. Поищем команды с одним аргументом.
|
||||||
@@ -103,20 +101,14 @@ func cmdParser(me echotron.APIResponseUser, cmd *echotron.Update) (bool, error)
|
|||||||
"dig", "копать", "fish", "fishing", "рыба", "рыбка", "рыбалка",
|
"dig", "копать", "fish", "fishing", "рыба", "рыбка", "рыбалка",
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cmds {
|
if slices.Contains(cmds, command) {
|
||||||
// В vscode возникает ошибка при использовании if-а.
|
smsg.Misc.Username = ConstructTelegramHighlightName(cmd.Message.From)
|
||||||
switch {
|
smsg.Misc.Msgformat = 1
|
||||||
case command == c:
|
|
||||||
smsg.Misc.Username = ConstructTelegramHighlightName(cmd.Message.From)
|
|
||||||
smsg.Misc.Msgformat = 1
|
|
||||||
|
|
||||||
break //nolint: gosimple
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если у нас супергруппа с тредами, надо проставить thread id.
|
// Если у нас супергруппа с тредами, надо проставить thread id.
|
||||||
if cmd.Message.Chat.Type == "supergroup" && cmd.Message.IsTopicMessage && cmd.Message.ThreadID != 0 {
|
if cmd.Message.Chat.Type == "supergroup" && cmd.Message.IsTopicMessage && cmd.Message.ThreadID != 0 {
|
||||||
smsg.ThreadID = fmt.Sprintf("%d", cmd.Message.ThreadID)
|
smsg.ThreadID = strconv.Itoa(cmd.Message.ThreadID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Отправляем сообщение в редиску.
|
// Отправляем сообщение в редиску.
|
||||||
@@ -129,7 +121,7 @@ func cmdParser(me echotron.APIResponseUser, cmd *echotron.Update) (bool, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Заталкиваем наш json в редиску.
|
// Заталкиваем наш json в редиску.
|
||||||
if err := RedisClient.Publish(ctx, Config.Redis.Channel, data).Err(); err != nil {
|
if err := RedisClient.Publish(Ctx, Config.Redis.Channel, data).Err(); err != nil {
|
||||||
log.Warnf("Unable to send data to redis channel %s: %s", Config.Redis.Channel, err)
|
log.Warnf("Unable to send data to redis channel %s: %s", Config.Redis.Channel, err)
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Sent msg to redis channel %s: %s", Config.Redis.Channel, string(data))
|
log.Debugf("Sent msg to redis channel %s: %s", Config.Redis.Channel, string(data))
|
||||||
|
|||||||
@@ -9,37 +9,42 @@ import (
|
|||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config - это у нас глобальная штука.
|
var (
|
||||||
var Config myConfig
|
// Config - это у нас глобальная штука.
|
||||||
|
Config MyConfig
|
||||||
|
|
||||||
// To break circular message forwarding we must set some sane default, it can be overridden via config.
|
// forwardMax is used to break circular message forwarding we must set some sane default, it can be overridden via config.
|
||||||
var forwardMax int64 = 5
|
forwardMax int64 = 5
|
||||||
|
|
||||||
// Объектики клиента-редиски.
|
// RedisClient объектик клиента-редиски.
|
||||||
var RedisClient *redis.Client
|
RedisClient *redis.Client
|
||||||
var Subscriber *redis.PubSub
|
|
||||||
|
|
||||||
// Main context.
|
// Subscriber is redis PubSub object.
|
||||||
var ctx = context.Background()
|
Subscriber *redis.PubSub
|
||||||
|
|
||||||
// Ставится в true, если мы получили сигнал на выключение.
|
// Ctx is main context.
|
||||||
var Shutdown = false
|
Ctx = context.Background()
|
||||||
|
|
||||||
// Канал, в который приходят уведомления для хэндлера сигналов от траппера сигналов.
|
// Shutdown ставится в true, если мы получили сигнал на выключение.
|
||||||
var SigChan = make(chan os.Signal, 1)
|
Shutdown = false
|
||||||
|
|
||||||
// Мапка с открытыми дескрипторами баз с настройками.
|
// SigChan канал, в который приходят уведомления для хэндлера сигналов от траппера сигналов.
|
||||||
var settingsDB = make(map[string]*pebble.DB)
|
SigChan = make(chan os.Signal, 1)
|
||||||
|
|
||||||
var tg echotron.API
|
// settingsDB мапка с открытыми дескрипторами баз с настройками.
|
||||||
|
settingsDB = make(map[string]*pebble.DB)
|
||||||
|
|
||||||
// Приветсвенные фразы для новых участников чата.
|
// tg is var for telegram api.
|
||||||
var introduceGreet = [...]string{
|
tg echotron.API
|
||||||
"Дратути",
|
|
||||||
"Дарована",
|
// introduceGreet приветсвенные фразы для новых участников чата.
|
||||||
"Доброе утро, день или вечер",
|
introduceGreet = [...]string{
|
||||||
"Добро пожаловать в наше скромное коммунити",
|
"Дратути",
|
||||||
"Наше вам с кисточкой тут, на канальчике",
|
"Дарована",
|
||||||
}
|
"Доброе утро, день или вечер",
|
||||||
|
"Добро пожаловать в наше скромное коммунити",
|
||||||
|
"Наше вам с кисточкой тут, на канальчике",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
// Help Выводит в чат сообщение с основными командами бота.
|
// Help Выводит в чат сообщение с основными командами бота.
|
||||||
func Help(cmd *echotron.Update) (bool, error) {
|
func Help(cmd *echotron.Update) (bool, error) {
|
||||||
help := "```\n"
|
help := "```\n"
|
||||||
|
|
||||||
help += fmt.Sprintf("%shelp | %sпомощь - список команд", Config.Csign, Config.Csign)
|
help += fmt.Sprintf("%shelp | %sпомощь - список команд", Config.Csign, Config.Csign)
|
||||||
help += fmt.Sprintf("%sanek | %sанек | %sанекдот - рандомный анекдот с anekdot.ru", Config.Csign, Config.Csign, Config.Csign)
|
help += fmt.Sprintf("%sanek | %sанек | %sанекдот - рандомный анекдот с anekdot.ru", Config.Csign, Config.Csign, Config.Csign)
|
||||||
help += fmt.Sprintf("%sbuni - рандомный стрип hapi buni", Config.Csign)
|
help += fmt.Sprintf("%sbuni - рандомный стрип hapi buni", Config.Csign)
|
||||||
|
|||||||
@@ -11,52 +11,52 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseConfig разбирает и валидирует даденный конфиг.
|
// ParseConfig разбирает и валидирует даденный конфиг.
|
||||||
func ParseConfig(path string) (myConfig, error) {
|
func ParseConfig(path string) (MyConfig, error) {
|
||||||
fileInfo, err := os.Stat(path)
|
fileInfo, err := os.Stat(path)
|
||||||
|
|
||||||
// Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём.
|
// Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return myConfig{}, err
|
return MyConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Конфиг-файл длинноват для конфига, попробуем следующего кандидата.
|
// Конфиг-файл длинноват для конфига, попробуем следующего кандидата.
|
||||||
if fileInfo.Size() > 65535 {
|
if fileInfo.Size() > 65535 {
|
||||||
err := fmt.Errorf("config file %s is too long for config, skipping", path)
|
err := fmt.Errorf("config file %s is too long for config, skipping", path)
|
||||||
|
|
||||||
return myConfig{}, err
|
return MyConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf, err := os.ReadFile(path)
|
buf, err := os.ReadFile(path)
|
||||||
|
|
||||||
// Не удалось прочитать.
|
// Не удалось прочитать.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return myConfig{}, err
|
return MyConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Исходя из документации, hjson какбы умеет парсить "кривой" json, но парсит его в map-ку.
|
// Исходя из документации, hjson какбы умеет парсить "кривой" json, но парсит его в map-ку.
|
||||||
// Интереснее на выходе получить структурку: то есть мы вначале конфиг преобразуем в map-ку, затем эту map-ку
|
// Интереснее на выходе получить структурку: то есть мы вначале конфиг преобразуем в map-ку, затем эту map-ку
|
||||||
// сериализуем в 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)
|
||||||
|
|
||||||
// Не удалось распарсить.
|
// Не удалось распарсить.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return myConfig{}, err
|
return MyConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpjson, err := json.Marshal(tmp)
|
tmpjson, err := json.Marshal(tmp)
|
||||||
|
|
||||||
// Не удалось преобразовать map-ку в json.
|
// Не удалось преобразовать map-ку в json.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return myConfig{}, err
|
return MyConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(tmpjson, &sampleConfig); err != nil {
|
if err := json.Unmarshal(tmpjson, &sampleConfig); err != nil {
|
||||||
return myConfig{}, err
|
return MyConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Валидируем значения из конфига.
|
// Валидируем значения из конфига.
|
||||||
@@ -73,29 +73,29 @@ func ParseConfig(path string) (myConfig, error) {
|
|||||||
if sampleConfig.Redis.Channel == "" {
|
if sampleConfig.Redis.Channel == "" {
|
||||||
err := fmt.Errorf("channel field in config file %s must be set", path)
|
err := fmt.Errorf("channel field in config file %s must be set", path)
|
||||||
|
|
||||||
return myConfig{}, err
|
return MyConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if sampleConfig.Redis.MyChannel == "" {
|
if sampleConfig.Redis.MyChannel == "" {
|
||||||
err := fmt.Errorf("my_channel field in config file %s must be set", path)
|
err := fmt.Errorf("my_channel field in config file %s must be set", path)
|
||||||
|
|
||||||
return myConfig{}, err
|
return MyConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if sampleConfig.Telegram.Token == "" {
|
if sampleConfig.Telegram.Token == "" {
|
||||||
return myConfig{}, fmt.Errorf("telegram.token field in config file %s must be set", path)
|
return MyConfig{}, fmt.Errorf("telegram.token field in config file %s must be set", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sampleConfig.Loglevel == "" {
|
if sampleConfig.Loglevel == "" {
|
||||||
sampleConfig.Loglevel = "info"
|
sampleConfig.Loglevel = "info"
|
||||||
}
|
}
|
||||||
|
|
||||||
// sampleConfig.Log = "" if not set
|
// sampleConfig.Log = "" if not set..
|
||||||
|
|
||||||
if sampleConfig.Csign == "" {
|
if sampleConfig.Csign == "" {
|
||||||
err := fmt.Errorf("csign field in config file %s must be set", path)
|
err := fmt.Errorf("csign field in config file %s must be set", path)
|
||||||
|
|
||||||
return myConfig{}, err
|
return MyConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if sampleConfig.ForwardsMax == 0 {
|
if sampleConfig.ForwardsMax == 0 {
|
||||||
@@ -103,7 +103,7 @@ func ParseConfig(path string) (myConfig, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if sampleConfig.DataDir == "" {
|
if sampleConfig.DataDir == "" {
|
||||||
return myConfig{}, fmt.Errorf("data_dir field in config file %s must be set", path)
|
return MyConfig{}, fmt.Errorf("data_dir field in config file %s must be set", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sampleConfig, err
|
return sampleConfig, err
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func RedisMsgParser(msg string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate our j
|
// Validate our j.
|
||||||
if exist := j.From; exist == "" {
|
if exist := j.From; exist == "" {
|
||||||
log.Warnf("Incorrect msg from redis, no from field: %s", msg)
|
log.Warnf("Incorrect msg from redis, no from field: %s", msg)
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ func RedisMsgParser(msg string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// j.Misc.Answer может и не быть, тогда ответа на такое сообщение не будет
|
// j.Misc.Answer может и не быть, тогда ответа на такое сообщение не будет.
|
||||||
if j.Misc.Answer == 0 {
|
if j.Misc.Answer == 0 {
|
||||||
log.Debug("Field Misc->Answer = 0, skipping message")
|
log.Debug("Field Misc->Answer = 0, skipping message")
|
||||||
|
|
||||||
@@ -76,14 +76,14 @@ func RedisMsgParser(msg string) {
|
|||||||
j.Misc.Csign = Config.Csign
|
j.Misc.Csign = Config.Csign
|
||||||
}
|
}
|
||||||
|
|
||||||
// j.Misc.FwdCnt если нам его не передали, то будет 0
|
// j.Misc.FwdCnt если нам его не передали, то будет 0.
|
||||||
if exist := j.Misc.Fwdcnt; exist == 0 {
|
if exist := j.Misc.Fwdcnt; exist == 0 {
|
||||||
j.Misc.Fwdcnt = 1
|
j.Misc.Fwdcnt = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// j.Misc.GoodMorning может быть 1 или 0, по-умолчанию 0
|
// j.Misc.GoodMorning может быть 1 или 0, по-умолчанию 0.
|
||||||
// j.Misc.MsgFormat может быть 1 или 0, по-умолчанию 0
|
// j.Misc.MsgFormat может быть 1 или 0, по-умолчанию 0.
|
||||||
// j.Misc.Username можно не передавать, тогда будет пустая строка
|
// j.Misc.Username можно не передавать, тогда будет пустая строка.
|
||||||
|
|
||||||
// Отвалидировались, теперь вернёмся к нашим баранам.
|
// Отвалидировались, теперь вернёмся к нашим баранам.
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func GetSetting(chatID string, setting string) string {
|
|||||||
chatHash := sha256.Sum256([]byte(chatID))
|
chatHash := sha256.Sum256([]byte(chatID))
|
||||||
database := fmt.Sprintf("settings_db/%x", chatHash)
|
database := fmt.Sprintf("settings_db/%x", chatHash)
|
||||||
|
|
||||||
// Если БД не открыта, откроем её
|
// Если БД не открыта, откроем её.
|
||||||
if _, ok := settingsDB[database]; !ok {
|
if _, ok := settingsDB[database]; !ok {
|
||||||
var options pebble.Options
|
var options pebble.Options
|
||||||
// По дефолту ограничение ставится на мегабайты данных, а не на количество файлов, поэтому с дефолтными
|
// По дефолту ограничение ставится на мегабайты данных, а не на количество файлов, поэтому с дефолтными
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func SigHandler() {
|
|||||||
Shutdown = true
|
Shutdown = true
|
||||||
|
|
||||||
// Отпишемся от всех каналов и закроем коннект к редиске.
|
// Отпишемся от всех каналов и закроем коннект к редиске.
|
||||||
if err = Subscriber.Unsubscribe(ctx); err != nil {
|
if err = Subscriber.Unsubscribe(Ctx); err != nil {
|
||||||
log.Errorf("Unable to unsubscribe from redis channels cleanly: %s", err)
|
log.Errorf("Unable to unsubscribe from redis channels cleanly: %s", err)
|
||||||
} else {
|
} else {
|
||||||
log.Debug("Unsubscribe from all redis channels")
|
log.Debug("Unsubscribe from all redis channels")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package tg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"aleesa-telegram-go/internal/log"
|
"aleesa-telegram-go/internal/log"
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Telega основная горутинка, реализующая бота.
|
// Telega основная горутинка, реализующая бота.
|
||||||
func Telega(c myConfig) {
|
func Telega(c MyConfig) {
|
||||||
tg = echotron.NewAPI(c.Telegram.Token)
|
tg = echotron.NewAPI(c.Telegram.Token)
|
||||||
|
|
||||||
for u := range echotron.PollingUpdates(c.Telegram.Token) {
|
for u := range echotron.PollingUpdates(c.Telegram.Token) {
|
||||||
@@ -86,11 +87,11 @@ func ConstructPartialUserUsername(u *echotron.User) string {
|
|||||||
return u.LastName
|
return u.LastName
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("%d", u.ID)
|
return strconv.FormatInt(u.ID, 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConstructPartialUserUsername пытается найти и вытащить username, если такового нет, вытаскивает First/Last Name, если
|
// ConstructPartialChatUsername пытается найти и вытащить username, если такового нет, вытаскивает First/Last Name, если
|
||||||
// такового нет, то возвращает ID.
|
// такового нет, то возвращает ID.
|
||||||
func ConstructPartialChatUsername(c *echotron.Chat) string {
|
func ConstructPartialChatUsername(c *echotron.Chat) string {
|
||||||
switch {
|
switch {
|
||||||
@@ -107,7 +108,7 @@ func ConstructPartialChatUsername(c *echotron.Chat) string {
|
|||||||
return c.LastName
|
return c.LastName
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("%d", c.ID)
|
return strconv.FormatInt(c.ID, 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +127,7 @@ func ConstructUserFirstLastName(u *echotron.User) string {
|
|||||||
case u.Username != "":
|
case u.Username != "":
|
||||||
user = fmt.Sprintf("@%s", u.Username)
|
user = fmt.Sprintf("@%s", u.Username)
|
||||||
default:
|
default:
|
||||||
user = fmt.Sprintf("%d", u.ID)
|
user = strconv.FormatInt(u.ID, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"aleesa-telegram-go/internal/log"
|
"aleesa-telegram-go/internal/log"
|
||||||
@@ -21,10 +22,9 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Сообщение о том, что этот чятик изменился, например, превратился в супергруппу.
|
// Сообщение о том, что этот чятик изменился, например, превратился в супергруппу.
|
||||||
if (msg.Message.MigrateFromChatID < 0) && (msg.Message.MigrateToChatID < 0) { //nolint: revive,staticcheck
|
if (msg.Message.MigrateFromChatID < 0) && (msg.Message.MigrateToChatID < 0) {
|
||||||
// TODO: поддержать миграцию настроек чата на новый chatId.
|
// TODO: поддержать миграцию настроек чата на новый chatId.
|
||||||
// TODO: подумать, что можно сделать с настройками бэкэндов. Кажись, ничего, но надо глянуть.
|
// TODO: подумать, что можно сделать с настройками бэкэндов. Кажись, ничего, но надо глянуть.
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,16 +56,17 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Люди пришли в чят.
|
// Люди пришли в чят.
|
||||||
if msg.Message.NewChatMembers != nil { //nolint: revive,staticcheck
|
if msg.Message.NewChatMembers != nil {
|
||||||
// TODO: проверить, надо ли приветствовать, выбрать одну из приветственных фраз, потянуть время, типа, мы пишем
|
// TODO: проверить, надо ли приветствовать, выбрать одну из приветственных фраз, потянуть время, типа, мы пишем
|
||||||
// текст и поприветствовать вновь прибывшего.
|
// текст и поприветствовать вновь прибывшего.
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GreetMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GreetMsg") == "1" {
|
||||||
// Пользователи, которых мы приветсвуем, одной строкой.
|
// Пользователи, которых мы приветсвуем, одной строкой.
|
||||||
var users string
|
var users string
|
||||||
|
|
||||||
if len(msg.Message.NewChatMembers) > 1 {
|
if len(msg.Message.NewChatMembers) > 1 {
|
||||||
lastOne := msg.Message.NewChatMembers[len(msg.Message.NewChatMembers)-1]
|
lastOne := msg.Message.NewChatMembers[len(msg.Message.NewChatMembers)-1]
|
||||||
theRest := msg.Message.NewChatMembers[:len(msg.Message.NewChatMembers)-1]
|
theRest := msg.Message.NewChatMembers[:len(msg.Message.NewChatMembers)-1]
|
||||||
|
|
||||||
var usersSlice []string
|
var usersSlice []string
|
||||||
|
|
||||||
for _, user := range theRest {
|
for _, user := range theRest {
|
||||||
@@ -73,6 +74,7 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
users = strings.Join(usersSlice, ", ")
|
users = strings.Join(usersSlice, ", ")
|
||||||
|
|
||||||
users += fmt.Sprintf(" and %s", ConstructTelegramHighlightName(lastOne))
|
users += fmt.Sprintf(" and %s", ConstructTelegramHighlightName(lastOne))
|
||||||
} else {
|
} else {
|
||||||
users = ConstructTelegramHighlightName(msg.Message.NewChatMembers[0])
|
users = ConstructTelegramHighlightName(msg.Message.NewChatMembers[0])
|
||||||
@@ -88,7 +90,7 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
resp, err := tg.SendChatAction(
|
resp, err := tg.SendChatAction(
|
||||||
echotron.Typing,
|
echotron.Typing,
|
||||||
msg.Message.From.ID,
|
msg.Message.From.ID,
|
||||||
&echotron.ChatActionOptions{MessageThreadID: int(msg.Message.ThreadID)},
|
&echotron.ChatActionOptions{MessageThreadID: msg.Message.ThreadID},
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: вероятно, ошибку надо засылать в обработчик ошибок, так как в ней может быть миграция чятика или
|
// TODO: вероятно, ошибку надо засылать в обработчик ошибок, так как в ней может быть миграция чятика или
|
||||||
@@ -123,7 +125,7 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
|
|
||||||
// Человек ушёл из чата.
|
// Человек ушёл из чата.
|
||||||
if msg.Message.LeftChatMember != nil {
|
if msg.Message.LeftChatMember != nil {
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "GoodbyeMsg") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GoodbyeMsg") == "1" {
|
||||||
user := ConstructUserFirstLastName(msg.Message.From)
|
user := ConstructUserFirstLastName(msg.Message.From)
|
||||||
|
|
||||||
goodbye := fmt.Sprintf("Прощаемся с %s", user)
|
goodbye := fmt.Sprintf("Прощаемся с %s", user)
|
||||||
@@ -160,8 +162,8 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
rmsg.Misc.Answer = 1
|
rmsg.Misc.Answer = 1
|
||||||
|
|
||||||
// Засылаем фразу в misc-канал (в роутер).
|
// Засылаем фразу в misc-канал (в роутер).
|
||||||
rmsg.Chatid = fmt.Sprintf("%d", msg.Message.Chat.ID)
|
rmsg.Chatid = strconv.FormatInt(msg.Message.Chat.ID, 10)
|
||||||
rmsg.Userid = fmt.Sprintf("%d", msg.Message.From.ID)
|
rmsg.Userid = strconv.FormatInt(msg.Message.From.ID, 10)
|
||||||
rmsg.Message = msg.Message.Text
|
rmsg.Message = msg.Message.Text
|
||||||
rmsg.Mode = "private"
|
rmsg.Mode = "private"
|
||||||
rmsg.Plugin = "telegram"
|
rmsg.Plugin = "telegram"
|
||||||
@@ -198,7 +200,7 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Заталкиваем наш json в редиску.
|
// Заталкиваем наш json в редиску.
|
||||||
if err := RedisClient.Publish(ctx, Config.Redis.Channel, data).Err(); err != nil {
|
if err := RedisClient.Publish(Ctx, Config.Redis.Channel, data).Err(); err != nil {
|
||||||
log.Warnf("Unable to send data to redis channel %s: %s", Config.Redis.Channel, err)
|
log.Warnf("Unable to send data to redis channel %s: %s", Config.Redis.Channel, err)
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Sent msg to redis channel %s: %s", Config.Redis.Channel, string(data))
|
log.Debugf("Sent msg to redis channel %s: %s", Config.Redis.Channel, string(data))
|
||||||
@@ -209,7 +211,7 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
// Обрабатываем сообщения для групп и супергрупп. По сути это примерно одинаковые вещи/сущности.
|
// Обрабатываем сообщения для групп и супергрупп. По сути это примерно одинаковые вещи/сущности.
|
||||||
// Цензор удаляет сообщения из чятика, если они "неправильные" - от имени других каналов, аудиосообщения,
|
// Цензор удаляет сообщения из чятика, если они "неправильные" - от имени других каналов, аудиосообщения,
|
||||||
// содержат картинки, видео аудио итп, это настраивается через команду !admin censor.
|
// содержат картинки, видео аудио итп, это настраивается через команду !admin censor.
|
||||||
if GetSetting(fmt.Sprintf("%d", msg.Message.Chat.ID), "censor") == "1" {
|
if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "censor") == "1" {
|
||||||
// Если цензор отработал, больше делать нечего, сообщения уже нету.
|
// Если цензор отработал, больше делать нечего, сообщения уже нету.
|
||||||
if Censor(msg) {
|
if Censor(msg) {
|
||||||
return
|
return
|
||||||
@@ -239,7 +241,7 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Здесь же, если фраза обращена к боту (ник или имя), выставляем флажок, что надо ответить
|
// Здесь же, если фраза обращена к боту (ник или имя), выставляем флажок, что надо ответить.
|
||||||
quotedBotUsername := regexp.QuoteMeta(me.Result.Username)
|
quotedBotUsername := regexp.QuoteMeta(me.Result.Username)
|
||||||
quotedBotFirstName := regexp.QuoteMeta(me.Result.FirstName)
|
quotedBotFirstName := regexp.QuoteMeta(me.Result.FirstName)
|
||||||
quotedBotLastName := regexp.QuoteMeta(me.Result.LastName)
|
quotedBotLastName := regexp.QuoteMeta(me.Result.LastName)
|
||||||
@@ -250,7 +252,9 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
return
|
return
|
||||||
} else if messageContainsBotUsername {
|
} else if messageContainsBotUsername {
|
||||||
rmsg.Misc.Answer = 1
|
rmsg.Misc.Answer = 1
|
||||||
|
|
||||||
m := regexp.MustCompile(quotedBotUsername)
|
m := regexp.MustCompile(quotedBotUsername)
|
||||||
|
|
||||||
msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "")
|
msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +277,9 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
|
|
||||||
if messageContainsBotName {
|
if messageContainsBotName {
|
||||||
rmsg.Misc.Answer = 1
|
rmsg.Misc.Answer = 1
|
||||||
|
|
||||||
m := regexp.MustCompile(quotedBotFirstName + "[[:space:]]+" + quotedBotLastName)
|
m := regexp.MustCompile(quotedBotFirstName + "[[:space:]]+" + quotedBotLastName)
|
||||||
|
|
||||||
msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "")
|
msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "")
|
||||||
}
|
}
|
||||||
// Если у нас есть только имя, то попробуем его вырезать из входящей фразы.
|
// Если у нас есть только имя, то попробуем его вырезать из входящей фразы.
|
||||||
@@ -288,7 +294,9 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
|
|
||||||
if messageContainsBotName {
|
if messageContainsBotName {
|
||||||
rmsg.Misc.Answer = 1
|
rmsg.Misc.Answer = 1
|
||||||
|
|
||||||
m := regexp.MustCompile(quotedBotFirstName)
|
m := regexp.MustCompile(quotedBotFirstName)
|
||||||
|
|
||||||
msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "")
|
msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "")
|
||||||
}
|
}
|
||||||
// Если у нас есть только фамилия, то попробуем его вырезать из входящей фразы.
|
// Если у нас есть только фамилия, то попробуем его вырезать из входящей фразы.
|
||||||
@@ -303,14 +311,16 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
|
|
||||||
if messageContainsBotName {
|
if messageContainsBotName {
|
||||||
rmsg.Misc.Answer = 1
|
rmsg.Misc.Answer = 1
|
||||||
|
|
||||||
m := regexp.MustCompile(quotedBotLastName)
|
m := regexp.MustCompile(quotedBotLastName)
|
||||||
|
|
||||||
msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "")
|
msg.Message.Text = m.ReplaceAllString(msg.Message.Text, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Засылаем фразу в misc-канал (в роутер).
|
// Засылаем фразу в misc-канал (в роутер).
|
||||||
rmsg.Chatid = fmt.Sprintf("%d", msg.Message.Chat.ID)
|
rmsg.Chatid = strconv.FormatInt(msg.Message.Chat.ID, 10)
|
||||||
rmsg.Userid = fmt.Sprintf("%d", msg.Message.From.ID)
|
rmsg.Userid = strconv.FormatInt(msg.Message.From.ID, 10)
|
||||||
rmsg.Message = msg.Message.Text
|
rmsg.Message = msg.Message.Text
|
||||||
rmsg.Mode = "public"
|
rmsg.Mode = "public"
|
||||||
rmsg.Plugin = "telegram"
|
rmsg.Plugin = "telegram"
|
||||||
@@ -335,7 +345,7 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Заталкиваем наш json в редиску.
|
// Заталкиваем наш json в редиску.
|
||||||
if err := RedisClient.Publish(ctx, Config.Redis.Channel, data).Err(); err != nil {
|
if err := RedisClient.Publish(Ctx, Config.Redis.Channel, data).Err(); err != nil {
|
||||||
log.Warnf("Unable to send data to redis channel %s: %s", Config.Redis.Channel, err)
|
log.Warnf("Unable to send data to redis channel %s: %s", Config.Redis.Channel, err)
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Sent msg to redis channel %s: %s", Config.Redis.Channel, string(data))
|
log.Debugf("Sent msg to redis channel %s: %s", Config.Redis.Channel, string(data))
|
||||||
|
|||||||
@@ -1,68 +1,71 @@
|
|||||||
package tg
|
package tg
|
||||||
|
|
||||||
// myConfig структура, описывающая формат Конфига.
|
type (
|
||||||
type myConfig struct {
|
// MyConfig структура, описывающая формат Конфига.
|
||||||
Redis struct {
|
MyConfig struct {
|
||||||
Server string `json:"server,omitempty"`
|
Csign string `json:"csign,omitempty"`
|
||||||
Port int `json:"port,omitempty"`
|
DataDir string `json:"data_dir,omitempty"`
|
||||||
Channel string `json:"channel,omitempty"`
|
Log string `json:"log,omitempty"`
|
||||||
MyChannel string `json:"my_channel,omitempty"`
|
Loglevel string `json:"loglevel,omitempty"`
|
||||||
} `json:"redis"`
|
|
||||||
|
|
||||||
Telegram struct {
|
Telegram struct {
|
||||||
Token string `json:"token,omitempty"`
|
Token string `json:"token,omitempty"`
|
||||||
|
} `json:"telegram"`
|
||||||
|
|
||||||
|
Redis struct {
|
||||||
|
Channel string `json:"channel,omitempty"`
|
||||||
|
MyChannel string `json:"my_channel,omitempty"`
|
||||||
|
Server string `json:"server,omitempty"`
|
||||||
|
Port int `json:"port,omitempty"`
|
||||||
|
} `json:"redis"`
|
||||||
|
|
||||||
|
ForwardsMax int64 `json:"forwards_max,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
Loglevel string `json:"loglevel,omitempty"`
|
// rMsg структура, описывающая формат входящего сообщения из pubsub-канала redis-ки.
|
||||||
Log string `json:"log,omitempty"`
|
rMsg struct {
|
||||||
Csign string `json:"csign,omitempty"`
|
From string `json:"from,omitempty"`
|
||||||
ForwardsMax int64 `json:"forwards_max,omitempty"`
|
Chatid string `json:"chatid,omitempty"`
|
||||||
DataDir string `json:"data_dir,omitempty"`
|
Userid string `json:"userid,omitempty"`
|
||||||
}
|
ThreadID string `json:"threadid,omitempty"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
Plugin string `json:"plugin,omitempty"`
|
||||||
|
Mode string `json:"mode,omitempty"`
|
||||||
|
Misc struct {
|
||||||
|
Botnick string `json:"bot_nick,omitempty"`
|
||||||
|
Csign string `json:"csign,omitempty"`
|
||||||
|
// Судя по перловой реализации, сюда всегда попадает [$fullname](tg://user?id=$userid).
|
||||||
|
// Согласно докуметации, и перловой реализации бота, мы проставляем это поле тогда, когда мы точно знаем, что в
|
||||||
|
// бэкэнде оно используется.
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
Answer int64 `json:"answer,omitempty"`
|
||||||
|
Fwdcnt int64 `json:"fwd_cnt,omitempty"`
|
||||||
|
GoodMorning int64 `json:"good_morning,omitempty"`
|
||||||
|
// В этом поле мы пишем 1, если бэкэнд должен в ответе форматировать сообщение в MarkdownV2, что какбэ
|
||||||
|
// не оч хорошо, так как мы выносим особенности реализации бэкэнда сюда.
|
||||||
|
Msgformat int64 `json:"msg_format,omitempty"`
|
||||||
|
} `json:"Misc"`
|
||||||
|
}
|
||||||
|
|
||||||
// rMsg структура, описывающая формат входящего сообщения из pubsub-канала redis-ки.
|
// sMsg структура, описывающая исходящее сообщение в pubsub-канал redis-ки.
|
||||||
type rMsg struct {
|
sMsg struct {
|
||||||
From string `json:"from,omitempty"`
|
From string `json:"from"`
|
||||||
Chatid string `json:"chatid,omitempty"`
|
Chatid string `json:"chatid"`
|
||||||
Userid string `json:"userid,omitempty"`
|
Userid string `json:"userid"`
|
||||||
ThreadID string `json:"threadid,omitempty"`
|
ThreadID string `json:"threadid,omitempty"`
|
||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message"`
|
||||||
Plugin string `json:"plugin,omitempty"`
|
Plugin string `json:"plugin"`
|
||||||
Mode string `json:"mode,omitempty"`
|
Mode string `json:"mode"`
|
||||||
Misc struct {
|
Misc struct {
|
||||||
Answer int64 `json:"answer,omitempty"`
|
Botnick string `json:"bot_nick"`
|
||||||
Botnick string `json:"bot_nick,omitempty"`
|
Csign string `json:"csign"`
|
||||||
Csign string `json:"csign,omitempty"`
|
Username string `json:"username"`
|
||||||
Fwdcnt int64 `json:"fwd_cnt,omitempty"`
|
Answer int64 `json:"answer"`
|
||||||
GoodMorning int64 `json:"good_morning,omitempty"`
|
Fwdcnt int64 `json:"fwd_cnt"`
|
||||||
// В этом поле мы пишем 1, если бэкэнд должен в ответе форматировать сообщение в MarkdownV2, что какбэ
|
GoodMorning int64 `json:"good_morning"`
|
||||||
// не оч хорошо, так как мы выносим особенности реализации бэкэнда сюда.
|
Msgformat int64 `json:"msg_format"`
|
||||||
Msgformat int64 `json:"msg_format,omitempty"`
|
} `json:"misc"`
|
||||||
// Судя по перловой реализации, сюда всегда попадает [$fullname](tg://user?id=$userid).
|
}
|
||||||
// Согласно докуметации, и перловой реализации бота, мы проставляем это поле тогда, когда мы точно знаем, что в
|
)
|
||||||
// бэкэнде оно используется.
|
|
||||||
Username string `json:"username,omitempty"`
|
|
||||||
} `json:"Misc"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// sMsg структура, описывающая исходящее сообщение в pubsub-канал redis-ки.
|
|
||||||
type sMsg struct {
|
|
||||||
From string `json:"from"`
|
|
||||||
Chatid string `json:"chatid"`
|
|
||||||
Userid string `json:"userid"`
|
|
||||||
ThreadID string `json:"threadid,omitempty"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
Plugin string `json:"plugin"`
|
|
||||||
Mode string `json:"mode"`
|
|
||||||
Misc struct {
|
|
||||||
Answer int64 `json:"answer"`
|
|
||||||
Botnick string `json:"bot_nick"`
|
|
||||||
Csign string `json:"csign"`
|
|
||||||
Fwdcnt int64 `json:"fwd_cnt"`
|
|
||||||
GoodMorning int64 `json:"good_morning"`
|
|
||||||
Msgformat int64 `json:"msg_format"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
} `json:"misc"`
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
||||||
|
|||||||
Reference in New Issue
Block a user