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:
@@ -35,7 +35,73 @@
|
|||||||
"ping_splay_delay": 3,
|
"ping_splay_delay": 3,
|
||||||
# Ник бота, с которым он будет заходить в комнаты
|
# Ник бота, с которым он будет заходить в комнаты
|
||||||
"nick": "buny",
|
"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",
|
"user": "buny@jabber.tld",
|
||||||
# Пароль для авторизации
|
# Пароль для авторизации
|
||||||
@@ -52,5 +118,5 @@
|
|||||||
"loglevel": "debug",
|
"loglevel": "debug",
|
||||||
|
|
||||||
# Если не задан, логи идут в STDOUT
|
# Если не задан, логи идут в STDOUT
|
||||||
"log": "/var/log/echo-jabber-bot/echo-jabber-bot.log",
|
"log": "/var/log/buny-jabber-bot/error.log"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
log.Debugf("Looks like message, ChatType: %s, From: %s, Subject: %s Text: %s",
|
||||||
v.Type, v.Remote, v.Subject, v.Text)
|
v.Type, v.Remote, v.Subject, v.Text)
|
||||||
|
|
||||||
if config.NoEcho {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Топик чятика присылается в виде сообщения с subject, но без text
|
// Топик чятика присылается в виде сообщения с subject, но без text
|
||||||
// В то же время сообщения от людей приходят с пустым subject, но с заполненным text
|
// В то же время сообщения от людей приходят с пустым subject, но с заполненным text
|
||||||
if v.Text != "" {
|
if v.Text != "" {
|
||||||
|
|||||||
107
lib.go
107
lib.go
@@ -67,7 +67,7 @@ func sigHandler() {
|
|||||||
|
|
||||||
// readConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге
|
// readConfig читает и валидирует конфиг, а также выставляет некоторые default-ы, если значений для параметров в конфиге
|
||||||
// нет.
|
// нет.
|
||||||
func readConfig() { //nolint:gocognit
|
func readConfig() { //nolint:gocognit,gocyclo
|
||||||
configLoaded := false
|
configLoaded := false
|
||||||
executablePath, err := os.Executable()
|
executablePath, err := os.Executable()
|
||||||
|
|
||||||
@@ -228,6 +228,26 @@ func readConfig() { //nolint:gocognit
|
|||||||
// Если sampleConfig.Jabber.Password не задан, то авторизации не будет
|
// Если sampleConfig.Jabber.Password не задан, то авторизации не будет
|
||||||
// Если sampleConfig.Jabber.Sasl не задан, то авторизация происходит через NickServ
|
// Если 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 {
|
if len(sampleConfig.Jabber.Channels) < 1 {
|
||||||
log.Errorf("No jabber channels/rooms defined in config, quitting")
|
log.Errorf("No jabber channels/rooms defined in config, quitting")
|
||||||
@@ -471,16 +491,7 @@ func establishConnection() {
|
|||||||
go joinMuc(room)
|
go joinMuc(room)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := talk.SendPresence(
|
go RotateStatus("")
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
lastActivity = time.Now().Unix()
|
lastActivity = time.Now().Unix()
|
||||||
connecting = false
|
connecting = false
|
||||||
@@ -568,17 +579,9 @@ func joinMuc(room string) {
|
|||||||
// Вот теперь точно можно слать статус.
|
// Вот теперь точно можно слать статус.
|
||||||
log.Infof("Joined to MUC: %s", room)
|
log.Infof("Joined to MUC: %s", room)
|
||||||
|
|
||||||
if _, err := talk.SendPresence(
|
go RotateStatus(room)
|
||||||
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)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// probeServerLiveness проверяет живость соединения с сервером. Для многих серверов обязательная штука, без которой
|
// 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: */
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -93,7 +93,7 @@ func main() {
|
|||||||
Debug: verboseClient,
|
Debug: verboseClient,
|
||||||
Session: false,
|
Session: false,
|
||||||
Status: "xa",
|
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,
|
DialTimeout: time.Duration(config.Jabber.ConnectionTimeout) * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
types.go
10
types.go
@@ -24,12 +24,18 @@ type myConfig struct {
|
|||||||
User string `json:"user,omitempty"`
|
User string `json:"user,omitempty"`
|
||||||
Password string `json:"password,omitempty"`
|
Password string `json:"password,omitempty"`
|
||||||
Channels []string `json:"channels"`
|
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"`
|
} `json:"jabber,omitempty"`
|
||||||
|
|
||||||
Loglevel string `json:"loglevel,omitempty"`
|
Loglevel string `json:"loglevel,omitempty"`
|
||||||
Log string `json:"log,omitempty"`
|
Log string `json:"log,omitempty"`
|
||||||
NoEcho bool `json:"noecho,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// myWhiteList прототип структурки с белым списком jid-ов.
|
// myWhiteList прототип структурки с белым списком jid-ов.
|
||||||
|
|||||||
Reference in New Issue
Block a user