diff --git a/data/sample_config.json b/data/sample_config.json index 90048cb..7c466d5 100644 --- a/data/sample_config.json +++ b/data/sample_config.json @@ -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" } diff --git a/event_parser.go b/event_parser.go index 18859d7..fc94657 100644 --- a/event_parser.go +++ b/event_parser.go @@ -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 != "" { diff --git a/lib.go b/lib.go index 8339160..98a7fce 100644 --- a/lib.go +++ b/lib.go @@ -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 - } + 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: */ diff --git a/main.go b/main.go index 99ec052..a5987aa 100644 --- a/main.go +++ b/main.go @@ -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, } diff --git a/types.go b/types.go index c5d5faf..b9a4057 100644 --- a/types.go +++ b/types.go @@ -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-ов.