[WIP] Implement good morning message for all willing chats, update TODO.md
This commit is contained in:
3
TODO.md
3
TODO.md
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
1 [V] [V] цензор сообщений определённого типа.
|
1 [V] [V] цензор сообщений определённого типа.
|
||||||
|
|
||||||
2 [ ] [V] фортунка каждое утро. (+ добавить время, относительно gmt, когда показывать фортунку). См. п.13.
|
2 [V] [V] фортунка каждое утро. См. п.13.
|
||||||
|
|
||||||
3 [V] [V] Приветствие новых участников
|
3 [V] [V] Приветствие новых участников
|
||||||
|
|
||||||
@@ -68,6 +68,7 @@
|
|||||||
[V] регулярных компакций базы с настройками.
|
[V] регулярных компакций базы с настройками.
|
||||||
[ ] регулярного обслуживания таблиц с пользователями.
|
[ ] регулярного обслуживания таблиц с пользователями.
|
||||||
|
|
||||||
|
14. [ ] в функции AppendChatListDB для нового чата добавлять дефолтные значения настроек.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -89,13 +89,20 @@ func main() {
|
|||||||
go tg.SigHandler()
|
go tg.SigHandler()
|
||||||
go tg.Telega(tg.Config)
|
go tg.Telega(tg.Config)
|
||||||
|
|
||||||
// Periodically compact/flush pebble dbs.
|
// Периодически обслуживаем базы с настройками чатов.
|
||||||
if job, err := scheduler.Every(1).Hours().NotImmediately().Run(tg.TidySettingsDB); err != nil {
|
if job, err := scheduler.Every(1).Hours().NotImmediately().Run(tg.TidySettingsDB); err != nil {
|
||||||
log.Errorf("Unable to schedule periodic settings db flush: %s", err)
|
log.Errorf("Unable to schedule periodic settings db flush: %s", err)
|
||||||
} else {
|
} else {
|
||||||
tg.PeriodicJobs = append(tg.PeriodicJobs, job)
|
tg.PeriodicJobs = append(tg.PeriodicJobs, job)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Отправлем "доброе утро" каждое утро для всех чатов, которые на это подписались.
|
||||||
|
if job, err := scheduler.Every().Day().At("8:10").Run(tg.SendGoodMorning); err != nil {
|
||||||
|
log.Errorf("Unable to schedule send good morning task: %s", err)
|
||||||
|
} else {
|
||||||
|
tg.PeriodicJobs = append(tg.PeriodicJobs, job)
|
||||||
|
}
|
||||||
|
|
||||||
// Обработчик событий от редиски.
|
// Обработчик событий от редиски.
|
||||||
for msg := range redisMsgChan {
|
for msg := range redisMsgChan {
|
||||||
if tg.Shutdown {
|
if tg.Shutdown {
|
||||||
|
|||||||
@@ -35,10 +35,19 @@ var (
|
|||||||
// settingsDB мапка с открытыми дескрипторами баз с настройками.
|
// settingsDB мапка с открытыми дескрипторами баз с настройками.
|
||||||
settingsDB = make(map[string]*pebble.DB)
|
settingsDB = make(map[string]*pebble.DB)
|
||||||
|
|
||||||
|
// chatListDB объектик *pebble.DB с базой, в которой лежит список чатов.
|
||||||
|
chatListDB *pebble.DB
|
||||||
|
|
||||||
|
// chatListDBName имя базы данных со списком чатов.
|
||||||
|
chatListDBName = "chat_list_db"
|
||||||
|
|
||||||
|
// chatList слайс со списоком чатов.
|
||||||
|
chatList = []string{}
|
||||||
|
|
||||||
// tg is var for telegram api.
|
// tg is var for telegram api.
|
||||||
tg echotron.API
|
tg echotron.API
|
||||||
|
|
||||||
// introduceGreet приветсвенные фразы для новых участников чата.
|
// introduceGreet приветственные фразы для новых участников чата.
|
||||||
introduceGreet = [...]string{
|
introduceGreet = [...]string{
|
||||||
"Дратути",
|
"Дратути",
|
||||||
"Дарована",
|
"Дарована",
|
||||||
|
|||||||
@@ -2,11 +2,14 @@ package tg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"aleesa-telegram-go/internal/log"
|
"aleesa-telegram-go/internal/log"
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// TidySettingsDB flushes regularly pebble dbs with settings. Remmended action to keeb that db in a good shape.
|
// TidySettingsDB флашит на диск базу с настройками чатов. Рекомендуется делать это время от времени для поддержания
|
||||||
// Meant to be run about hourly or something like that.
|
// производительности базы на должном уровне.
|
||||||
|
// Предполагается, что это происходит где-то раз в час, чаще смысла нет.
|
||||||
TidySettingsDB = func() {
|
TidySettingsDB = func() {
|
||||||
if len(settingsDB) > 0 {
|
if len(settingsDB) > 0 {
|
||||||
for name, db := range settingsDB {
|
for name, db := range settingsDB {
|
||||||
@@ -17,6 +20,56 @@ var (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debugf("Flushing %s", chatListDBName)
|
||||||
|
|
||||||
|
if err := chatListDB.Flush(); err != nil {
|
||||||
|
log.Errorf("Unable to Flush() %s: %s", chatListDBName, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendGoodMorning отсылает сообщение "с добрым утром" (сейчас - фортунку). Предполагается, что оно прогоняется по
|
||||||
|
// всем желающим чатам раз в сутки, с утра. Утро отсчитывается от настроек локали в системе.
|
||||||
|
SendGoodMorning = func() {
|
||||||
|
for _, chatID := range chatList {
|
||||||
|
if GetSetting(chatID, "FortuneMsg") == "1" {
|
||||||
|
me, err := tg.GetMe()
|
||||||
|
// Засылаем фразу в misc-канал (в роутер).
|
||||||
|
var rmsg rMsg
|
||||||
|
|
||||||
|
rmsg.Chatid = chatID
|
||||||
|
rmsg.Userid = strconv.FormatInt(me.Result.ID, 10)
|
||||||
|
rmsg.Message = "!f"
|
||||||
|
rmsg.Mode = "public"
|
||||||
|
rmsg.Plugin = "telegram"
|
||||||
|
rmsg.From = "telegram"
|
||||||
|
rmsg.Misc.Csign = Config.Csign
|
||||||
|
rmsg.Misc.Fwdcnt = 1
|
||||||
|
|
||||||
|
rmsg.Misc.Botnick = ConstructPartialUserUsername(me.Result)
|
||||||
|
rmsg.Misc.Username = ConstructPartialUserUsername(me.Result)
|
||||||
|
|
||||||
|
rmsg.Misc.GoodMorning = 1
|
||||||
|
// Форматирование нужно только для вывода некоторых ответов на команды, команды мы ловим выше по тексту, так что
|
||||||
|
// смело ставим тут 0.
|
||||||
|
rmsg.Misc.Msgformat = 0
|
||||||
|
|
||||||
|
data, err := json.Marshal(rmsg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Unable to to serialize message for redis: %s", err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Заталкиваем наш json в редиску.
|
||||||
|
if err := RedisClient.Publish(Ctx, Config.Redis.Channel, data).Err(); err != nil {
|
||||||
|
log.Warnf("Unable to send data to redis channel %s: %s", Config.Redis.Channel, err)
|
||||||
|
} else {
|
||||||
|
log.Debugf("Sent msg to redis channel %s: %s", Config.Redis.Channel, string(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"aleesa-telegram-go/internal/log"
|
"aleesa-telegram-go/internal/log"
|
||||||
|
|
||||||
@@ -45,6 +46,81 @@ func FetchV(db *pebble.DB, key string) (string, error) {
|
|||||||
return valueString, err
|
return valueString, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitChatListDB открывает для пользования базу со списком чатов.
|
||||||
|
func InitChatListDB() error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
options pebble.Options
|
||||||
|
dbPath = Config.DataDir + "/" + chatListDBName
|
||||||
|
)
|
||||||
|
|
||||||
|
// По дефолту ограничение ставится на мегабайты данных, а не на количество файлов, поэтому с дефолтными
|
||||||
|
// настройками порождается огромное количество файлов. Умолчальное ограничение на количество файлов - 500 штук,
|
||||||
|
// что нас не устраивает, поэтому немного снизим эту цифру до более приемлемых значений.
|
||||||
|
options.L0CompactionFileThreshold = 8
|
||||||
|
chatListDB, err = pebble.Open(dbPath, &options)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to open settings db, %s: %w\n", dbPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Заполним слайс со списком чатов. Операция нудная.
|
||||||
|
iterator, err := chatListDB.NewIter(&pebble.IterOptions{})
|
||||||
|
|
||||||
|
if !iterator.First() {
|
||||||
|
return errors.New("Unable to iterate slice with chats")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Попробуем извлечь список ключей и заполнить слайс с чатами.
|
||||||
|
for {
|
||||||
|
// Закончили итерировать по списку.
|
||||||
|
if !iterator.Valid() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Битая база?
|
||||||
|
if err := iterator.Error(); err != nil {
|
||||||
|
chatList = []string{}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
chatList = append(chatList, string(chatName))
|
||||||
|
|
||||||
|
iterator.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendChatListDB добавляет чат в список известных боту. Можно добавлять чаты не глядя, дубликатов не добавится.
|
||||||
|
// Bot API нам такую информацию не даёт.
|
||||||
|
func AppendChatListDB(chatID string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if slices.Contains(chatList, chatID) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = StoreKV(chatListDB, chatID, "{}"); err != nil {
|
||||||
|
return fmt.Errorf("Unable to append %s to %s: %w", chatID, chatListDBName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: fill in defaults!
|
||||||
|
|
||||||
|
// Не забываем актуализировать список чатов.
|
||||||
|
chatList = append(chatList, chatID)
|
||||||
|
slices.Sort(chatList)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// GetSetting достаёт настройку из БД с настройками.
|
// GetSetting достаёт настройку из БД с настройками.
|
||||||
func GetSetting(chatID string, setting string) string {
|
func GetSetting(chatID string, setting string) string {
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ func telegramMsgParser(msg *echotron.Update) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AppendChatListDB(strconv.FormatInt(msg.ChatID(), 10))
|
||||||
|
|
||||||
// Сообщение о том, что этот чятик изменился, например, превратился в супергруппу.
|
// Сообщение о том, что этот чятик изменился, например, превратился в супергруппу.
|
||||||
if (msg.Message.MigrateFromChatID < 0) && (msg.Message.MigrateToChatID < 0) {
|
if (msg.Message.MigrateFromChatID < 0) && (msg.Message.MigrateToChatID < 0) {
|
||||||
// TODO: поддержать миграцию настроек чата на новый chatId.
|
// TODO: поддержать миграцию настроек чата на новый chatId.
|
||||||
|
|||||||
Reference in New Issue
Block a user