0

Add golangci-lint config and fix linter warns

This commit is contained in:
eleksir
2025-03-30 16:19:20 +03:00
parent 8c24a1d8c6
commit 7bcc407857
9 changed files with 279 additions and 143 deletions

84
.golangci.yml Normal file
View File

@@ -0,0 +1,84 @@
version: "2"
run:
go: "1.21"
modules-download-mode: readonly
tests: false
allow-parallel-runners: true
linters:
default: none
enable:
- asasalint
- asciicheck
- bodyclose
- containedctx
- contextcheck
- decorder
- durationcheck
- errcheck
- errchkjson
- errorlint
- exhaustive
- ginkgolinter
- gocheckcompilerdirectives
- gocritic
- godot
- gosec
- gosmopolitan
- govet
- grouper
- importas
- ineffassign
- ireturn
- makezero
- mirror
- nakedret
- nilerr
- nilnil
- nlreturn
- noctx
- nolintlint
- nonamedreturns
- predeclared
- promlinter
- reassign
- revive
- rowserrcheck
- staticcheck
- unconvert
- unused
- wastedassign
- whitespace
- wsl
settings:
gosec:
excludes:
# Оно не используется для повышения безопасности или каких-то таких секъюрных вещей, оно используется для выборки
# произвольного элемента из массива, так что ИДИ НАХУЙ с этой проверкой и не еби мозги липовой безопасностью.
- G404
# Не еби мозги. Сертификаты для локалхоста или для локальной сети могут быть невалидными, если ты сможешь
# выписать валидный серт для локалхоста, тебе миллионы разработчиков поставят золотой памятник. Просто потому
# что эти пидоры-безпасники всрали всё что только можно всрать своими дебильными политиками.
- G402
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
- vendor$

View File

@@ -11,15 +11,9 @@ import (
irc "github.com/thoj/go-ircevent" irc "github.com/thoj/go-ircevent"
) )
// TODO: Implement 005 REPL_BOUNCE // ircClientInit горутинка для работы с протоколом irc.
// ircClientInit горутинка для работы с протоколом irc
func ircClientRun() { func ircClientRun() {
for { for !shutdown {
if shutdown {
// Если мы завершаем работу программы, то нам ничего обрабатывать не надо
break
}
// Иницализируем irc-клиента // Иницализируем irc-клиента
serverString := fmt.Sprintf("%s:%d", config.Irc.Server, config.Irc.Port) serverString := fmt.Sprintf("%s:%d", config.Irc.Server, config.Irc.Port)
log.Debugf("Preparing to connect to %s", serverString) log.Debugf("Preparing to connect to %s", serverString)
@@ -30,10 +24,12 @@ func ircClientRun() {
if config.Irc.Ssl { if config.Irc.Ssl {
log.Debug("Force use ssl for connection") log.Debug("Force use ssl for connection")
ircClient.UseTLS = true ircClient.UseTLS = true
if !config.Irc.SslVerify { if !config.Irc.SslVerify {
log.Debug("Skip server certificate validation") log.Debug("Skip server certificate validation")
ircClient.TLSConfig = &tls.Config{InsecureSkipVerify: true} ircClient.TLSConfig = &tls.Config{InsecureSkipVerify: true}
} else { } else {
log.Debug("Force server certificate validation") log.Debug("Force server certificate validation")
@@ -92,18 +88,19 @@ func ircClientRun() {
if channel == mychannel { if channel == mychannel {
// Для каждого канала формат строго 1 из 4-х: #channel | @#channel | +#channel | @+#channel // Для каждого канала формат строго 1 из 4-х: #channel | @#channel | +#channel | @+#channel
switch { switch modes {
case modes == "@+": case "@+":
userModeUpdateUser(channel, dstNick, "+o") userModeUpdateUser(channel, dstNick, "+o")
userModeUpdateUser(channel, dstNick, "+v") userModeUpdateUser(channel, dstNick, "+v")
case modes == "@": case "@":
userModeUpdateUser(channel, dstNick, "+o") userModeUpdateUser(channel, dstNick, "+o")
case modes == "+": case "+":
userModeUpdateUser(channel, dstNick, "+v") userModeUpdateUser(channel, dstNick, "+v")
default: default:
userModeUpdateUser(channel, dstNick, "-o") userModeUpdateUser(channel, dstNick, "-o")
userModeUpdateUser(channel, dstNick, "-v") userModeUpdateUser(channel, dstNick, "-v")
} }
break break
} }
} }
@@ -123,6 +120,7 @@ func ircClientRun() {
if channel == mychannel { if channel == mychannel {
for _, name := range strings.Split(namesString, " ") { for _, name := range strings.Split(namesString, " ") {
mode := name[:1] mode := name[:1]
var nick string var nick string
if mode == "@" || mode == "+" { if mode == "@" || mode == "+" {
@@ -131,16 +129,17 @@ func ircClientRun() {
nick = name nick = name
} }
switch { switch mode {
case mode == "@": case "@":
userModeUpdateUser(channel, nick, "+o") userModeUpdateUser(channel, nick, "+o")
case mode == "+": case "+":
userModeUpdateUser(channel, nick, "+v") userModeUpdateUser(channel, nick, "+v")
default: default:
userModeUpdateUser(channel, nick, "-o") userModeUpdateUser(channel, nick, "-o")
userModeUpdateUser(channel, nick, "-v") userModeUpdateUser(channel, nick, "-v")
} }
} }
break break
} }
} }
@@ -173,8 +172,9 @@ func ircClientRun() {
if !config.Irc.Sasl && config.Irc.Password != "" && !nickIsUsed { if !config.Irc.Sasl && config.Irc.Password != "" && !nickIsUsed {
log.Info("Identifying via NickServ") log.Info("Identifying via NickServ")
message := fmt.Sprintf("identify %s %s", config.Irc.Nick, config.Irc.Password) message := fmt.Sprintf("identify %s %s", config.Irc.Nick, config.Irc.Password)
imChan <- iMsg{ChatId: "NickServ", Text: message} imChan <- iMsg{ChatID: "NickServ", Text: message}
} }
// TODO: wait until +R flag been set? could be implemented with waiting for channel message. // TODO: wait until +R flag been set? could be implemented with waiting for channel message.
@@ -241,8 +241,9 @@ func ircClientRun() {
if !config.Irc.Sasl && config.Irc.Password != "" && !nickIsUsed { if !config.Irc.Sasl && config.Irc.Password != "" && !nickIsUsed {
log.Info("Identifying via NickServ") log.Info("Identifying via NickServ")
message := fmt.Sprintf("identify %s %s", config.Irc.Nick, config.Irc.Password) message := fmt.Sprintf("identify %s %s", config.Irc.Nick, config.Irc.Password)
imChan <- iMsg{ChatId: "NickServ", Text: message} imChan <- iMsg{ChatID: "NickServ", Text: message}
} }
// TODO: wait until +R flag been set? could be implemented with waiting for channel message. // TODO: wait until +R flag been set? could be implemented with waiting for channel message.
@@ -264,8 +265,11 @@ func ircClientRun() {
ircClient.AddCallback("433", func(e *irc.Event) { ircClient.AddCallback("433", func(e *irc.Event) {
log.Errorf("433 ERR_NICKNAMEINUSE, %s", e.Raw) log.Errorf("433 ERR_NICKNAMEINUSE, %s", e.Raw)
nickIsUsed = true nickIsUsed = true
time.Sleep(60 * time.Second)
<-time.NewTimer(60 * time.Second).C // 1 minute sleep.
ircClient.Nick(config.Irc.Nick) ircClient.Nick(config.Irc.Nick)
}) })
@@ -321,6 +325,7 @@ func ircClientRun() {
for _, ircChan := range config.Irc.Channels { for _, ircChan := range config.Irc.Channels {
if ircChan == channel { if ircChan == channel {
ircClient.Join(channel) ircClient.Join(channel)
break break
} }
} }
@@ -341,6 +346,7 @@ func ircClientRun() {
for _, ircChan := range config.Irc.Channels { for _, ircChan := range config.Irc.Channels {
if ircChan == channel { if ircChan == channel {
ircClient.Join(channel) ircClient.Join(channel)
break break
} }
} }
@@ -359,6 +365,7 @@ func ircClientRun() {
for _, ircChan := range config.Irc.Channels { for _, ircChan := range config.Irc.Channels {
if ircChan == channel { if ircChan == channel {
ircClient.Join(channel) ircClient.Join(channel)
break break
} }
} }
@@ -423,8 +430,9 @@ func ircClientRun() {
log.Warn("I regain my nick") log.Warn("I regain my nick")
} else { } else {
log.Warn("I regain my nick, trying to identify myself via NickServ") log.Warn("I regain my nick, trying to identify myself via NickServ")
message := fmt.Sprintf("identify %s %s", config.Irc.Nick, config.Irc.Password) message := fmt.Sprintf("identify %s %s", config.Irc.Nick, config.Irc.Password)
imChan <- iMsg{ChatId: "NickServ", Text: message} imChan <- iMsg{ChatID: "NickServ", Text: message}
} }
} else { } else {
log.Infof("%s renames themself to %s", srcNick, dstNick) log.Infof("%s renames themself to %s", srcNick, dstNick)
@@ -485,6 +493,7 @@ func ircClientRun() {
channel := e.Arguments[0] channel := e.Arguments[0]
fullSrcNick := e.Source fullSrcNick := e.Source
srcNick := e.Nick srcNick := e.Nick
var dstNick string var dstNick string
if len(e.Arguments) >= 3 { // кого-то по-MODE-или на канале if len(e.Arguments) >= 3 { // кого-то по-MODE-или на канале
@@ -497,6 +506,7 @@ func ircClientRun() {
} }
} else { // Установка mode-а при заходе на сервер } else { // Установка mode-а при заходе на сервер
dstNick = e.Arguments[0] dstNick = e.Arguments[0]
log.Infof("Server set my mode to %s", mode) log.Infof("Server set my mode to %s", mode)
} }
@@ -545,8 +555,9 @@ func ircClientRun() {
log.Debugf("Make an actual connection to irc") log.Debugf("Make an actual connection to irc")
if err := ircClient.Connect(serverString); err != nil { if err := ircClient.Connect(serverString); err != nil {
log.Fatalf("Unable to prepare irc connection: %s", err) log.Errorf("Unable to prepare irc connection: %s", err)
time.Sleep(3 * time.Second) <-time.NewTimer(3 * time.Second).C // Sleep for 3 seconds.
continue continue
} }
@@ -560,21 +571,22 @@ func ircSend() {
for { for {
m := <-imChan m := <-imChan
switch { switch config.Irc.RateLimit.Type {
case config.Irc.RateLimit.Type == "simple_delay": case "simple_delay":
log.Debugf("Sending to chat %s message: %s", m.ChatId, m.Text) log.Debugf("Sending to chat %s message: %s", m.ChatID, m.Text)
if m.Text[0:4] == "/me " { if m.Text[0:4] == "/me " {
ircClient.Action(m.ChatId, m.Text) ircClient.Action(m.ChatID, m.Text)
} else { } else {
ircClient.Privmsg(m.ChatId, m.Text) ircClient.Privmsg(m.ChatID, m.Text)
} }
sleepDelay := time.Duration(config.Irc.RateLimit.SimpleDelay) * time.Millisecond sleepDelay := time.Duration(config.Irc.RateLimit.SimpleDelay) * time.Millisecond
log.Debugf("Due to delay type simple_delay waiting for %d milliseconds", int(sleepDelay)) log.Debugf("Due to delay type simple_delay waiting for %d milliseconds", int(sleepDelay))
time.Sleep(sleepDelay) time.Sleep(sleepDelay)
case config.Irc.RateLimit.Type == "token_bucket": case "token_bucket":
var currentTimeMs = time.Now().UnixMilli() var currentTimeMs = time.Now().UnixMilli()
var expirationTimeMs = config.Irc.RateLimit.TokenBucket.ExpirationTime * 1000 var expirationTimeMs = config.Irc.RateLimit.TokenBucket.ExpirationTime * 1000
if len(msgBucket.Timestamps) > 0 { if len(msgBucket.Timestamps) > 0 {
@@ -588,6 +600,7 @@ func ircSend() {
bucketFill := len(newBucket.Timestamps) bucketFill := len(newBucket.Timestamps)
log.Debugf("Message bucket filled with %d/%d messages", bucketFill, config.Irc.RateLimit.TokenBucket.Size) log.Debugf("Message bucket filled with %d/%d messages", bucketFill, config.Irc.RateLimit.TokenBucket.Size)
newBucket.Timestamps = append(newBucket.Timestamps, currentTimeMs) newBucket.Timestamps = append(newBucket.Timestamps, currentTimeMs)
if bucketFill >= config.Irc.RateLimit.TokenBucket.Size { if bucketFill >= config.Irc.RateLimit.TokenBucket.Size {
@@ -598,15 +611,17 @@ func ircSend() {
} else { } else {
// Проставим время отправки сообщения // Проставим время отправки сообщения
log.Debug("Message bucket is empty") log.Debug("Message bucket is empty")
msgBucket.Timestamps = append(msgBucket.Timestamps, currentTimeMs) msgBucket.Timestamps = append(msgBucket.Timestamps, currentTimeMs)
} }
if msgBucket.IsFull { if msgBucket.IsFull {
log.Debug("Message bucket overflowed, hitting ratelimit") log.Debug("Message bucket overflowed, hitting ratelimit")
sleepPeriod := expirationTimeMs - (currentTimeMs - msgBucket.Timestamps[len(msgBucket.Timestamps)-1]) sleepPeriod := expirationTimeMs - (currentTimeMs - msgBucket.Timestamps[len(msgBucket.Timestamps)-1])
if config.Irc.RateLimit.TokenBucket.Limit > 0 { if config.Irc.RateLimit.TokenBucket.Limit > 0 {
sleepPeriod = sleepPeriod / int64(config.Irc.RateLimit.TokenBucket.Limit) sleepPeriod /= int64(config.Irc.RateLimit.TokenBucket.Limit)
} }
log.Debugf("Sleeping for %d milliseconds", sleepPeriod) log.Debugf("Sleeping for %d milliseconds", sleepPeriod)
@@ -616,20 +631,20 @@ func ircSend() {
msgBucket.Timestamps[len(msgBucket.Timestamps)-1] = currentTimeMs msgBucket.Timestamps[len(msgBucket.Timestamps)-1] = currentTimeMs
} }
log.Debugf("Sending to chat %s message: %s", m.ChatId, m.Text) log.Debugf("Sending to chat %s message: %s", m.ChatID, m.Text)
if len(m.Text) > 4 && m.Text[0:4] == "/me " { if len(m.Text) > 4 && m.Text[0:4] == "/me " {
ircClient.Action(m.ChatId, m.Text[4:]) ircClient.Action(m.ChatID, m.Text[4:])
} else { } else {
ircClient.Privmsg(m.ChatId, m.Text) ircClient.Privmsg(m.ChatID, m.Text)
} }
default: default:
log.Debugf("Sending to chat %s message: %s", m.ChatId, m.Text) log.Debugf("Sending to chat %s message: %s", m.ChatID, m.Text)
if len(m.Text) > 4 && m.Text[0:4] == "/me " { if len(m.Text) > 4 && m.Text[0:4] == "/me " {
ircClient.Action(m.ChatId, m.Text[4:]) ircClient.Action(m.ChatID, m.Text[4:])
} else { } else {
ircClient.Privmsg(m.ChatId, m.Text) ircClient.Privmsg(m.ChatID, m.Text)
} }
} }
} }
@@ -638,12 +653,12 @@ func ircSend() {
func ircSendUnrestricted() { func ircSendUnrestricted() {
for { for {
m := <-imChanUnrestricted m := <-imChanUnrestricted
log.Debugf("Skipping ratelimit and sending to chat %s message: %s", m.ChatId, m.Text) log.Debugf("Skipping ratelimit and sending to chat %s message: %s", m.ChatID, m.Text)
if len(m.Text) > 4 && m.Text[0:4] == "/me " { if len(m.Text) > 4 && m.Text[0:4] == "/me " {
ircClient.Action(m.ChatId, m.Text[4:]) ircClient.Action(m.ChatID, m.Text[4:])
} else { } else {
ircClient.Privmsg(m.ChatId, m.Text) ircClient.Privmsg(m.ChatID, m.Text)
} }
} }
} }

View File

@@ -6,54 +6,53 @@ import (
"aleesa-irc-go/internal/anycollection" "aleesa-irc-go/internal/anycollection"
"aleesa-irc-go/internal/boolcollection" "aleesa-irc-go/internal/boolcollection"
"github.com/cockroachdb/pebble" "github.com/cockroachdb/pebble"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
irc "github.com/thoj/go-ircevent" irc "github.com/thoj/go-ircevent"
) )
// Config - это у нас глобальная штука :) // Config - это у нас глобальная штука :).
var config myConfig var config myConfig
// To break circular message forwarding we must set some sane default, it can be overridden via config // To break circular message forwarding we must set some sane default, it can be overridden via config.
var forwardMax int64 = 5 var forwardMax int64 = 5
// Объектики irc-клиента // Объектики irc-клиента.
var ircClient *irc.Connection var ircClient *irc.Connection
var nickIsUsed = false var nickIsUsed = false
// Объектики клиента-редиски // Объектики клиента-редиски.
var redisClient *redis.Client var redisClient *redis.Client
var subscriber *redis.PubSub var subscriber *redis.PubSub
// Main context // Main context.
var ctx = context.Background() var ctx = context.Background()
// Ставится в true, если мы получили сигнал на выключение // Ставится в true, если мы получили сигнал на выключение.
var shutdown = false var shutdown = false
// Канал, в который приходят уведомления для хэндлера сигналов от траппера сигналов // Канал, в который приходят уведомления для хэндлера сигналов от траппера сигналов.
var sigChan = make(chan os.Signal, 1) var sigChan = make(chan os.Signal, 1)
// Канал, в который пишутся сообщения для отправки в IRC в обычном порядке // Канал, в который пишутся сообщения для отправки в IRC в обычном порядке.
var imChan = make(chan iMsg, 10000) var imChan = make(chan iMsg, 10000)
// Канал, в который пишутся сообщения для отправки в IRC, если ограничений нет (у бота +o или +v на канале) // Канал, в который пишутся сообщения для отправки в IRC, если ограничений нет (у бота +o или +v на канале).
var imChanUnrestricted = make(chan iMsg, 100) var imChanUnrestricted = make(chan iMsg, 100)
// "Ведёрко" с timestamp-ами последних отправленных сообщений // "Ведёрко" с timestamp-ами последних отправленных сообщений.
var msgBucket bucket var msgBucket bucket
// Мапка с открытыми дескрипторами баз с настройками // Мапка с открытыми дескрипторами баз с настройками.
var settingsDB = make(map[string]*pebble.DB) var settingsDB = make(map[string]*pebble.DB)
// "Базюлька" с MODE-ами пользователей на каналах // "Базюлька" с MODE-ами пользователей на каналах.
var userMode = anycollection.NewCollection() var userMode = anycollection.NewCollection()
// "Базюлька" с доступными MODE-ами пользователя // "Базюлька" с доступными MODE-ами пользователя.
var availableUserModes = boolcollection.NewCollection() var availableUserModes = boolcollection.NewCollection()
// "Базюлька" c с доступными MODE-ами каналов // "Базюлька" c с доступными MODE-ами каналов.
var availableChanModes = boolcollection.NewCollection() var availableChanModes = boolcollection.NewCollection()
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */ /* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -8,7 +8,7 @@ import "strings"
активируют мягкий ratelimit на стороне сервера, без них, сервер просто рвёт соединение по превышению лимитов активируют мягкий ratelimit на стороне сервера, без них, сервер просто рвёт соединение по превышению лимитов
*/ */
// Удаляет сведения о MODE-ах пользователя для заданного канала // Удаляет сведения о MODE-ах пользователя для заданного канала.
func userModeDeleteUser(ircChan string, nick string) { func userModeDeleteUser(ircChan string, nick string) {
channel, ok := userMode.Get(ircChan) channel, ok := userMode.Get(ircChan)
@@ -24,16 +24,17 @@ func userModeDeleteUser(ircChan string, nick string) {
} }
} }
// Удаляет сведения о MODE-ах пользователя для всех каналов, на которых есть бот // Удаляет сведения о MODE-ах пользователя для всех каналов, на которых есть бот.
func userModePurgeUser(nick string) { func userModePurgeUser(nick string) {
for _, channel := range config.Irc.Channels { for _, channel := range config.Irc.Channels {
userModeDeleteUser(channel, nick) userModeDeleteUser(channel, nick)
} }
} }
// Обновляет или создаёт запись о mode-ах пользователей // Обновляет или создаёт запись о mode-ах пользователей.
func userModeUpdateUser(ircChan string, nick string, modes string) { func userModeUpdateUser(ircChan string, nick string, modes string) {
var channelData map[string]map[string]bool var channelData map[string]map[string]bool
channel, ok := userMode.Get(ircChan) channel, ok := userMode.Get(ircChan)
if ok { if ok {
@@ -48,12 +49,12 @@ func userModeUpdateUser(ircChan string, nick string, modes string) {
channelData[nick] = make(map[string]bool) channelData[nick] = make(map[string]bool)
} }
switch { switch modes[:1] {
case modes[:1] == "+": case "+":
for _, mode := range strings.Split(modes[1:], "") { for _, mode := range strings.Split(modes[1:], "") {
channelData[nick][mode] = true channelData[nick][mode] = true
} }
case modes[:1] == "-": case "-":
for _, mode := range strings.Split(modes[1:], "") { for _, mode := range strings.Split(modes[1:], "") {
channelData[nick][mode] = false channelData[nick][mode] = false
} }
@@ -62,9 +63,10 @@ func userModeUpdateUser(ircChan string, nick string, modes string) {
userMode.Set(ircChan, channelData) userMode.Set(ircChan, channelData)
} }
// Возвращает значение MODE-а v для запрошенного ника // Возвращает значение MODE-а v для запрошенного ника.
func userModeIsVoiced(ircChan string, nick string) bool { func userModeIsVoiced(ircChan string, nick string) bool {
var channelData map[string]map[string]bool var channelData map[string]map[string]bool
channel, ok := userMode.Get(ircChan) channel, ok := userMode.Get(ircChan)
if ok { if ok {
@@ -88,9 +90,10 @@ func userModeIsVoiced(ircChan string, nick string) bool {
return false return false
} }
// Возвращает значение MODE-а o для запрошенного ника // Возвращает значение MODE-а o для запрошенного ника.
func userModeIsOped(ircChan string, nick string) bool { func userModeIsOped(ircChan string, nick string) bool {
var channelData map[string]map[string]bool var channelData map[string]map[string]bool
channel, ok := userMode.Get(ircChan) channel, ok := userMode.Get(ircChan)
if ok { if ok {
@@ -116,6 +119,7 @@ func userModeIsOped(ircChan string, nick string) bool {
func userModeIsHere(ircChan string, nick string) bool { func userModeIsHere(ircChan string, nick string) bool {
var channelData map[string]map[string]bool var channelData map[string]map[string]bool
channel, ok := userMode.Get(ircChan) channel, ok := userMode.Get(ircChan)
if ok { if ok {

View File

@@ -11,7 +11,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// Производит некоторую инициализацию перед запуском main() // Производит некоторую инициализацию перед запуском main().
func init() { func init() {
log.SetFormatter(&log.TextFormatter{ log.SetFormatter(&log.TextFormatter{
DisableQuote: true, DisableQuote: true,
@@ -52,7 +52,7 @@ func init() {
userMode.Delete("channel") userMode.Delete("channel")
} }
// Собственно, какбэ "точка входа" - основная процедура в нашем боте // Собственно, какбэ "точка входа" - основная процедура в нашем боте.
func main() { func main() {
// Main context // Main context
var ctx = context.Background() var ctx = context.Background()

View File

@@ -9,8 +9,8 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// ircMsgParser парсит сообщения, прилетевшие из IRC-ки // ircMsgParser парсит сообщения, прилетевшие из IRC-ки.
func ircMsgParser(channel string, nick string, user string, source string, msg string) { func ircMsgParser(channel string, nick string, user string, source string, msg string) { //nolint: revive
// nick - это выбранный пользователем nick (если он занят, то его "нарисует" сервер) // nick - это выбранный пользователем nick (если он занят, то его "нарисует" сервер)
// user - это короткое имя пользователя, под которым его видит сервер // user - это короткое имя пользователя, под которым его видит сервер
// source - это длинное имя пользователя, оно содержит в себе помимо user, ещё и ip с которого пришёл пользователь // source - это длинное имя пользователя, оно содержит в себе помимо user, ещё и ip с которого пришёл пользователь
@@ -48,50 +48,50 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
switch { switch {
case cmd == "help" || msg == "помощь": case cmd == "help" || msg == "помощь":
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%shelp | %sпомощь - это сообщение", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%shelp | %sпомощь - это сообщение", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sanek | %sанек | %sанекдот - рандомный анекдот с anekdot.ru", config.Csign, config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sanek | %sанек | %sанекдот - рандомный анекдот с anekdot.ru", config.Csign, config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sbuni - комикс-стрип hapi buni", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sbuni - комикс-стрип hapi buni", config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sbunny - кролик", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sbunny - кролик", config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%srabbit | %sкролик - кролик", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%srabbit | %sкролик - кролик", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%scat | %sкис - кошечка", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%scat | %sкис - кошечка", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sdice | %sroll | %sкости - бросить кости", config.Csign, config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sdice | %sroll | %sкости - бросить кости", config.Csign, config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sdig | %sкопать - заняться археологией", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sdig | %sкопать - заняться археологией", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sdrink | %sпраздник - какой сегодня праздник?", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sdrink | %sпраздник - какой сегодня праздник?", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sfish | %sfisher - порыбачить", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sfish | %sfisher - порыбачить", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sрыба | %sрыбка | %sрыбалка - порыбачить", config.Csign, config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sрыба | %sрыбка | %sрыбалка - порыбачить", config.Csign, config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sf | %sф - рандомная фраза из сборника цитат fortune_mod", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sf | %sф - рандомная фраза из сборника цитат fortune_mod", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sfortune | %sфортунка - рандомная фраза из сборника цитат fortune_mod", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sfortune | %sфортунка - рандомная фраза из сборника цитат fortune_mod", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sfox | %sлис - лисичка", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sfox | %sлис - лисичка", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sfriday | %sпятница - а не пятница ли сегодня?", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sfriday | %sпятница - а не пятница ли сегодня?", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sfrog | %sлягушка - лягушка", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sfrog | %sлягушка - лягушка", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%shorse | %sлошадь | %sлошадка - лошадка", config.Csign, config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%shorse | %sлошадь | %sлошадка - лошадка", config.Csign, config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%skarma фраза - посмотреть карму фразы", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%skarma фраза - посмотреть карму фразы", config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sкарма фраза - посмотреть карму фразы", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sкарма фраза - посмотреть карму фразы", config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintln("фраза++ | фраза-- - повысить или понизить карму фразы")} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintln("фраза++ | фраза-- - повысить или понизить карму фразы")}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%slat | %sлат - сгенерировать фразу из крылатого латинского выражения", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%slat | %sлат - сгенерировать фразу из крылатого латинского выражения", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%smonkeyuser - комикс-стрип MonkeyUser", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%smonkeyuser - комикс-стрип MonkeyUser", config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sowl | %sсова - сова", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sowl | %sсова - сова", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sping | %sпинг - попинговать бота", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sping | %sпинг - попинговать бота", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sproverb | %sпословица - рандомная русская пословица", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sproverb | %sпословица - рандомная русская пословица", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%ssnail | %sулитка - улитка", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%ssnail | %sулитка - улитка", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%ssome_brew - выдать соответствующий напиток, бармен может налить rum, ром, vodka, водку, tequila, текила, whisky, виски, absinthe, абсент", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%ssome_brew - выдать соответствующий напиток, бармен может налить rum, ром, vodka, водку, tequila, текила, whisky, виски, absinthe, абсент", config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sver | %sversion - написать что-то про версию ПО", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sver | %sversion - написать что-то про версию ПО", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sверсия - написать что-то про версию ПО", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sверсия - написать что-то про версию ПО", config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sw <город> | %sп <город> - погода в городе", config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sw <город> | %sп <город> - погода в городе", config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sxkcd - комикс-стрип с xkcb.ru", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sxkcd - комикс-стрип с xkcb.ru", config.Csign)}
if userModeIsOped(channel, nick) { if userModeIsOped(channel, nick) {
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sadmin - настройки некоторых плагинов бота для канала", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sadmin - настройки некоторых плагинов бота для канала", config.Csign)}
} }
return return
case cmd == "admin": case cmd == "admin":
if userModeIsOped(channel, nick) { if userModeIsOped(channel, nick) {
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sadmin oboobs # - где 1 - вкл, 0 - выкл плагина oboobs", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sadmin oboobs # - где 1 - вкл, 0 - выкл плагина oboobs", config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sadmin oboobs показываем ли сисечки по просьбе участников чата (команды %stits, %stities, %sboobs, %sboobies, %sсиси, %sсисечки)", config.Csign, config.Csign, config.Csign, config.Csign, config.Csign, config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sadmin oboobs показываем ли сисечки по просьбе участников чата (команды %stits, %stities, %sboobs, %sboobies, %sсиси, %sсисечки)", config.Csign, config.Csign, config.Csign, config.Csign, config.Csign, config.Csign, config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sadmin obutts # - где 1 - вкл, 0 - выкл плагина obutts", config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sadmin obutts # - где 1 - вкл, 0 - выкл плагина obutts", config.Csign)}
imChan <- iMsg{ChatId: nick, Text: fmt.Sprintf("%sadmin obutts показываем ли попки по просьбе участников чата (команды %sass, %sbutt, %sbooty, %sпопа, %sпопка)", config.Csign, config.Csign, config.Csign, config.Csign, config.Csign, config.Csign)} imChan <- iMsg{ChatID: nick, Text: fmt.Sprintf("%sadmin obutts показываем ли попки по просьбе участников чата (команды %sass, %sbutt, %sbooty, %sпопа, %sпопка)", config.Csign, config.Csign, config.Csign, config.Csign, config.Csign, config.Csign)}
} }
return return
@@ -100,16 +100,16 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
if userModeIsOped(channel, nick) { if userModeIsOped(channel, nick) {
value := getSetting(channel, "oboobs") value := getSetting(channel, "oboobs")
switch { switch value {
case value == "": case "":
_ = saveSetting(channel, "oboobs", "0") _ = saveSetting(channel, "oboobs", "0")
imChan <- iMsg{ChatId: nick, Text: "Плагин oboobs выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин oboobs выключен"}
case value == "0": case "0":
imChan <- iMsg{ChatId: nick, Text: "Плагин oboobs выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин oboobs выключен"}
case value == "1": case "1":
imChan <- iMsg{ChatId: nick, Text: "Плагин oboobs включен"} imChan <- iMsg{ChatID: nick, Text: "Плагин oboobs включен"}
default: default:
imChan <- iMsg{ChatId: nick, Text: "Плагин oboobs выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин oboobs выключен"}
} }
} }
@@ -120,9 +120,9 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
err := saveSetting(channel, "oboobs", "1") err := saveSetting(channel, "oboobs", "1")
if err != nil { if err != nil {
imChan <- iMsg{ChatId: nick, Text: "Плагин oboobs всё ещё выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин oboobs всё ещё выключен"}
} else { } else {
imChan <- iMsg{ChatId: nick, Text: "Плагин oboobs включен"} imChan <- iMsg{ChatID: nick, Text: "Плагин oboobs включен"}
} }
} }
@@ -131,7 +131,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
case cmd == "admin oboobs 0": case cmd == "admin oboobs 0":
if userModeIsOped(channel, nick) { if userModeIsOped(channel, nick) {
_ = saveSetting(channel, "oboobs", "0") _ = saveSetting(channel, "oboobs", "0")
imChan <- iMsg{ChatId: nick, Text: "Плагин oboobs выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин oboobs выключен"}
} }
return return
@@ -140,16 +140,16 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
if userModeIsOped(channel, nick) { if userModeIsOped(channel, nick) {
value := getSetting(channel, "obutts") value := getSetting(channel, "obutts")
switch { switch value {
case value == "": case "":
_ = saveSetting(channel, "obutts", "0") _ = saveSetting(channel, "obutts", "0")
imChan <- iMsg{ChatId: nick, Text: "Плагин obutts выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин obutts выключен"}
case value == "0": case "0":
imChan <- iMsg{ChatId: nick, Text: "Плагин obutts выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин obutts выключен"}
case value == "1": case "1":
imChan <- iMsg{ChatId: nick, Text: "Плагин obutts включен"} imChan <- iMsg{ChatID: nick, Text: "Плагин obutts включен"}
default: default:
imChan <- iMsg{ChatId: nick, Text: "Плагин obutts выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин obutts выключен"}
} }
} }
@@ -160,9 +160,9 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
err := saveSetting(channel, "obutts", "1") err := saveSetting(channel, "obutts", "1")
if err != nil { if err != nil {
imChan <- iMsg{ChatId: nick, Text: "Плагин obutts всё ещё выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин obutts всё ещё выключен"}
} else { } else {
imChan <- iMsg{ChatId: nick, Text: "Плагин obutts включен"} imChan <- iMsg{ChatID: nick, Text: "Плагин obutts включен"}
} }
} }
@@ -171,7 +171,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
case cmd == "admin obutts 0": case cmd == "admin obutts 0":
if userModeIsOped(channel, nick) { if userModeIsOped(channel, nick) {
_ = saveSetting(channel, "obutts", "0") _ = saveSetting(channel, "obutts", "0")
imChan <- iMsg{ChatId: nick, Text: "Плагин obutts выключен"} imChan <- iMsg{ChatID: nick, Text: "Плагин obutts выключен"}
} }
return return
@@ -192,6 +192,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
if cmd == command { if cmd == command {
done = true done = true
outgoingMessage = msg outgoingMessage = msg
break break
} }
} }
@@ -206,6 +207,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
if cmd == command { if cmd == command {
done = true done = true
outgoingMessage = msg outgoingMessage = msg
break break
} }
} }
@@ -226,7 +228,8 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
message.Misc.Username = strings.TrimSpace(pile[1]) message.Misc.Username = strings.TrimSpace(pile[1])
} else { } else {
msg = fmt.Sprintf("Я тут не вижу участника с ником %s", userNick) msg = fmt.Sprintf("Я тут не вижу участника с ником %s", userNick)
imChan <- iMsg{ChatId: channel, Text: msg} imChan <- iMsg{ChatID: channel, Text: msg}
return return
} }
} // в противном случае юзер просто поставил пробел на конце команды, интерпретируем это как } // в противном случае юзер просто поставил пробел на конце команды, интерпретируем это как
@@ -234,6 +237,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
outgoingMessage = msg outgoingMessage = msg
done = true done = true
break break
} }
} }
@@ -250,6 +254,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
if cmdLen > len(command) && cmd[0:len(command)] == command { if cmdLen > len(command) && cmd[0:len(command)] == command {
done = true done = true
outgoingMessage = msg outgoingMessage = msg
break break
} }
} }
@@ -267,6 +272,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
if cmd[:cmdLen] == command { if cmd[:cmdLen] == command {
done = true done = true
outgoingMessage = msg outgoingMessage = msg
break break
} }
} }
@@ -283,6 +289,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
if cmd[:cmdLen] == command { if cmd[:cmdLen] == command {
// done = true // done = true
outgoingMessage = msg outgoingMessage = msg
break break
} }
} }
@@ -297,6 +304,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
if err != nil { if err != nil {
log.Warnf("Unable to to serialize message for redis: %s", err) log.Warnf("Unable to to serialize message for redis: %s", err)
return return
} }
@@ -351,6 +359,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
if err != nil { if err != nil {
log.Warnf("Unable to to serialize message for redis: %s", err) log.Warnf("Unable to to serialize message for redis: %s", err)
return return
} }
@@ -363,7 +372,7 @@ func ircMsgParser(channel string, nick string, user string, source string, msg s
} }
} }
// redisMsgParser парсит json-чики прилетевшие из REDIS-ки, причём, json-чики должны быть относительно валидными // redisMsgParser парсит json-чики прилетевшие из REDIS-ки, причём, json-чики должны быть относительно валидными.
func redisMsgParser(msg string) { func redisMsgParser(msg string) {
if shutdown { if shutdown {
// Если мы завершаем работу программы, то нам ничего обрабатывать не надо // Если мы завершаем работу программы, то нам ничего обрабатывать не надо
@@ -376,43 +385,51 @@ func redisMsgParser(msg string) {
if err := json.Unmarshal([]byte(msg), &j); err != nil { if err := json.Unmarshal([]byte(msg), &j); err != nil {
log.Warnf("Unable to to parse message from redis channel: %s", err) log.Warnf("Unable to to parse message from redis channel: %s", err)
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)
return return
} }
if exist := j.Chatid; exist == "" { if exist := j.Chatid; exist == "" {
log.Warnf("Incorrect msg from redis, no chatid field: %s", msg) log.Warnf("Incorrect msg from redis, no chatid field: %s", msg)
return return
} }
if exist := j.Userid; exist == "" { if exist := j.Userid; exist == "" {
log.Warnf("Incorrect msg from redis, no userid field: %s", msg) log.Warnf("Incorrect msg from redis, no userid field: %s", msg)
return return
} }
if exist := j.Message; exist == "" { if exist := j.Message; exist == "" {
log.Warnf("Incorrect msg from redis, no message field: %s", msg) log.Warnf("Incorrect msg from redis, no message field: %s", msg)
return return
} }
if exist := j.Plugin; exist == "" { if exist := j.Plugin; exist == "" {
log.Warnf("Incorrect msg from redis, no plugin field: %s", msg) log.Warnf("Incorrect msg from redis, no plugin field: %s", msg)
return return
} }
if exist := j.Mode; exist == "" { if exist := j.Mode; exist == "" {
log.Warnf("Incorrect msg from redis, no mode field: %s", msg) log.Warnf("Incorrect msg from redis, no mode field: %s", msg)
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")
return return
} }
@@ -436,9 +453,9 @@ func redisMsgParser(msg string) {
for _, message := range lines { for _, message := range lines {
if userModeIsOped(j.Chatid, ircClient.GetNick()) || userModeIsVoiced(j.Chatid, ircClient.GetNick()) { if userModeIsOped(j.Chatid, ircClient.GetNick()) || userModeIsVoiced(j.Chatid, ircClient.GetNick()) {
imChanUnrestricted <- iMsg{ChatId: j.Chatid, Text: message} imChanUnrestricted <- iMsg{ChatID: j.Chatid, Text: message}
} else { } else {
imChan <- iMsg{ChatId: j.Chatid, Text: message} imChan <- iMsg{ChatID: j.Chatid, Text: message}
} }
} }
} }

View File

@@ -11,9 +11,10 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// StoreKV сохраняет в указанной бд ключ и значение // StoreKV сохраняет в указанной бд ключ и значение.
func StoreKV(db *pebble.DB, key string, value string) error { func StoreKV(db *pebble.DB, key string, value string) error {
var kArray = []byte(key) var kArray = []byte(key)
var vArray = []byte(value) var vArray = []byte(value)
err := db.Set(kArray, vArray, pebble.Sync) err := db.Set(kArray, vArray, pebble.Sync)
@@ -21,11 +22,12 @@ func StoreKV(db *pebble.DB, key string, value string) error {
return err return err
} }
// FetchV достаёт значение по ключу // FetchV достаёт значение по ключу.
func FetchV(db *pebble.DB, key string) (string, error) { func FetchV(db *pebble.DB, key string) (string, error) {
var kArray = []byte(key) var kArray = []byte(key)
var vArray []byte var vArray []byte
var valueString = "" var valueString = ""
vArray, closer, err := db.Get(kArray) vArray, closer, err := db.Get(kArray)
@@ -40,7 +42,7 @@ func FetchV(db *pebble.DB, key string) (string, error) {
return valueString, err return valueString, err
} }
// Достанем настройку из БД с настройками // Достанем настройку из БД с настройками.
func getSetting(chatID string, setting string) string { func getSetting(chatID string, setting string) string {
var err error var err error
@@ -58,6 +60,7 @@ func getSetting(chatID string, setting string) string {
if err != nil { if err != nil {
log.Errorf("Unable to open settings db, %s: %s\n", database, err) log.Errorf("Unable to open settings db, %s: %s\n", database, err)
return "" return ""
} }
} }
@@ -66,13 +69,14 @@ func getSetting(chatID string, setting string) string {
// Если из базы ничего не вынулось, по каким-то причинам, то просто вернём пустую строку // Если из базы ничего не вынулось, по каким-то причинам, то просто вернём пустую строку
if err != nil { if err != nil {
if errors.Is(err, pebble.ErrNotFound) { switch {
case errors.Is(err, pebble.ErrNotFound):
log.Debugf("Unable to get value for %s: no record found in db %s", setting, database) log.Debugf("Unable to get value for %s: no record found in db %s", setting, database)
} else if errors.Is(err, fs.ErrNotExist) { case errors.Is(err, fs.ErrNotExist):
log.Debugf("Unable to get value for %s: db dir %s does not exist", setting, database) log.Debugf("Unable to get value for %s: db dir %s does not exist", setting, database)
} else if errors.Is(err, oserror.ErrNotExist) { case errors.Is(err, oserror.ErrNotExist):
log.Debugf("Unable to get value for %s: db dir %s does not exist", setting, database) log.Debugf("Unable to get value for %s: db dir %s does not exist", setting, database)
} else { default:
log.Errorf("Unable to get value for %s in db dir %s: %s", setting, database, err) log.Errorf("Unable to get value for %s in db dir %s: %s", setting, database, err)
} }
@@ -82,10 +86,12 @@ func getSetting(chatID string, setting string) string {
return value return value
} }
// Сохраним настройку в БД с настройками // Сохраним настройку в БД с настройками.
func saveSetting(chatID string, setting string, value string) error { func saveSetting(chatID string, setting string, value string) error {
var chatHash = sha256.Sum256([]byte(chatID)) var chatHash = sha256.Sum256([]byte(chatID))
var database = fmt.Sprintf("settings_db/%x", chatHash) var database = fmt.Sprintf("settings_db/%x", chatHash)
var err error var err error
// Если БД не открыта, откроем её // Если БД не открыта, откроем её
@@ -100,6 +106,7 @@ func saveSetting(chatID string, setting string, value string) error {
if err != nil { if err != nil {
log.Errorf("Unable to open settings db, %s: %s\n", database, err) log.Errorf("Unable to open settings db, %s: %s\n", database, err)
return err return err
} }
} }

View File

@@ -1,6 +1,6 @@
package main package main
// Конфиг // Конфиг.
type myConfig struct { type myConfig struct {
Redis struct { Redis struct {
Server string `json:"server,omitempty"` Server string `json:"server,omitempty"`
@@ -35,7 +35,7 @@ type myConfig struct {
DataDir string `json:"data_dir,omitempty"` DataDir string `json:"data_dir,omitempty"`
} }
// Входящее сообщение из pubsub-канала redis-ки // Входящее сообщение из pubsub-канала redis-ки.
type rMsg struct { type rMsg struct {
From string `json:"from,omitempty"` From string `json:"from,omitempty"`
Chatid string `json:"chatid,omitempty"` Chatid string `json:"chatid,omitempty"`
@@ -55,7 +55,7 @@ type rMsg struct {
} `json:"Misc"` } `json:"Misc"`
} }
// Исходящее сообщение в pubsub-канал redis-ки // Исходящее сообщение в pubsub-канал redis-ки.
type sMsg struct { type sMsg struct {
From string `json:"from"` From string `json:"from"`
Chatid string `json:"chatid"` Chatid string `json:"chatid"`
@@ -75,14 +75,13 @@ type sMsg struct {
} `json:"misc"` } `json:"misc"`
} }
// Сообщение в irc // TODO: Имплементировать тип сообщения - privmsg или action.
// TODO: Имплементировать тип сообщения - privmsg или action
type iMsg struct { type iMsg struct {
ChatId string ChatID string
Text string Text string
} }
// "Ведёрко" для реализации ограничителя скорости отправки исходящих сообщений - Token Bucket // "Ведёрко" для реализации ограничителя скорости отправки исходящих сообщений - Token Bucket.
type bucket struct { type bucket struct {
Timestamps []int64 Timestamps []int64
IsFull bool IsFull bool

15
util.go
View File

@@ -11,7 +11,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// Читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге нет // Читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге нет.
func readConfig() { func readConfig() {
configLoaded := false configLoaded := false
executablePath, err := os.Executable() executablePath, err := os.Executable()
@@ -40,6 +40,7 @@ func readConfig() {
// Конфиг-файл длинноват для конфига, попробуем следующего кандидата // Конфиг-файл длинноват для конфига, попробуем следующего кандидата
if fileInfo.Size() > 65535 { if fileInfo.Size() > 65535 {
log.Warnf("Config file %s is too long for config, skipping", location) log.Warnf("Config file %s is too long for config, skipping", location)
continue continue
} }
@@ -48,6 +49,7 @@ func readConfig() {
// Не удалось прочитать, попробуем следующего кандидата // Не удалось прочитать, попробуем следующего кандидата
if err != nil { if err != nil {
log.Warnf("Skip reading config file %s: %s", location, err) log.Warnf("Skip reading config file %s: %s", location, err)
continue continue
} }
@@ -55,12 +57,14 @@ func readConfig() {
// Интереснее на выходе получить структурку: то есть мы вначале конфиг преобразуем в map-ку, затем эту map-ку // Интереснее на выходе получить структурку: то есть мы вначале конфиг преобразуем в map-ку, затем эту map-ку
// сериализуем в json, а потом json преврщааем в стркутурку. Не очень эффективно, но он и не часто требуется. // сериализуем в json, а потом json преврщааем в стркутурку. Не очень эффективно, но он и не часто требуется.
var sampleConfig myConfig var sampleConfig myConfig
var tmp map[string]interface{} var tmp map[string]interface{}
err = hjson.Unmarshal(buf, &tmp) err = hjson.Unmarshal(buf, &tmp)
// Не удалось распарсить - попробуем следующего кандидата // Не удалось распарсить - попробуем следующего кандидата
if err != nil { if err != nil {
log.Warnf("Skip parsing config file %s: %s", location, err) log.Warnf("Skip parsing config file %s: %s", location, err)
continue continue
} }
@@ -69,17 +73,20 @@ func readConfig() {
// Не удалось преобразовать map-ку в json // Не удалось преобразовать map-ку в json
if err != nil { if err != nil {
log.Warnf("Skip parsing config file %s: %s", location, err) log.Warnf("Skip parsing config file %s: %s", location, err)
continue continue
} }
if err := json.Unmarshal(tmpjson, &sampleConfig); err != nil { if err := json.Unmarshal(tmpjson, &sampleConfig); err != nil {
log.Warnf("Skip parsing config file %s: %s", location, err) log.Warnf("Skip parsing config file %s: %s", location, err)
continue continue
} }
// Валидируем значения из конфига // Валидируем значения из конфига
if sampleConfig.Redis.Server == "" { if sampleConfig.Redis.Server == "" {
sampleConfig.Redis.Server = "localhost" sampleConfig.Redis.Server = "localhost"
log.Infof("Redis server is not defined in config, using localhost") log.Infof("Redis server is not defined in config, using localhost")
} }
@@ -100,11 +107,13 @@ func readConfig() {
// Значения для IRC-клиента // Значения для IRC-клиента
if sampleConfig.Irc.Server == "" { if sampleConfig.Irc.Server == "" {
sampleConfig.Irc.Server = "localhost" sampleConfig.Irc.Server = "localhost"
log.Errorf("Irc server is not defined in config, using localhost") log.Errorf("Irc server is not defined in config, using localhost")
} }
if sampleConfig.Irc.Port == 0 { if sampleConfig.Irc.Port == 0 {
sampleConfig.Irc.Port = 6667 sampleConfig.Irc.Port = 6667
log.Infof("Irc port is not defined in config, using 6667") log.Infof("Irc port is not defined in config, using 6667")
} }
@@ -181,7 +190,9 @@ func readConfig() {
config = sampleConfig config = sampleConfig
configLoaded = true configLoaded = true
log.Infof("Using %s as config file", location) log.Infof("Using %s as config file", location)
break break
} }
@@ -191,7 +202,7 @@ func readConfig() {
} }
} }
// Хэндлер сигналов закрывает все бд, все сетевые соединения и сваливает из приложения // Хэндлер сигналов закрывает все бд, все сетевые соединения и сваливает из приложения.
func sigHandler() { func sigHandler() {
var err error var err error