Implement random startup/runtime status, cosmetic fixes

* Implement random startup status from array in config
* Implement random runtime status from array in config
* Implement runtime status rotation
* Remove noecho option from config and from code
* Use separate goroutine to set statuses
This commit is contained in:
eleksir
2023-08-17 09:48:57 -07:00
parent ce9561b488
commit 8a67a91ffb
5 changed files with 163 additions and 30 deletions

View File

@@ -35,7 +35,73 @@
"ping_splay_delay": 3,
# Ник бота, с которым он будет заходить в комнаты
"nick": "buny",
"resource" : "buny bot",
# Уникальная часть jid-а, специфичная для клиента
"resource" : "Лунная призма",
# Статус, с которым бот запускается. (если всё нормально, этот статус будет видать только в логах сервера и
# на долю секунды он промелькнёт у всех в ростере, у кого бот в знакомых. Может отсуствовать, тогда статус будет
# пустой строкой
"startup_status": [
"bunny bot is starting",
],
# Статус, который демонстрируется во время работы бота, как xa
# (по задумке - extended away, на практике, к away обычно отношения не имеет)
"runtime_status": {
# Сам текст статуса, может отсустствовать, тогда статус - это пустая строка
"text": [
"Тот, кто не знает силу пешек, не имеет права ходить королевой.",
"Когда ты пройдешь сквозь мрак беспомощности и попадешь в мир надежды, тогда ты преодолеешь все преграды.",
"По-моему, тебе очень хочется стать уткой по-пекински!",
"If a soldier’s pride means hurting one another, I don’t want it.",
"Without the bad times, we wouldn’t appreciate the good times.",
"I’ll just warn you now, I don’t know how to use a computer.",
"Thinking isn’t going to get us anywhere.",
"Вместо того, чтобы произносить речи, лучше бы подумала, что ты будешь делать дальше.",
"Да как ты смела разгадать мой замысел?! Я же целую ночь не спала, пока его придумала. Верни мне мой сон!",
"Не волнуйся, жизнь намного скучнее, чем ты себе её представляешь.",
"Я бы завела котёнка, но у меня уже есть Луна и она жрёт как лошадь.",
"Звезда нашей надежды никогда не исчезнет. Пока она горит, всё будет в порядке. Мы не сможем проиграть",
"Голова с хвостиками… Не вмешивайся в наши дела! Играть в войну — это опасно"
],
# Период смены статуса, сек. Если параметра нет или он выставлен в 0, ротации не будет
"rotation_time": 1,
# Рандомная составляющая, добавляемая к периоду смены статуса, сек.
"rotation_splay_time": 1,
},
# Произносим ли что-то пафосное в момоент бана
"ban_phrases_enable": false,
# Пафосные фраза, произносимые перед баном
"ban_phrases": [
"Во имя Луны, я накажу тебя!",
"Сила Луны, проснись!",
"Мы — воительницы справедливости!",
"Любовь и справедливость победят всегда!",
"Я буду защищать этот мир до последнего вздоха!",
"Мысли о любви делают нас сильнее!",
"Никогда не сдавайся, даже если все кажется безнадежным!",
"Мы можем преодолеть любые трудности, если будем вместе!",
"Любовь — это самая мощная сила во Вселенной!",
"Верь в себя и свою силу!",
"Красавица-воин Сейлор Мун, покоряющая сердца!",
"Мы несем свет и надежду в этот мир!",
"Луна, дай мне силу!",
"Мысли о друзьях дают мне силу!",
"Мы боремся за мир и справедливость!",
"Мы всегда найдем путь к победе!",
"Наша дружба — это наша сила!",
"Мы — защитницы мира, и ничто не остановит нас!",
"Любовь — это то, что делает нас сильнее!",
"Мы сражаемся за будущее всех живых существ!",
"Мы всегда будем вместе, независимо от трудностей!",
"Мы — сестры по духу и воительницы справедливости!",
"Мы несем свет и надежду в этот мир!",
"Любовь — это самое важное чувство во Вселенной!",
"Мы сражаемся за справедливость и защищаем тех, кто слабее!",
"Мы — герои, которые противостоят тьме!",
"Луна, дай мне силу стать красавицей-воином!",
"Мы сражаемся за мир и равенство!",
"Мы — надежда для всех, кто нуждается в защите!",
"Мы — воительницы справедливости, и ничто не остановит нас!"
],
# Имя пользователя для авторизации на сервере
"user": "buny@jabber.tld",
# Пароль для авторизации
@@ -52,5 +118,5 @@
"loglevel": "debug",
# Если не задан, логи идут в STDOUT
"log": "/var/log/echo-jabber-bot/echo-jabber-bot.log",
"log": "/var/log/buny-jabber-bot/error.log"
}

View File

@@ -22,10 +22,6 @@ func parseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
log.Debugf("Looks like message, ChatType: %s, From: %s, Subject: %s Text: %s",
v.Type, v.Remote, v.Subject, v.Text)
if config.NoEcho {
return
}
// Топик чятика присылается в виде сообщения с subject, но без text
// В то же время сообщения от людей приходят с пустым subject, но с заполненным text
if v.Text != "" {

105
lib.go
View File

@@ -67,7 +67,7 @@ func sigHandler() {
// readConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге
// нет.
func readConfig() { //nolint:gocognit
func readConfig() { //nolint:gocognit,gocyclo
configLoaded := false
executablePath, err := os.Executable()
@@ -228,6 +228,26 @@ func readConfig() { //nolint:gocognit
// Если sampleConfig.Jabber.Password не задан, то авторизации не будет
// Если sampleConfig.Jabber.Sasl не задан, то авторизация происходит через NickServ
// Если sampleConfig.Jabber.BanPhrasesEnable не задан, то он false
// Если список фраз, с которыми банят пустой, то вносим в него одну позицию с пустой строкой
if len(sampleConfig.Jabber.BanPhrases) == 0 {
sampleConfig.Jabber.BanPhrases[0] = ""
}
// Если список фраз с которыми стартует бот пустой, вносим в него 1 запись с пустой строкой
if len(sampleConfig.Jabber.StartupStatus) == 0 {
sampleConfig.Jabber.StartupStatus[0] = ""
}
// Если список статусов, с которыми работает бот пустой, вносим в него 1 запись с пустой строкой
if len(sampleConfig.Jabber.RuntimeStatus.Text) == 0 {
sampleConfig.Jabber.RuntimeStatus.Text[0] = ""
}
// Если sampleConfig.Jabber.RuntimeStatus.RotationTime не задан, то он равен 0
// Если sampleConfig.Jabber.RuntimeStatus.RotationSplayTime не задан, то он равен 0
// Нам бот нужен в каких-то чат-румах, а не "просто так"
if len(sampleConfig.Jabber.Channels) < 1 {
log.Errorf("No jabber channels/rooms defined in config, quitting")
@@ -471,16 +491,7 @@ func establishConnection() {
go joinMuc(room)
}
if _, err := talk.SendPresence(
xmpp.Presence{ //nolint:exhaustruct
Status: "Ready to chat",
},
); err != nil {
log.Infof("Unable to send presence to jabber server: %s", err)
gTomb.Kill(err)
return
}
go RotateStatus("")
lastActivity = time.Now().Unix()
connecting = false
@@ -568,17 +579,9 @@ func joinMuc(room string) {
// Вот теперь точно можно слать статус.
log.Infof("Joined to MUC: %s", room)
if _, err := talk.SendPresence(
xmpp.Presence{ //nolint:exhaustruct
To: room,
Status: "Ready to chat",
},
); err != nil {
log.Infof("Unable to send presence to MUC %s: %s", room, err)
gTomb.Kill(err)
go RotateStatus(room)
return
}
}
// probeServerLiveness проверяет живость соединения с сервером. Для многих серверов обязательная штука, без которой
@@ -759,4 +762,66 @@ func probeMUCLiveness() { //nolint:gocognit
}
}
// RotateStatus периодически изменяет статус бота в MUC-е согласно настройкам из кофига.
func RotateStatus(room string) {
defer gTomb.Done()
for {
select {
case <-gTomb.Dying():
return
default:
// TODO: Переделать на ticker-ы
totalSleepTime := time.Duration(config.Jabber.RuntimeStatus.RotationTime) * time.Second
totalSleepTime += time.Duration(config.Jabber.RuntimeStatus.RotationSplayTime) * time.Second
for {
status := randomPhrase(config.Jabber.RuntimeStatus.Text)
log.Debugf("Set status for MUC: %s to: %s", room, status)
var p xmpp.Presence
if room != "" {
p = xmpp.Presence{ //nolint:exhaustruct
To: room,
Status: status,
}
} else {
p = xmpp.Presence{ //nolint:exhaustruct
Status: status,
}
}
if _, err := talk.SendPresence(p); err != nil {
log.Infof("Unable to send presence to MUC %s: %s", room, err)
gTomb.Kill(err)
return
}
// Если мы не хотим ротировать, то цикл нам тут не нужен, просто выходим.
if config.Jabber.RuntimeStatus.RotationTime == 0 {
gTomb.Done()
return
}
time.Sleep(totalSleepTime)
}
}
}
}
// randomPhrase Выдаёт одну рандомную фразу из даденного списка фраз.
func randomPhrase(list []string) string {
phrase := ""
if listLen := len(list); listLen > 0 {
phrase = list[rand.Intn(listLen)] //nolint:gosec
}
return phrase
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -93,7 +93,7 @@ func main() {
Debug: verboseClient,
Session: false,
Status: "xa",
StatusMessage: fmt.Sprintf("%s bot is starting up", config.Jabber.Nick),
StatusMessage: randomPhrase(config.Jabber.StartupStatus),
DialTimeout: time.Duration(config.Jabber.ConnectionTimeout) * time.Second,
}

View File

@@ -24,12 +24,18 @@ type myConfig struct {
User string `json:"user,omitempty"`
Password string `json:"password,omitempty"`
Channels []string `json:"channels"`
OutcastDomains []string `json:"outcast_domains,omitempty"`
StartupStatus []string `json:"startup_status,omitempty"`
RuntimeStatus struct {
Text []string `json:"text,omitempty""`
RotationTime int64 `json:"rotation_time,omitempty"`
RotationSplayTime int64 `json:"rotation_splay_time,omitempty"`
} `json:"runtime_status,omitempty"`
BanPhrasesEnable bool `json:"ban_phrases_enable,omitempty"`
BanPhrases []string `json:"ban_phrases,omitempty"`
} `json:"jabber,omitempty"`
Loglevel string `json:"loglevel,omitempty"`
Log string `json:"log,omitempty"`
NoEcho bool `json:"noecho,omitempty"`
}
// myWhiteList прототип структурки с белым списком jid-ов.