Implement help, помощь, rehash commands, restrict presence collection precedure

This commit is contained in:
eleksir
2023-09-03 14:52:35 +03:00
parent 91eac5cb6d
commit ca384b5165
7 changed files with 322 additions and 54 deletions

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env gmake -f #!/usr/bin/env gmake -f
BUILDOPTS=-ldflags="-s -w" -a -gcflags=all=-l -trimpath -pgo=auto BUILDOPTS=-ldflags="-s -w" -a -gcflags=all=-l -trimpath -pgo=auto
FILELIST=collection.go types.go globals.go lib.go event_parser.go buny.go commands.go main.go
all: clean build all: clean build
@@ -9,15 +10,15 @@ ifeq ($(OS),Windows_NT)
# powershell # powershell
ifeq ($(SHELL),sh.exe) ifeq ($(SHELL),sh.exe)
SET CGO_ENABLED=0 SET CGO_ENABLED=0
go build ${BUILDOPTS} -o "buny-jabber-bot" collection.go types.go globals.go lib.go event_parser.go buny.go main.go go build ${BUILDOPTS} -o "buny-jabber-bot" ${FILELIST}
else else
# jetbrains golang # jetbrains golang
CGO_ENABLED=0 CGO_ENABLED=0
go build ${BUILDOPTS} -o "buny-jabber-bot" collection.go types.go globals.go lib.go event_parser.go buny.go main.go go build ${BUILDOPTS} -o "buny-jabber-bot" ${FILELIST}
endif endif
# bash/git bash # bash/git bash
else else
CGO_ENABLED=0 go build ${BUILDOPTS} -o "buny-jabber-bot" collection.go types.go globals.go lib.go event_parser.go buny.go main.go CGO_ENABLED=0 go build ${BUILDOPTS} -o "buny-jabber-bot" ${FILELIST}
endif endif
clean: clean:

141
commands.go Normal file
View File

@@ -0,0 +1,141 @@
package main
import (
"fmt"
"strings"
"github.com/davecgh/go-spew/spew"
"github.com/eleksir/go-xmpp"
log "github.com/sirupsen/logrus"
)
func cmd(v xmpp.Chat) error {
var err error
switch {
case v.Text == fmt.Sprintf("%shelp", config.CSign) || v.Text == fmt.Sprintf("%sпомощь", config.CSign):
var (
answer string
chosenOneTalks = false
)
realJID := getRealJIDfromNick(v.Remote)
for _, master := range config.Jabber.BotMasters {
if (strings.SplitN(realJID, "/", 2))[0] == master {
chosenOneTalks = true
}
}
if chosenOneTalks {
answer = fmt.Sprintf("%sпомощь - этот список команд\n", config.CSign)
answer += fmt.Sprintf("%shelp - this commands list\n", config.CSign)
answer += fmt.Sprintf("%srehash - reload white and black lists", config.CSign)
} else {
answer = "Ничем помочь не могу. Луна не светит на тебя."
}
dest := v.Remote
if v.Type == "groupchat" {
dest = (strings.SplitN(v.Remote, "/", 2))[0]
}
if _, err := talk.Send(
xmpp.Chat{ //nolint:exhaustruct
Remote: dest,
Text: strings.TrimSpace(answer),
Type: v.Type,
},
); err != nil {
err = fmt.Errorf("unable to send message to %s: %w", v.Remote, err)
return err
}
case v.Text == fmt.Sprintf("%srehash", config.CSign):
/* Эта команда может прилетать из приватной беседы с realjid-ом, из приватной беседы с chat-nick-ом, а также из
* чятика.
* Groupchat мы можем определить по v.Type (groupchat) и тогда понятно что делать.
* А вот, например, приватные притязания определить несколько сложно-вато. Но можно попробовать, например,
* пытаться по списку presence-ов находить персонажа и его real jid и уже из этого определять master он или нет.
*/
// Попробуем определить каков алгоритм наших действий, в зависимости от типа сообщения
switch v.Type {
case "groupchat":
// Проверим, является ли "командир" избранным или это самозванец?
var (
chosenOneTalks = false
listsLoaded = true
)
realJID := getRealJIDfromNick(v.Remote)
for _, master := range config.Jabber.BotMasters {
if (strings.SplitN(realJID, "/", 2))[0] == master {
chosenOneTalks = true
}
}
if !chosenOneTalks {
log.Infof(
"Command %srehash given by non-bot_master user %s(%s), ignoring",
config.CSign,
realJID,
v.Remote,
)
return err
}
if err := readWhitelist(); err != nil {
listsLoaded = false
var msg xmpp.Chat
msg.Remote = v.Remote
msg.Type = "chat" // private message
msg.Text = fmt.Sprint(err)
if _, err := talk.Send(msg); err != nil {
return err
}
}
if err := readBlacklist(); err != nil {
listsLoaded = false
var msg xmpp.Chat
msg.Remote = v.Remote
msg.Type = "chat" // private message
msg.Text = fmt.Sprint(err)
if _, err := talk.Send(msg); err != nil {
return err
}
}
if listsLoaded {
room := (strings.SplitN(v.Remote, "/", 2))[0]
var msg xmpp.Chat
msg.Remote = room
msg.Type = v.Type
msg.Text = "Сделано"
if _, err := talk.Send(msg); err != nil {
return err
}
}
case "chat":
default:
log.Infof("Rehash command from outer space: %s", spew.Sdump(v))
}
return err
default:
return err
}
return err
}

View File

@@ -3,46 +3,80 @@
"jabber": { "jabber": {
# Если не задан, будет localhost # Если не задан, будет localhost
"server": "jabber.tld", "server": "jabber.tld",
# Если не задано - 5222 для нешифрованного соединения или для starttls и 5223 для голого (старорежимного) ssl # Если не задано - 5222 для нешифрованного соединения или для starttls и 5223 для голого (старорежимного) ssl
"port": 5222, "port": 5222,
# Включить шифрование # Включить шифрование
"ssl": true, "ssl": true,
# Это более современный протокол и как раз на нём работет большинство jabber-серверов, порт 5222, # Это более современный протокол и как раз на нём работет большинство jabber-серверов, порт 5222,
# jabber.ru по этому протоколу как-то странно работает, если его включить, я получаю # jabber.ru по этому протоколу как-то странно работает, если его включить, я получаю
# tls: first record does not look like a TLS handshake # tls: first record does not look like a TLS handshake
"starttls" : true, "starttls" : true,
# Не проверяем сертификаты по-умолчанию. # Не проверяем сертификаты по-умолчанию.
# Вам правда хочется всё это проверять? Там по идее могут быть всякие Lets Encrypt, которые хоть и работают, но # Вам правда хочется всё это проверять? Там по идее могут быть всякие Lets Encrypt, которые хоть и работают, но
# создают кучу проблем # создают кучу проблем
"ssl_verify": false, "ssl_verify": false,
# Позволять авторизацию логин-паролем по незашифрованному каналу связи # Позволять авторизацию логин-паролем по незашифрованному каналу связи
"insecureallowunencryptedauth": false, "insecureallowunencryptedauth": false,
# Таймаут установления соединения с сервером, в секундах. 10 секунд, если не задано. # Таймаут установления соединения с сервером, в секундах. 10 секунд, если не задано.
"connection_timeout": 10, "connection_timeout": 10,
# Задержка перед пере-коннекчиванием. 3 секунды, если не задано. # Задержка перед пере-коннекчиванием. 3 секунды, если не задано.
"reconnect_delay": 3, "reconnect_delay": 3,
# Промежуток между пингами сервера, для определения его живости. По-умолчанию 60 секунд. # Промежуток между пингами сервера, для определения его живости. По-умолчанию 60 секунд.
# Пинги посылаются, если в течение этого времени не было активности со стороны сервера. # Пинги посылаются, если в течение этого времени не было активности со стороны сервера.
"server_ping_delay": 60, "server_ping_delay": 60,
# Промежуток между пингами muc-ов. По-умолчанию 900 секунд. (Согласно рекомендации в xep-0410.) # Промежуток между пингами muc-ов. По-умолчанию 900 секунд. (Согласно рекомендации в xep-0410.)
# Пинги посылаются, если в течение этого времени не было активности со стороны muc-а. # Пинги посылаются, если в течение этого времени не было активности со стороны muc-а.
"muc_ping_delay": 900, "muc_ping_delay": 900,
# Сколько ждать перед переджоиванием к комнате. По-умолчанию, 3 секунды. # Сколько ждать перед переджоиванием к комнате. По-умолчанию, 3 секунды.
"muc_rejoin_delay": 3, "muc_rejoin_delay": 3,
# Ping-to-ping splay delay. Варьируемая задержка между пингами, чтобы не набирать высокий message rate. # Ping-to-ping splay delay. Варьируемая задержка между пингами, чтобы не набирать высокий message rate.
# По-умолчанию, 3 секунды. Под капотом преобразуются в миллисекунды. Важна для пингов MUC-ов, особенно, # По-умолчанию, 3 секунды. Под капотом преобразуются в миллисекунды. Важна для пингов MUC-ов, особенно,
# если их МНОГО. # если их МНОГО.
"ping_splay_delay": 3, "ping_splay_delay": 3,
# Ник бота, с которым он будет заходить в комнаты # Ник бота, с которым он будет заходить в комнаты
"nick": "buny", "nick": "buny",
# Уникальная часть jid-а, специфичная для клиента # Уникальная часть jid-а, специфичная для клиента
"resource" : "Лунная призма", "resource" : "Лунная призма",
# Имя пользователя для авторизации на сервере
"user": "buny@jabber.tld",
# Пароль для авторизации
"password": "secret",
# Список JID-ов, которым позволено управлять ботом (например, давать отмашку на rehash).
# В списке jid-ы без resource-а.
# Если не задано ни одного мастера, то бот сам себе мастер.
"bot_masters": [
"luna@earth.tld"
],
# Jabber-каналы, к которым бот попробует присоединиться при старте
"channels": [
"my_channel@conference.jabber.tld",
"another_channel@conference.jabber.tld"
],
# Статус, с которым бот запускается. (если всё нормально, этот статус будет видать только в логах сервера и # Статус, с которым бот запускается. (если всё нормально, этот статус будет видать только в логах сервера и
# на долю секунды он промелькнёт у всех в ростере, у кого бот в знакомых. Может отсуствовать, тогда статус будет # на долю секунды он промелькнёт у всех в ростере, у кого бот в знакомых. Может отсуствовать, тогда статус будет
# пустой строкой # пустой строкой
"startup_status": [ "startup_status": [
"bunny bot is starting" "bunny bot is starting"
], ],
# Статус, который демонстрируется во время работы бота, как xa # Статус, который демонстрируется во время работы бота, как xa
# (по задумке - extended away, на практике, к away обычно отношения не имеет) # (по задумке - extended away, на практике, к away обычно отношения не имеет)
"runtime_status": { "runtime_status": {
@@ -62,15 +96,19 @@
"Звезда нашей надежды никогда не исчезнет. Пока она горит, всё будет в порядке. Мы не сможем проиграть", "Звезда нашей надежды никогда не исчезнет. Пока она горит, всё будет в порядке. Мы не сможем проиграть",
"Голова с хвостиками… Не вмешивайся в наши дела! Играть в войну — это опасно" "Голова с хвостиками… Не вмешивайся в наши дела! Играть в войну — это опасно"
], ],
# Период смены статуса, сек. Если параметра нет или он выставлен в 0, ротации не будет # Период смены статуса, сек. Если параметра нет или он выставлен в 0, ротации не будет
# 3 дня # 3 дня
"rotation_time": 259200, "rotation_time": 259200,
# Рандомная составляющая, добавляемая к периоду смены статуса, сек. # Рандомная составляющая, добавляемая к периоду смены статуса, сек.
# 4 дня # 4 дня
"rotation_splay_time": 345600 "rotation_splay_time": 345600
}, },
# Произносим ли что-то пафосное в момоент бана # Произносим ли что-то пафосное в момоент бана
"ban_phrases_enable": false, "ban_phrases_enable": false,
# Пафосные фраза, произносимые перед баном # Пафосные фраза, произносимые перед баном
"ban_phrases": [ "ban_phrases": [
"Во имя Луны, я накажу тебя!", "Во имя Луны, я накажу тебя!",
@@ -103,18 +141,12 @@
"Мы сражаемся за мир и равенство!", "Мы сражаемся за мир и равенство!",
"Мы — надежда для всех, кто нуждается в защите!", "Мы — надежда для всех, кто нуждается в защите!",
"Мы — воительницы справедливости, и ничто не остановит нас!" "Мы — воительницы справедливости, и ничто не остановит нас!"
],
# Имя пользователя для авторизации на сервере
"user": "buny@jabber.tld",
# Пароль для авторизации
"password": "secret",
# Jabber-каналы, к которым бот попробует присоединиться при старте
"channels": [
"my_channel@conference.jabber.tld",
"another_channel@conference.jabber.tld"
] ]
}, },
# command sign символ-суффикс команды, например !rehash или !help. По-умолчанию "!".
"csign" : "!",
# Многословность логов. Если не задано, то info. Debug - ДЕЙСТВИТЕЛЬНО вербозный уровень логгирования. # Многословность логов. Если не задано, то info. Debug - ДЕЙСТВИТЕЛЬНО вербозный уровень логгирования.
# Есть ещё trace :) # Есть ещё trace :)
"loglevel": "debug", "loglevel": "debug",

View File

@@ -42,6 +42,12 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
return return
} }
if err := cmd(v); err != nil {
gTomb.Kill(err)
return
}
lastActivity = lastServerActivity lastActivity = lastServerActivity
if muc, _ := strings.CutSuffix(v.Remote, "/"); muc != "" { if muc, _ := strings.CutSuffix(v.Remote, "/"); muc != "" {
@@ -55,6 +61,12 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
// eleksir@jabber.ru/array.lan - это если мы работаем через ростер // eleksir@jabber.ru/array.lan - это если мы работаем через ростер
log.Debugf("Private message: %s", v.Text) log.Debugf("Private message: %s", v.Text)
if err := cmd(v); err != nil {
gTomb.Kill(err)
return
}
lastActivity = lastServerActivity lastActivity = lastServerActivity
// Внезапно, ошибки. По идее они должны ассоциироваться с отправляемыми сообщениями, но по ходу это // Внезапно, ошибки. По идее они должны ассоциироваться с отправляемыми сообщениями, но по ходу это
@@ -539,7 +551,7 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
var p xmpp.Presence var p xmpp.Presence
_ = json.Unmarshal([]byte(presenceJSONstring), &p) _ = json.Unmarshal([]byte(presenceJSONstring), &p)
if p.JID == v.JID { if p.From == v.From {
continue continue
} }
@@ -551,15 +563,29 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
// Участник пришёл // Участник пришёл
default: default:
var presenceJSONStrings []string var presenceJSONStrings []string
var newPresenceJSONStrings []string
var presenceJSONBytes []byte var presenceJSONBytes []byte
if presenceJSONInterface, present := roomPresences.Get(room); present { if presenceJSONInterface, present := roomPresences.Get(room); present {
presenceJSONStrings = interfaceToStringSlice(presenceJSONInterface) presenceJSONStrings = interfaceToStringSlice(presenceJSONInterface)
} }
presenceJSONBytes, _ = json.Marshal(v) for _, presenceJSONString := range presenceJSONStrings {
presenceJSONStrings = append(presenceJSONStrings, string(presenceJSONBytes)) var p xmpp.Presence
roomPresences.Set(room, presenceJSONStrings) _ = json.Unmarshal([]byte(presenceJSONString), &p)
// Если находим, что у нас уже есть клиент с таким же From, то есть полным nick-ом (для grouchat)
// просто замещаем его.
if p.From == v.From {
continue
}
newPresenceJSONStrings = append(newPresenceJSONStrings, presenceJSONString)
}
presenceJSONBytes, _ = json.Marshal(v) //nolint:errchkjson
newPresenceJSONStrings = append(newPresenceJSONStrings, string(presenceJSONBytes))
roomPresences.Set(room, newPresenceJSONStrings)
} }
// Проверяем, а не злодей ли зашёл? Сделать это мы можем, только если мы находимся в комнате. // Проверяем, а не злодей ли зашёл? Сделать это мы можем, только если мы находимся в комнате.

123
lib.go
View File

@@ -2,11 +2,13 @@ package main
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"math/rand" "math/rand"
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"strings"
"syscall" "syscall"
"time" "time"
@@ -68,14 +70,19 @@ func sigHandler() {
// readConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге // readConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге
// нет. // нет.
func readConfig() { //nolint:gocognit,gocyclo func readConfig() error { //nolint:gocognit,gocyclo
configLoaded := false var (
executablePath, err := os.Executable() err error
executablePath string
configLoaded = false
)
executablePath, err = os.Executable()
if err != nil { if err != nil {
log.Errorf("Unable to get current executable path: %s", err) err := fmt.Errorf("unable to get current executable path: %w", err)
os.Exit(1) return err
} }
configJSONPath := fmt.Sprintf("%s/data/config.json", filepath.Dir(executablePath)) configJSONPath := fmt.Sprintf("%s/data/config.json", filepath.Dir(executablePath))
@@ -210,8 +217,7 @@ func readConfig() { //nolint:gocognit,gocyclo
} }
if sampleConfig.Jabber.Nick == "" { if sampleConfig.Jabber.Nick == "" {
log.Errorf("Jabber nick is not defined in config, quitting") return errors.New("jabber nick is not defined in config, quitting") //nolint:goerr113
os.Exit(1)
} }
if sampleConfig.Jabber.Resource == "" { if sampleConfig.Jabber.Resource == "" {
@@ -227,13 +233,15 @@ func readConfig() { //nolint:gocognit,gocyclo
} }
// Если sampleConfig.Jabber.Password не задан, то авторизации не будет // Если sampleConfig.Jabber.Password не задан, то авторизации не будет
// Если sampleConfig.Jabber.Sasl не задан, то авторизация происходит через NickServ
// Если sampleConfig.Jabber.BanPhrasesEnable не задан, то он false // Если не задано ни одного мастера, то бот сам себе мастер
if len(sampleConfig.Jabber.BotMasters) == 0 {
sampleConfig.Jabber.BotMasters[0] = sampleConfig.Jabber.User
}
// Если список фраз, с которыми банят пустой, то вносим в него одну позицию с пустой строкой // Нам бот нужен в каких-то чат-румах, а не "просто так"
if len(sampleConfig.Jabber.BanPhrases) == 0 { if len(sampleConfig.Jabber.Channels) < 1 {
sampleConfig.Jabber.BanPhrases[0] = "" return errors.New("no jabber channels/rooms defined in config, quitting") //nolint:goerr113
} }
// Если список фраз с которыми стартует бот пустой, вносим в него 1 запись с пустой строкой // Если список фраз с которыми стартует бот пустой, вносим в него 1 запись с пустой строкой
@@ -249,10 +257,15 @@ func readConfig() { //nolint:gocognit,gocyclo
// Если sampleConfig.Jabber.RuntimeStatus.RotationTime не задан, то он равен 0 // Если sampleConfig.Jabber.RuntimeStatus.RotationTime не задан, то он равен 0
// Если sampleConfig.Jabber.RuntimeStatus.RotationSplayTime не задан, то он равен 0 // Если sampleConfig.Jabber.RuntimeStatus.RotationSplayTime не задан, то он равен 0
// Нам бот нужен в каких-то чат-румах, а не "просто так" // Если sampleConfig.Jabber.BanPhrasesEnable не задан, то он false
if len(sampleConfig.Jabber.Channels) < 1 {
log.Errorf("No jabber channels/rooms defined in config, quitting") // Если список фраз, с которыми банят пустой, то вносим в него одну позицию с пустой строкой
os.Exit(1) if len(sampleConfig.Jabber.BanPhrases) == 0 {
sampleConfig.Jabber.BanPhrases[0] = ""
}
if sampleConfig.CSign == "" {
sampleConfig.CSign = "!"
} }
if sampleConfig.Loglevel == "" { if sampleConfig.Loglevel == "" {
@@ -271,19 +284,26 @@ func readConfig() { //nolint:gocognit,gocyclo
} }
if !configLoaded { if !configLoaded {
log.Error("Config was not loaded! Refusing to start.") return errors.New("config was not loaded!") //nolint:goerr113
os.Exit(1)
} }
return err //nolint:wrapcheck
} }
// readWhitelist читает и валидирует белые списки пользователей. // readWhitelist читает и валидирует белые списки пользователей.
func readWhitelist() { func readWhitelist() error {
whitelistLoaded := false var (
executablePath, err := os.Executable() whitelistLoaded = false
err error
executablePath string
)
executablePath, err = os.Executable()
if err != nil { if err != nil {
log.Errorf("Unable to get current executable path: %s", err) err = fmt.Errorf("unable to get current executable path: %w", err)
os.Exit(1)
return err
} }
whitelistJSONPath := fmt.Sprintf("%s/data/whitelist.json", filepath.Dir(executablePath)) whitelistJSONPath := fmt.Sprintf("%s/data/whitelist.json", filepath.Dir(executablePath))
@@ -360,21 +380,26 @@ func readWhitelist() {
} }
if !whitelistLoaded { if !whitelistLoaded {
log.Error("Whitelist was not loaded! Refusing to start.") return errors.New("whitelist was not loaded!") //nolint:goerr113
os.Exit(1)
} }
return err
} }
// readBlacklist читает и валидирует чёрные списки пользователей. // readBlacklist читает и валидирует чёрные списки пользователей.
func readBlacklist() { func readBlacklist() error {
blacklistLoaded := false var (
executablePath, err := os.Executable() blacklistLoaded = false
err error
executablePath string
)
executablePath, err = os.Executable()
if err != nil { if err != nil {
log.Errorf("Unable to get current executable path: %s", err) err = fmt.Errorf("unable to get current executable path: %w", err)
os.Exit(1) return err
} }
whitelistJSONPath := fmt.Sprintf("%s/data/blacklist.json", filepath.Dir(executablePath)) whitelistJSONPath := fmt.Sprintf("%s/data/blacklist.json", filepath.Dir(executablePath))
@@ -451,10 +476,10 @@ func readBlacklist() {
} }
if !blacklistLoaded { if !blacklistLoaded {
log.Error("Blacklist was not loaded! Refusing to start.") return errors.New("blacklist was not loaded!")
os.Exit(1)
} }
return err
} }
// establishConnection устанавливает соединение с jabber-сервером. // establishConnection устанавливает соединение с jabber-сервером.
@@ -582,7 +607,7 @@ func joinMuc(room string) {
go RotateStatus(room) go RotateStatus(room)
// Время прoверить участников на предмет злобности // Время проверить участников на предмет злобности
namesInterface, present := roomPresences.Get(room) namesInterface, present := roomPresences.Get(room)
// Если room есть в списке presence-ов, то фигачим. room там должен быть, просто обязан. // Если room есть в списке presence-ов, то фигачим. room там должен быть, просто обязан.
@@ -855,4 +880,32 @@ func interfaceToStringSlice(iface interface{}) []string {
return mySlice return mySlice
} }
// getRealJIDfromNick достаёт из запомненных presence-ов по даденному nick-у real jid с resource-ом. Nick должен
// содержать имя конфы, откуда участник.
func getRealJIDfromNick(fullNick string) string {
var p xmpp.Presence
room := (strings.SplitN(fullNick, "/", 2))[0]
// Достанем presence участника
presenceJSONInterface, present := roomPresences.Get(room)
// Никого нет дома
if !present {
return ""
}
presenceJSONStrings := interfaceToStringSlice(presenceJSONInterface)
for _, presepresenceJSONString := range presenceJSONStrings {
_ = json.Unmarshal([]byte(presepresenceJSONString), &p)
if p.From == fullNick {
return p.JID
}
}
return ""
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */ /* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

19
main.go
View File

@@ -24,7 +24,11 @@ func init() {
TimestampFormat: "2006-01-02 15:04:05", TimestampFormat: "2006-01-02 15:04:05",
}) })
readConfig() if err := readConfig(); err != nil {
log.Error(err)
os.Exit(1)
}
// no panic // no panic
switch config.Loglevel { switch config.Loglevel {
@@ -67,8 +71,17 @@ func main() {
} }
// Самое время вгрузить белые и чёрные списки, если что - получим ошибку в лог. // Самое время вгрузить белые и чёрные списки, если что - получим ошибку в лог.
readWhitelist() if err := readWhitelist(); err != nil {
readBlacklist() log.Error(err)
os.Exit(1)
}
if err := readBlacklist(); err != nil {
log.Error(err)
os.Exit(1)
}
// github.com/mattn/go-xmpp пишет в stdio, нам этого не надо, ловим выхлоп его в logrus с уровнем trace // github.com/mattn/go-xmpp пишет в stdio, нам этого не надо, ловим выхлоп его в logrus с уровнем trace
xmpp.DebugWriter = log.WithFields(log.Fields{"logger": "stdlib"}).WriterLevel(log.TraceLevel) xmpp.DebugWriter = log.WithFields(log.Fields{"logger": "stdlib"}).WriterLevel(log.TraceLevel)

View File

@@ -23,6 +23,7 @@ type myConfig struct {
Resource string `json:"resource,omitempty"` Resource string `json:"resource,omitempty"`
User string `json:"user,omitempty"` User string `json:"user,omitempty"`
Password string `json:"password,omitempty"` Password string `json:"password,omitempty"`
BotMasters []string `json:"bot_masters"`
Channels []string `json:"channels"` Channels []string `json:"channels"`
StartupStatus []string `json:"startup_status,omitempty"` StartupStatus []string `json:"startup_status,omitempty"`
RuntimeStatus struct { RuntimeStatus struct {
@@ -34,6 +35,7 @@ type myConfig struct {
BanPhrases []string `json:"ban_phrases,omitempty"` BanPhrases []string `json:"ban_phrases,omitempty"`
} `json:"jabber,omitempty"` } `json:"jabber,omitempty"`
CSign string `json:"csign,omitempty"`
Loglevel string `json:"loglevel,omitempty"` Loglevel string `json:"loglevel,omitempty"`
Log string `json:"log,omitempty"` Log string `json:"log,omitempty"`
} }