0
Files
aleesa-jabber-go/commands.go
2023-09-17 12:18:09 +03:00

375 lines
16 KiB
Go

package main
import (
"encoding/json"
"fmt"
"regexp"
"slices"
"strings"
"github.com/eleksir/go-xmpp"
log "github.com/sirupsen/logrus"
)
func cmd(v xmpp.Chat) error {
var (
err error
message sMsg
data []byte
)
message.From = config.Redis.MyChannel
message.Threadid = "" // Тредиков в jabber-е нету, поэтому это поле отправляем пустым
message.Message = v.Text
message.Plugin = config.Redis.MyChannel
// Список команд, публично доступных, без каких-то специальных настроек
cmds := []string{"ping", "пинг", "пинх", "pong", "понг", "понх", "coin", "монетка", "roll", "dice", "кости",
"ver", "version", "версия", "хэлп", "halp", "kde", "кде", "lat", "лат", "friday", "пятница", "proverb",
"пословица", "пословиться", "fortune", "фортунка", "f", "ф", "anek", "анек", "анекдот", "buni", "cat",
"кис", "drink", "праздник", "fox", "лис", "frog", "лягушка", "horse", "лошадь", "лошадка", "monkeyuser",
"owl", "сова", "сыч", "rabbit", "bunny", "кролик", "snail", "улитка", "xkcd", "dig", "копать", "fish",
"fishing", "рыба", "рыбка", "рыбалка", "karma", "карма"}
// Список отключаемых команд проверяется в case-е про groupchat, чуть ниже
// Список "сложных" команд, это те, которые имеют ключевые данные на конце команды. Пока что это только погодка.
cmdsComplex := []string{"w ", "п ", "погода ", "погодка ", "погадка ", "weather "}
// Список команд бармэна. Основное отличие в том, что после команды ключевые данные могут быть, а могут и не быть.
// То есть рюмашку можно заказать себе или кому-то в чятике.
cmdsBartender := []string{"rum", "ром", "vodka", "водка", "beer", "пиво", "tequila", "текила", "whisky", "виски",
"absinthe", "абсент"}
// Есть ещё команда на изменение кармы. Это команда-суффикс ++ или --. Она проверяется по-месту, потому что она одна
// и вполне уникальна.
switch v.Type {
case "groupchat":
message.Mode = "public"
message.Chatid = strings.SplitN(v.Remote, "/", 2)[0]
userNick := strings.SplitN(v.Remote, "/", 2)[1]
if realJid := getRealJIDfromNick(v.Remote); realJid != "" {
message.Userid = realJid
} else {
message.Userid = v.Remote
}
message.Misc.Answer = 0
message.Misc.Fwdcnt = 0
message.Misc.Csign = config.CSign
message.Misc.Username = userNick
message.Misc.Botnick = config.Jabber.Nick
message.Misc.Msgformat = 0
msgLen := len(v.Text)
// TODO: а вот тут надо впилить парсер команд
if (msgLen > len(config.CSign)) && (v.Text[:len(config.CSign)] == config.CSign) {
var (
cmd = v.Text[len(config.CSign):]
room = message.Chatid
answer string
)
// И таких кейсов у нас минимум на команды !help и семейство команд !admin, а также на те команды, которые не всегда работают
switch {
case cmd == "help" || cmd == "помощь":
answer += fmt.Sprintf("%shelp | %sпомощь - это сообщение\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sanek | %sанек | %sанекдот - рандомный анекдот с anekdot.ru\n", config.CSign, config.CSign, config.CSign)
answer += fmt.Sprintf("%sbuni - комикс-стрип hapi buni\n", config.CSign)
answer += fmt.Sprintf("%sbunny - кролик\n", config.CSign)
answer += fmt.Sprintf("%srabbit | %sкролик - кролик\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%scat | %sкис - кошечка\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sdice | %sroll | %sкости - бросить кости\n", config.CSign, config.CSign, config.CSign)
answer += fmt.Sprintf("%sdig | %sкопать - заняться археологией\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sdrink | %sпраздник - какой сегодня праздник?\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sfish | %sfisher - порыбачить\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sрыба | %sрыбка | %sрыбалка - порыбачить\n", config.CSign, config.CSign, config.CSign)
answer += fmt.Sprintf("%sf | %sф - рандомная фраза из сборника цитат fortune_mod\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sfortune | %sфортунка - рандомная фраза из сборника цитат fortune_mod\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sfox | %sлис - лисичка\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sfriday | %sпятница - а не пятница ли сегодня?\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sfrog | %sлягушка - лягушка\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%shorse | %sлошадь | %sлошадка - лошадка\n", config.CSign, config.CSign, config.CSign)
answer += fmt.Sprintf("%skarma фраза - посмотреть карму фразы\n", config.CSign)
answer += fmt.Sprintf("%sкарма фраза - посмотреть карму фразы\n", config.CSign)
answer += fmt.Sprintln("фраза++ | фраза-- - повысить или понизить карму фразы")
answer += fmt.Sprintf("%slat | %sлат - сгенерировать фразу из крылатого латинского выражения\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%smonkeyuser - комикс-стрип MonkeyUser\n", config.CSign)
answer += fmt.Sprintf("%sowl | %sсова - сова\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sping | %sпинг - попинговать бота\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sproverb | %sпословица - рандомная русская пословица\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%ssnail | %sулитка - улитка\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%ssome_brew - выдать соответствующий напиток, бармен может налить rum, ром, vodka, водку, tequila, текила\n", config.CSign)
answer += fmt.Sprintf("%sver | %sversion - написать что-то про версию ПО\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sверсия - написать что-то про версию ПО\n", config.CSign)
answer += fmt.Sprintf("%sw город | %sп город - погода в городе\n", config.CSign, config.CSign)
answer += fmt.Sprintf("%sxkcd - комикс-стрип с xkcb.ru\n", config.CSign)
// Для овнера или админа надо показывать команду admin
if isMucAdmin(v.Remote) {
answer += fmt.Sprintf("%sadmin - настройки некоторых плагинов бота для комнаты\n", config.CSign)
}
_, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
case cmd == "admin":
if isMucAdmin(v.Remote) {
answer += fmt.Sprintf("%sadmin oboobs # - где 1 - вкл, 0 - выкл плагина oboobs\n", config.CSign)
answer += fmt.Sprintf("%sadmin oboobs - показываем ли сисечки по просьбе участников чата (команды %stits, %stities, %sboobs, %sboobies, %sсиси, %sсисечки)\n", config.CSign, config.CSign, config.CSign, config.CSign, config.CSign, config.CSign, config.CSign)
answer += fmt.Sprintf("%sadmin obutts # - где 1 - вкл, 0 - выкл плагина obutts\n", config.CSign)
answer += fmt.Sprintf("%sadmin obutts - показываем ли попки по просьбе участников чата (команды %sass, %sbutt, %sbooty, %sпопа, %sпопка)\n", config.CSign, config.CSign, config.CSign, config.CSign, config.CSign, config.CSign)
_, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
return err
case cmd == "admin oboobs":
if isMucAdmin(v.Remote) {
switch getSetting(room, "oboobs") {
case "0":
answer = "Плагин oboobs выключен"
case "1":
answer = "Плагин oboobs включен"
case "":
_ = saveSetting(room, "oboobs", "0")
answer = "Плагин oboobs выключен"
default:
answer = "Плагин oboobs выключен"
}
_, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
case cmd == "admin oboobs 1":
if isMucAdmin(v.Remote) {
err := saveSetting(room, "oboobs", "1")
if err != nil {
answer = "Плагин oboobs всё ещё выключен"
} else {
answer = "Плагин oboobs включен"
}
_, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
case cmd == "admin oboobs 0":
if isMucAdmin(v.Remote) {
_ = saveSetting(room, "oboobs", "0")
answer = "Плагин oboobs выключен"
_, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
case cmd == "admin obutts":
if isMucAdmin(v.Remote) {
switch getSetting(room, "obutts") {
case "0":
answer = "Плагин obutts выключен"
case "1":
answer = "Плагин obutts включен"
case "":
_ = saveSetting(room, "obutts", "0")
answer = "Плагин obutts выключен"
default:
answer = "Плагин obutts выключен"
}
_, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
case cmd == "admin obutts 1":
if isMucAdmin(v.Remote) {
err := saveSetting(room, "obutts", "1")
if err != nil {
answer = "Плагин obutts всё ещё выключен"
} else {
answer = "Плагин obutts включен"
}
_, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
case cmd == "admin obutts 0":
if isMucAdmin(v.Remote) {
_ = saveSetting(room, "obutts", "0")
answer = "Плагин obutts выключен"
_, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
case cmd == "butt" || cmd == "booty" || cmd == "ass" || cmd == "попа" || cmd == "попка":
if getSetting(room, "obutts") != "1" {
return err
}
message.Misc.Answer = 1
case cmd == "tits" || cmd == "boobs" || cmd == "tities" || cmd == "boobies" || cmd == "сиси" || cmd == "сисечки":
if getSetting(room, "oboobs") != "1" {
return err
}
message.Misc.Answer = 1
// Отлавливаем команды и им проставляем message.Misc.Answer = 1
default:
done := false
// Простые команды
for _, command := range cmds {
if cmd == command {
done = true
message.Misc.Answer = 1
break
}
}
// Сложные команды, например, погода
if !done {
for _, command := range cmdsComplex {
cmdLen := len(cmd)
if cmdLen > len(command) && cmd[0:len(command)] == command {
done = true
message.Misc.Answer = 1
break
}
}
}
// Сам себе заказал выпивку
if !done {
for _, command := range cmdsBartender {
if cmd == command {
done = true
message.Misc.Answer = 1
break
}
}
}
// Заказал выпивку кому-то ещё
if !done {
re := regexp.MustCompile(" +")
pile := re.Split(cmd, 2)
names := getMucNames(room)
for _, command := range cmdsBartender {
if pile[0] == command {
userNick := strings.TrimSpace(pile[1])
if userNick != "" {
if slices.Contains(names, userNick) {
message.Misc.Username = userNick
} else {
answer := fmt.Sprintf("Я тут не вижу участника с ником %s", userNick)
_, err = talk.Send(xmpp.Chat{Remote: room, Type: v.Type, Text: answer}) //nolint:exhaustruct
return err
}
message.Misc.Answer = 1
break
}
}
}
}
}
}
// Ну, вот мы и добрались досюда, и... нам осталось понять, не обращаются ли к боту?
// Дело в том, что ответа требуют только команды и обращения к боту по нику
// или jid-у, в данном случае, по нику. А всё остальное должно попадать в craniac-а и оставаться там в качестве
// материала для бредогенератора.
// Попробуем выискать изменение кармы
// ++ или -- на конце фразы - это наш кандидат
if msgLen > len("++") {
if v.Text[msgLen-len("--"):msgLen] == "--" || v.Text[msgLen-len("++"):msgLen] == "++" {
// Предполагается, что менять карму мы будем для одной фразы, то есть для 1 строки
if len(strings.Split(v.Text, "\n")) == 1 {
// Костыль для кармы
message.Misc.Answer = 1
}
}
}
// Предполагается что в канале бот должен отвечать, только если к нему обратились, либо это была команда
if regexp.MustCompile(config.Jabber.Nick).Match([]byte(message.Message)) {
message.Misc.Answer = 1
}
message.Message = v.Text
data, err = json.Marshal(message)
if err != nil {
return fmt.Errorf("unable to to serialize message for redis: %w", err)
}
case "chat":
message.Mode = "private"
message.Chatid = v.Remote
// Jid у нас уникален, а вот nick может, во-первых, разниться от конфы к конфе, а во-вторых, его может взять
// себе другой пользователь конфы, пока оригинальный владелец ника отсутствует. Но мы предполагаем, что если
// комната анонимная, то владелец комнаты, приглашая бота, согласен на некоторые компромиссы.
if realJID := getRealJIDfromNick(v.Remote); realJID != "" {
message.Userid = realJID
} else {
message.Userid = v.Remote
}
message.Misc.Answer = 1
message.Misc.Fwdcnt = 0
message.Misc.Csign = config.CSign
message.Misc.Username = message.Userid
message.Misc.Botnick = config.Jabber.Nick
message.Misc.Msgformat = 0
data, err = json.Marshal(message)
if err != nil {
return fmt.Errorf("unable to to serialize message for redis: %w", err)
}
}
// Заталкиваем наш json в редиску
if err := redisClient.Publish(ctx, config.Redis.Channel, data).Err(); err != nil {
return fmt.Errorf("unable to send data to redis channel %s: %w", config.Redis.Channel, err)
}
log.Debugf("Sent msg to redis channel %s: %s", config.Redis.Channel, string(data))
return err
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */