From ddcc8b1c87d36961da738ed4f991e86b0e0f8ec9 Mon Sep 17 00:00:00 2001 From: eleksir Date: Sun, 9 Nov 2025 12:25:51 +0300 Subject: [PATCH] [WIP] MOAR linter fixes, also move init to tg lib --- TODO.org | 2 +- cmd/aleesa-telegram-go/main.go | 40 ++------------------ cmd/settings-migrator/importer.go | 3 +- internal/tg/admin.go | 62 +++++++++++++++---------------- internal/tg/help.go | 14 +++---- internal/tg/lib.go | 46 +++++++++++++++++++++++ internal/tg/parseConfig.go | 4 +- internal/tg/periodicJobs.go | 9 ++++- internal/tg/settings-db-util.go | 22 +++++------ internal/tg/sigHandler.go | 1 + internal/tg/telegram.go | 12 +++--- internal/tg/telegramMsgParser.go | 8 ++-- 12 files changed, 120 insertions(+), 103 deletions(-) create mode 100644 internal/tg/lib.go diff --git a/TODO.org b/TODO.org index 61a76d4..311b2bd 100644 --- a/TODO.org +++ b/TODO.org @@ -1,6 +1,6 @@ Перечень того, что надо реализовать. -В качестве основы возьмём https://github.com/NicoNex/echotron +В качестве основы возьмём https://github.com/NicoNex/echotron Для реализации телеграммного фронтэнда нам надо сделать: * DONE Переделать layout [1/1] diff --git a/cmd/aleesa-telegram-go/main.go b/cmd/aleesa-telegram-go/main.go index f503f5d..dd307c7 100644 --- a/cmd/aleesa-telegram-go/main.go +++ b/cmd/aleesa-telegram-go/main.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "os/signal" - "path/filepath" "syscall" "aleesa-telegram-go/internal/log" @@ -15,48 +14,15 @@ import ( "github.com/go-redis/redis/v8" ) -// init производит некоторую инициализацию перед запуском main(). -func init() { - var ( - err error - ) - - executablePath, err := os.Executable() - - if err != nil { - log.Fatalf("Unable to get current executable path: %s", err) - } - - configJSONPath := filepath.Dir(executablePath) + "/data/config.json" - - locations := []string{ - "~/.aleesa-telegram-go.json", - "~/aleesa-telegram-go.json", - "/etc/aleesa-telegram-go.json", - configJSONPath, - } - - for _, location := range locations { - tg.Config, err = tg.ParseConfig(location) - - if err == nil { - break - } - - log.Errorf("Unable to parse config at %s: %s", location, err) - } - - if err != nil { - os.Exit(1) - } -} - func main() { var ( logfile *os.File err error ) + // Найдём и прочитаем конфиг. + tg.ReadConfig() + // Откроем лог и скормим его логгеру. if tg.Config.Log != "" { logfile, err = os.OpenFile(tg.Config.Log, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) diff --git a/cmd/settings-migrator/importer.go b/cmd/settings-migrator/importer.go index 43f778d..697e4a8 100644 --- a/cmd/settings-migrator/importer.go +++ b/cmd/settings-migrator/importer.go @@ -1,4 +1,5 @@ -package settingsmigrator +// main Импортирует настройки из файла settings.json в базу с настройками. +package main import ( "fmt" diff --git a/internal/tg/admin.go b/internal/tg/admin.go index 3473674..c346997 100644 --- a/internal/tg/admin.go +++ b/internal/tg/admin.go @@ -21,47 +21,43 @@ func Admin(msg *echotron.Update) (bool, error) { case c == "admin" || c == "админ": answer = "```\n" - answer += fmt.Sprintf("%sadmin censor - показать список состояния типов сообщений\n", Config.Csign) - answer += fmt.Sprintf("%sадмин ценз - показать список состояния типов сообщений\n", Config.Csign) - answer += fmt.Sprintf("%sadmin censor type # - где 1 - вкл, 0 - выкл цензуры для означенного типа сообщений\n", Config.Csign) - answer += fmt.Sprintf("%sадмин ценз тип # - где 1 - вкл, 0 - выкл цензуры для означенного типа сообщений\n", Config.Csign) - answer += fmt.Sprintf("%sadmin fortune - показываем ли с утра фортунку для чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin фортунка - показываем ли с утра фортунку для чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin fortune # - где 1 - вкл, 0 - выкл фортунку с утра\n", Config.Csign) - answer += fmt.Sprintf("%sadmin фортунка # - где 1 - вкл, 0 - выкл фортунку с утра\n", Config.Csign) - answer += fmt.Sprintf("%sadmin greet - приветствуем ли новых участников чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin приветствие - приветствуем ли новых участников чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin greet # - где 1 - вкл, 0 - выкл приветствия новых участников чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin приветствие # - где 1 - вкл, 0 - выкл приветствия новых участников чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin goodbye - прощаемся ли с ушедшими участниками чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin прощание - прощаемся ли с ушедшими участниками чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin goodbye # - где 1 - вкл, 0 - выкл прощания с ушедшими участниками чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin прощание # - где 1 - вкл, 0 - выкл прощания с ушедшими участниками чата\n", Config.Csign) - answer += fmt.Sprintf("%sadmin oboobs # - где 1 - вкл, 0 - выкл плагина oboobs\n", Config.Csign) + answer += Config.Csign + "admin censor - показать список состояния типов сообщений\n" + answer += Config.Csign + "админ ценз - показать список состояния типов сообщений\n" + answer += Config.Csign + "admin censor type # - где 1 - вкл, 0 - выкл цензуры для означенного типа сообщений\n" + answer += Config.Csign + "админ ценз тип # - где 1 - вкл, 0 - выкл цензуры для означенного типа сообщений\n" + answer += Config.Csign + "admin fortune - показываем ли с утра фортунку для чата\n" + answer += Config.Csign + "admin фортунка - показываем ли с утра фортунку для чата\n" + answer += Config.Csign + "admin fortune # - где 1 - вкл, 0 - выкл фортунку с утра\n" + answer += Config.Csign + "admin фортунка # - где 1 - вкл, 0 - выкл фортунку с утра\n" + answer += Config.Csign + "admin greet - приветствуем ли новых участников чата\n" + answer += Config.Csign + "admin приветствие - приветствуем ли новых участников чата\n" + answer += Config.Csign + "admin greet # - где 1 - вкл, 0 - выкл приветствия новых участников чата\n" + answer += Config.Csign + "admin приветствие # - где 1 - вкл, 0 - выкл приветствия новых участников чата\n" + answer += Config.Csign + "admin goodbye - прощаемся ли с ушедшими участниками чата\n" + answer += Config.Csign + "admin прощание - прощаемся ли с ушедшими участниками чата\n" + answer += Config.Csign + "admin goodbye # - где 1 - вкл, 0 - выкл прощания с ушедшими участниками чата\n" + answer += Config.Csign + "admin прощание # - где 1 - вкл, 0 - выкл прощания с ушедшими участниками чата\n" + answer += Config.Csign + "admin oboobs # - где 1 - вкл, 0 - выкл плагина oboobs\n" + 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 += Config.Csign + "admin obutts # - где 1 - вкл, 0 - выкл плагина obutts\n" + answer += fmt.Sprintf( "%sadmin obutts - показываем ли попки по просьбе участников чата (команды %sass, %sbutt, %sbooty, %sпопа, %sпопка)\n", Config.Csign, Config.Csign, Config.Csign, Config.Csign, Config.Csign, Config.Csign, ) - answer += fmt.Sprintf("%sadmin chan_msg - оставляем ли сообщения присланные от имени (других) каналов\n", Config.Csign) - answer += fmt.Sprintf("%sadmin chan_msg # - где 1 - оставляем, 0 - удаляем\n", Config.Csign) - answer += fmt.Sprintf( - "%sadmin ban userid sec - выдаём ban указанному user-у на указанное количество секунд (от 30 сек до 1 года), доступно только создателю чата\n", - Config.Csign, - ) - answer += fmt.Sprintf( - "%sadmin mute userid sec - выдаём mute указанному user-у на указанное количество секунд (от 30 сек до 1 года), доступно только создателю чата\n", - Config.Csign, - ) - answer += fmt.Sprintf( - "%sadmin admin mute - разрешено ли обычным админам мьютить участников чата через бота (если бот - админ), (создатель чата всегда может попросить бота-админа замьютить обычного участника чата)\n", - Config.Csign, - ) - answer += fmt.Sprintf("%sadmin admin mute # - где 1 - разрешено, 0 - не разрешено\n", Config.Csign) + + answer += Config.Csign + "admin chan_msg - оставляем ли сообщения присланные от имени (других) каналов\n" + answer += Config.Csign + "admin chan_msg # - где 1 - оставляем, 0 - удаляем\n" + answer += Config.Csign + "admin ban userid sec - выдаём ban указанному user-у на указанное количество секунд (от 30 сек до 1 года), доступно только создателю чата\n" + answer += Config.Csign + "admin mute userid sec - выдаём mute указанному user-у на указанное количество секунд (от 30 сек до 1 года), доступно только создателю чата\n" + answer += Config.Csign + "admin admin mute - разрешено ли обычным админам мьютить участников чата через бота (если бот - админ), (создатель чата всегда может попросить бота-админа замьютить обычного участника чата)\n" + + answer += Config.Csign + "%sadmin admin mute # - где 1 - разрешено, 0 - не разрешено\n" answer += "\n" answer += "Типы сообщений:\naudio voice photo video video_note animation sticker dice game poll document\n" answer += "```" diff --git a/internal/tg/help.go b/internal/tg/help.go index ad744a7..7682c74 100644 --- a/internal/tg/help.go +++ b/internal/tg/help.go @@ -13,7 +13,7 @@ func Help(cmd *echotron.Update) (bool, error) { help += fmt.Sprintf("%shelp | %sпомощь - список команд", Config.Csign, Config.Csign) help += fmt.Sprintf("%sanek | %sанек | %sанекдот - рандомный анекдот с anekdot.ru", Config.Csign, Config.Csign, Config.Csign) - help += fmt.Sprintf("%sbuni - рандомный стрип hapi buni", Config.Csign) + help += Config.Csign + "buni - рандомный стрип hapi buni" help += fmt.Sprintf("%sbunny | %srabbit | %sкролик - кролик", Config.Csign, Config.Csign, Config.Csign) help += fmt.Sprintf("%scat | %sкис - кошечка", Config.Csign, Config.Csign) help += fmt.Sprintf("%scoin | %sмонетка - подбросить монетку - орёл или решка?", Config.Csign, Config.Csign) @@ -28,7 +28,7 @@ func Help(cmd *echotron.Update) (bool, error) { help += fmt.Sprintf("%sfrog | %sлягушка - лягушка", Config.Csign, Config.Csign) help += fmt.Sprintf("%shorse | %sлошадка - лошадка", Config.Csign, Config.Csign) help += fmt.Sprintf("%slat | %sлат - сгенерить фразу из крылатых латинских выражений", Config.Csign, Config.Csign) - help += fmt.Sprintf("%smonkeyuser - рандомный стрип MonkeyUser", Config.Csign) + help += Config.Csign + "monkeyuser - рандомный стрип MonkeyUser" help += fmt.Sprintf("%sowl | %sсова | %sсыч - сова", Config.Csign, Config.Csign, Config.Csign) help += fmt.Sprintf("%sproverb | %sпословица - рандомная русская пословица", Config.Csign, Config.Csign) help += fmt.Sprintf("%sping | %sпинг - попинговать бота", Config.Csign, Config.Csign) @@ -36,11 +36,11 @@ func Help(cmd *echotron.Update) (bool, error) { help += fmt.Sprintf("%ssnail | %sулитка - улитка", Config.Csign, Config.Csign) help += fmt.Sprintf("%sver | %sversion | %sверсия - что-то про версию ПО", Config.Csign, Config.Csign, Config.Csign) help += fmt.Sprintf("%sw <город> | %sп <город> - погода в указанном городе", Config.Csign, Config.Csign) - help += fmt.Sprintf("%sweather <город> - погода в указанном городе", Config.Csign) - help += fmt.Sprintf("%sпогода <город> - погода в указанном городе", Config.Csign) - help += fmt.Sprintf("%sпогодка <город> - погода в указанном городе", Config.Csign) - help += fmt.Sprintf("%sпогадка <город> - погода в указанном городе", Config.Csign) - help += fmt.Sprintf("%sxkcd - рандомный стрип с сайта xkcd.ru", Config.Csign) + help += Config.Csign + "weather <город> - погода в указанном городе" + help += Config.Csign + "погода <город> - погода в указанном городе" + help += Config.Csign + "погодка <город> - погода в указанном городе" + help += Config.Csign + "погадка <город> - погода в указанном городе" + help += Config.Csign + "xkcd - рандомный стрип с сайта xkcd.ru" help += fmt.Sprintf("%skarma фраза | %sкарма фраза - посмотреть карму фразы", Config.Csign, Config.Csign) help += "```\n" help += "Но на самом деле я бот больше для общения, чем для исполнения команд.\n" diff --git a/internal/tg/lib.go b/internal/tg/lib.go new file mode 100644 index 0000000..e5c8ca2 --- /dev/null +++ b/internal/tg/lib.go @@ -0,0 +1,46 @@ +package tg + +import ( + "aleesa-telegram-go/internal/log" + "os" + "path/filepath" +) + +// ReadConfig читает конфиг. Есть несколько преодопределённых локаций, откуда он пытается его вычитать. +// ./data/config.json, ~/.aleesa-telegram-go.json, ~/aleesa-telegram-go.json, ~/aleesa-telegram-go.json. +func ReadConfig() { + var ( + err error + ) + + executablePath, err := os.Executable() + + if err != nil { + log.Fatalf("Unable to get current executable path: %s", err) + } + + configJSONPath := filepath.Dir(executablePath) + "/data/config.json" + + locations := []string{ + "~/.aleesa-telegram-go.json", + "~/aleesa-telegram-go.json", + "/etc/aleesa-telegram-go.json", + configJSONPath, + } + + for _, location := range locations { + Config, err = parseConfig(location) + + if err == nil { + break + } + + log.Errorf("Unable to parse config at %s: %s", location, err) + } + + if err != nil { + os.Exit(1) + } +} + +/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */ diff --git a/internal/tg/parseConfig.go b/internal/tg/parseConfig.go index 91c0119..8a43f1a 100644 --- a/internal/tg/parseConfig.go +++ b/internal/tg/parseConfig.go @@ -10,8 +10,8 @@ import ( "github.com/hjson/hjson-go" ) -// ParseConfig разбирает и валидирует даденный конфиг. -func ParseConfig(path string) (MyConfig, error) { +// parseConfig разбирает и валидирует даденный конфиг. +func parseConfig(path string) (MyConfig, error) { fileInfo, err := os.Stat(path) // Предполагаем, что файла либо нет, либо мы не можем его прочитать, второе надо бы логгировать, но пока забьём. diff --git a/internal/tg/periodicJobs.go b/internal/tg/periodicJobs.go index 304ca39..4aa709c 100644 --- a/internal/tg/periodicJobs.go +++ b/internal/tg/periodicJobs.go @@ -31,9 +31,16 @@ var ( // SendGoodMorning отсылает сообщение "с добрым утром" (сейчас - фортунку). Предполагается, что оно прогоняется по // всем желающим чатам раз в сутки, с утра. Утро отсчитывается от настроек локали в системе. SendGoodMorning = func() { + me, err := tg.GetMe() + + if err != nil { + log.Errorf("Unable to send good mornings message, cannot get info about myself: %s", err) + + return + } + for _, chatID := range chatGroupList { if GetSetting(chatID, "FortuneMsg") == "1" { - me, err := tg.GetMe() // Засылаем фразу в misc-канал (в роутер). var rmsg rMsg diff --git a/internal/tg/settings-db-util.go b/internal/tg/settings-db-util.go index 728b005..7f7b346 100644 --- a/internal/tg/settings-db-util.go +++ b/internal/tg/settings-db-util.go @@ -65,34 +65,29 @@ func InitChatListDB() error { chatListDB, err = pebble.Open(dbPath, &options) if err != nil { - return fmt.Errorf("Unable to open settings db, %s: %w\n", dbPath, err) + return fmt.Errorf("unable to open settings db, %s: %w", dbPath, err) } // Заполним слайс со списком чатов. Операция нудная. iterator, err := chatListDB.NewIter(&pebble.IterOptions{}) if !iterator.First() { - return errors.New("Unable to iterate slice with chats") + return errors.New("unable to iterate slice with chats") } // Попробуем извлечь список ключей и заполнить слайс с чатами. - for { - // Закончили итерировать по списку. - if !iterator.Valid() { - break - } - + for !iterator.Valid() { // Битая база? if err := iterator.Error(); err != nil { chatList = []string{} - return fmt.Errorf("Unable to get chat list: %w", err) + return fmt.Errorf("unable to get chat list: %w", err) } chatName := iterator.Key() - if string(chatName) == "" { - return errors.New("Got empty chat name when query " + chatListDBName) + if len(chatName) == 0 { + return errors.New("got empty chat name when query " + chatListDBName) } chatID := string(chatName) @@ -121,18 +116,21 @@ func AppendChatListDB(chatID string) error { } if err = StoreKV(chatListDB, chatID, "1"); err != nil { - return fmt.Errorf("Unable to append %s to %s: %w", chatID, chatListDBName, err) + return fmt.Errorf("unable to append chat %s to chatListDB %s: %w", chatID, chatListDBName, err) } // Не забываем актуализировать список чатов. chatList = append(chatList, chatID) slices.Sort(chatList) + chatList = slices.Compact(chatList) // Если СhatID начинается с - это значит, что мы имеем дело именно с группой/супергруппой/каналом. if strings.HasPrefix(chatID, "-") { chatGroupList = append(chatGroupList, chatID) + slices.Sort(chatGroupList) + chatGroupList = slices.Compact(chatGroupList) } diff --git a/internal/tg/sigHandler.go b/internal/tg/sigHandler.go index 23671d8..e14a852 100644 --- a/internal/tg/sigHandler.go +++ b/internal/tg/sigHandler.go @@ -66,6 +66,7 @@ func SigHandler() { } log.Debug("Closing known chat list db") + _ = chatListDB.Close() os.Exit(0) diff --git a/internal/tg/telegram.go b/internal/tg/telegram.go index 3a6f608..fb8b0f0 100644 --- a/internal/tg/telegram.go +++ b/internal/tg/telegram.go @@ -75,10 +75,10 @@ func ConstructFullChatName(c *echotron.Chat) string { func ConstructPartialUserUsername(u *echotron.User) string { switch { case u.Username != "": - return fmt.Sprintf("@%s", u.Username) + return "@" + u.Username case u.FirstName != "" && u.LastName != "": - return fmt.Sprintf("%s %s", u.FirstName, u.LastName) + return u.FirstName + " " + u.LastName case u.FirstName != "": return u.FirstName @@ -96,10 +96,10 @@ func ConstructPartialUserUsername(u *echotron.User) string { func ConstructPartialChatUsername(c *echotron.Chat) string { switch { case c.Username != "": - return fmt.Sprintf("@%s", c.Username) + return "@" + c.Username case c.FirstName != "" && c.LastName != "": - return fmt.Sprintf("%s %s", c.FirstName, c.LastName) + return c.FirstName + " " + c.LastName case c.FirstName != "": return c.FirstName @@ -119,13 +119,13 @@ func ConstructUserFirstLastName(u *echotron.User) string { switch { case u.FirstName != "" && u.LastName != "": - user = fmt.Sprintf("%s %s", u.FirstName, u.LastName) + user = u.FirstName + " " + u.LastName case u.FirstName != "": user = u.FirstName case u.LastName != "": user = u.LastName case u.Username != "": - user = fmt.Sprintf("@%s", u.Username) + user = "@" + u.Username default: user = strconv.FormatInt(u.ID, 10) } diff --git a/internal/tg/telegramMsgParser.go b/internal/tg/telegramMsgParser.go index 20fe869..db635bd 100644 --- a/internal/tg/telegramMsgParser.go +++ b/internal/tg/telegramMsgParser.go @@ -21,7 +21,9 @@ func telegramMsgParser(msg *echotron.Update) { return } - AppendChatListDB(strconv.FormatInt(msg.ChatID(), 10)) + if err := AppendChatListDB(strconv.FormatInt(msg.ChatID(), 10)); err != nil { + log.Error(err.Error()) + } // Сообщение о том, что этот чятик изменился, например, превратился в супергруппу. if (msg.Message.MigrateFromChatID < 0) && (msg.Message.MigrateToChatID < 0) { @@ -77,7 +79,7 @@ func telegramMsgParser(msg *echotron.Update) { users = strings.Join(usersSlice, ", ") - users += fmt.Sprintf(" and %s", ConstructTelegramHighlightName(lastOne)) + users += " and " + ConstructTelegramHighlightName(lastOne) } else { users = ConstructTelegramHighlightName(msg.Message.NewChatMembers[0]) } @@ -130,7 +132,7 @@ func telegramMsgParser(msg *echotron.Update) { if GetSetting(strconv.FormatInt(msg.Message.Chat.ID, 10), "GoodbyeMsg") == "1" { user := ConstructUserFirstLastName(msg.Message.From) - goodbye := fmt.Sprintf("Прощаемся с %s", user) + goodbye := "Прощаемся с " + user opts := echotron.MessageOptions{DisableNotification: true, ParseMode: "MarkdownV2"}