Compare commits
No commits in common. "master" and "feature_test_ci" have entirely different histories.
master
...
feature_te
26
context.go
26
context.go
@ -20,7 +20,7 @@ const (
|
|||||||
ctxKeyMessageCleaner
|
ctxKeyMessageCleaner
|
||||||
ctxKeyDataBase
|
ctxKeyDataBase
|
||||||
ctxKeyPlayersBoard
|
ctxKeyPlayersBoard
|
||||||
ctxKeyMessageStorage
|
ctxKeyFragMessages
|
||||||
)
|
)
|
||||||
|
|
||||||
func createLogger(debug bool) *logrus.Logger {
|
func createLogger(debug bool) *logrus.Logger {
|
||||||
@ -44,16 +44,17 @@ func createLogger(debug bool) *logrus.Logger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createContext(config *Config, bot *tgbotapi.BotAPI, ch *commandHandler, db *dbLayer, pb *playersBoard, ms *messageStorage) (context.Context, func()) {
|
func createContext(config *Config, bot *tgbotapi.BotAPI, mc *messageCleaner, ch *commandHandler, db *dbLayer, pb *playersBoard, fms *fragMessages) (context.Context, func()) {
|
||||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, ctxKeyLogger, createLogger(true))
|
ctx = context.WithValue(ctx, ctxKeyLogger, createLogger(true))
|
||||||
ctx = context.WithValue(ctx, ctxKeyBotApi, bot)
|
ctx = context.WithValue(ctx, ctxKeyBotApi, bot)
|
||||||
ctx = context.WithValue(ctx, ctxKeyConfig, config)
|
ctx = context.WithValue(ctx, ctxKeyConfig, config)
|
||||||
|
ctx = context.WithValue(ctx, ctxKeyMessageCleaner, mc)
|
||||||
ctx = context.WithValue(ctx, ctxKeyCommandHandler, ch)
|
ctx = context.WithValue(ctx, ctxKeyCommandHandler, ch)
|
||||||
ctx = context.WithValue(ctx, ctxKeyDataBase, db)
|
ctx = context.WithValue(ctx, ctxKeyDataBase, db)
|
||||||
ctx = context.WithValue(ctx, ctxKeyPlayersBoard, pb)
|
ctx = context.WithValue(ctx, ctxKeyPlayersBoard, pb)
|
||||||
ctx = context.WithValue(ctx, ctxKeyMessageStorage, ms)
|
ctx = context.WithValue(ctx, ctxKeyFragMessages, fms)
|
||||||
|
|
||||||
return ctx, cancelFunc
|
return ctx, cancelFunc
|
||||||
}
|
}
|
||||||
@ -85,6 +86,15 @@ func getConfig(ctx context.Context) *Config {
|
|||||||
panic("Failed to get config from ctx")
|
panic("Failed to get config from ctx")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMessageCleaner(ctx context.Context) *messageCleaner {
|
||||||
|
v := ctx.Value(ctxKeyMessageCleaner)
|
||||||
|
if mc, ok := v.(*messageCleaner); ok {
|
||||||
|
return mc
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("Failed to get message cleaner from ctx")
|
||||||
|
}
|
||||||
|
|
||||||
func getCommandHandler(ctx context.Context) *commandHandler {
|
func getCommandHandler(ctx context.Context) *commandHandler {
|
||||||
v := ctx.Value(ctxKeyCommandHandler)
|
v := ctx.Value(ctxKeyCommandHandler)
|
||||||
if ch, ok := v.(*commandHandler); ok {
|
if ch, ok := v.(*commandHandler); ok {
|
||||||
@ -112,11 +122,11 @@ func getDPlayersBoard(ctx context.Context) *playersBoard {
|
|||||||
panic("Failed to get players board from ctx")
|
panic("Failed to get players board from ctx")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMessageStorage(ctx context.Context) *messageStorage {
|
func getFragMessages(ctx context.Context) *fragMessages {
|
||||||
v := ctx.Value(ctxKeyMessageStorage)
|
v := ctx.Value(ctxKeyFragMessages)
|
||||||
if ms, ok := v.(*messageStorage); ok {
|
if fms, ok := v.(*fragMessages); ok {
|
||||||
return ms
|
return fms
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("Failed to get message storage from ctx")
|
panic("Failed to get frag messages from ctx")
|
||||||
}
|
}
|
||||||
|
90
fragMessages.go
Normal file
90
fragMessages.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fragMessage struct {
|
||||||
|
playerName string
|
||||||
|
entityName string
|
||||||
|
chatID int64
|
||||||
|
messageID int
|
||||||
|
fragCount int
|
||||||
|
latestFragTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type fragMessages struct {
|
||||||
|
mx sync.Mutex
|
||||||
|
messages []*fragMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fragMessage) increaseFrag() *fragMessage {
|
||||||
|
f.fragCount += 1
|
||||||
|
f.latestFragTime = time.Now()
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFragMessages() *fragMessages {
|
||||||
|
return &fragMessages{
|
||||||
|
messages: make([]*fragMessage, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fms *fragMessages) addFrag(ctx context.Context, playerName string, entityName string) error {
|
||||||
|
botApi := getBotApi(ctx)
|
||||||
|
cfg := getConfig(ctx)
|
||||||
|
mc := getMessageCleaner(ctx)
|
||||||
|
|
||||||
|
fms.mx.Lock()
|
||||||
|
defer fms.mx.Unlock()
|
||||||
|
|
||||||
|
for _, fm := range fms.messages {
|
||||||
|
if fm.playerName == playerName && fm.entityName == entityName {
|
||||||
|
mc.resetTimer(fm.messageID, fm.chatID, time.Second*30)
|
||||||
|
fm.increaseFrag()
|
||||||
|
mess := tgbotapi.NewEditMessageText(
|
||||||
|
fm.chatID,
|
||||||
|
fm.messageID,
|
||||||
|
fmt.Sprintf("%s убил %s ✗ *%d*", fm.playerName, fm.entityName, fm.fragCount),
|
||||||
|
)
|
||||||
|
mess.ParseMode = tgbotapi.ModeMarkdown
|
||||||
|
m, err := botApi.Send(mess)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.MessageID != fm.messageID {
|
||||||
|
m.MessageID = fm.messageID
|
||||||
|
getLogger(ctx).Info("message id was changed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mess := tgbotapi.NewMessage(cfg.ChatID, fmt.Sprintf("%s убил %s", playerName, entityName))
|
||||||
|
m, err := botApi.Send(mess)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mc.add(ctx, m.MessageID, cfg.ChatID, time.Second*30)
|
||||||
|
|
||||||
|
fm := &fragMessage{
|
||||||
|
playerName: playerName,
|
||||||
|
entityName: entityName,
|
||||||
|
chatID: cfg.ChatID,
|
||||||
|
messageID: m.MessageID,
|
||||||
|
fragCount: 1,
|
||||||
|
latestFragTime: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
fms.messages = append(fms.messages, fm)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
69
handlers.go
69
handlers.go
@ -4,6 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type command interface {
|
type command interface {
|
||||||
@ -40,21 +42,19 @@ type joinCommand struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *joinCommand) run(ctx context.Context) {
|
func (c *joinCommand) run(ctx context.Context) {
|
||||||
|
botApi := getBotApi(ctx)
|
||||||
|
cfg := getConfig(ctx)
|
||||||
|
mc := getMessageCleaner(ctx)
|
||||||
db := getDB(ctx)
|
db := getDB(ctx)
|
||||||
log := getLogger(ctx)
|
log := getLogger(ctx)
|
||||||
pb := getDPlayersBoard(ctx)
|
pb := getDPlayersBoard(ctx)
|
||||||
ms := getMessageStorage(ctx)
|
|
||||||
|
|
||||||
err := ms.apply(ctx, fmt.Sprintf("join:%s", c.name), time.Minute/2, func(d interface{}) (string, interface{}) {
|
|
||||||
if v, _ := d.(bool); v {
|
|
||||||
return fmt.Sprintf("%s подключился снова", c.name), true
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s подключился", c.name), true
|
|
||||||
})
|
|
||||||
|
|
||||||
|
mess := tgbotapi.NewMessage(cfg.ChatID, fmt.Sprintf("%s подключился", c.name))
|
||||||
|
m, err := botApi.Send(mess)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
} else {
|
||||||
|
mc.add(ctx, m.MessageID, cfg.ChatID, time.Second*30)
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := db.getPlayerByName(ctx, c.name)
|
p, err := db.getPlayerByName(ctx, c.name)
|
||||||
@ -90,21 +90,19 @@ type quitCommand struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *quitCommand) run(ctx context.Context) {
|
func (c *quitCommand) run(ctx context.Context) {
|
||||||
|
botApi := getBotApi(ctx)
|
||||||
|
cfg := getConfig(ctx)
|
||||||
|
mc := getMessageCleaner(ctx)
|
||||||
db := getDB(ctx)
|
db := getDB(ctx)
|
||||||
log := getLogger(ctx)
|
log := getLogger(ctx)
|
||||||
pb := getDPlayersBoard(ctx)
|
pb := getDPlayersBoard(ctx)
|
||||||
ms := getMessageStorage(ctx)
|
|
||||||
|
|
||||||
err := ms.apply(ctx, fmt.Sprintf("quit:%s", c.name), time.Minute/2, func(d interface{}) (string, interface{}) {
|
|
||||||
if v, _ := d.(bool); v {
|
|
||||||
return fmt.Sprintf("%s отключился снова", c.name), true
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s отключился", c.name), true
|
|
||||||
})
|
|
||||||
|
|
||||||
|
mess := tgbotapi.NewMessage(cfg.ChatID, fmt.Sprintf("%s отключился", c.name))
|
||||||
|
m, err := botApi.Send(mess)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
} else {
|
||||||
|
mc.add(ctx, m.MessageID, cfg.ChatID, time.Second*30)
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := db.getPlayerByName(ctx, c.name)
|
p, err := db.getPlayerByName(ctx, c.name)
|
||||||
@ -140,19 +138,6 @@ func (c *deathCommand) run(ctx context.Context) {
|
|||||||
db := getDB(ctx)
|
db := getDB(ctx)
|
||||||
log := getLogger(ctx)
|
log := getLogger(ctx)
|
||||||
pb := getDPlayersBoard(ctx)
|
pb := getDPlayersBoard(ctx)
|
||||||
ms := getMessageStorage(ctx)
|
|
||||||
|
|
||||||
err := ms.apply(ctx, fmt.Sprintf("death:%s", c.name), time.Minute/2, func(d interface{}) (string, interface{}) {
|
|
||||||
if v, _ := d.(bool); v {
|
|
||||||
return fmt.Sprintf("%s умудрился опять помереть от %s", c.name, c.deathType), true
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s пал смертью храбрых от %s", c.name, c.deathType), true
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := db.getPlayerByName(ctx, c.name)
|
p, err := db.getPlayerByName(ctx, c.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -180,7 +165,12 @@ func (c *killCommand) run(ctx context.Context) {
|
|||||||
db := getDB(ctx)
|
db := getDB(ctx)
|
||||||
log := getLogger(ctx)
|
log := getLogger(ctx)
|
||||||
pb := getDPlayersBoard(ctx)
|
pb := getDPlayersBoard(ctx)
|
||||||
ms := getMessageStorage(ctx)
|
fms := getFragMessages(ctx)
|
||||||
|
|
||||||
|
err := fms.addFrag(ctx, c.name, c.entity)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
p, err := db.getPlayerByName(ctx, c.name)
|
p, err := db.getPlayerByName(ctx, c.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -193,21 +183,6 @@ func (c *killCommand) run(ctx context.Context) {
|
|||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
f := func(d interface{}) (string, interface{}) {
|
|
||||||
if fragsNum, ok := d.(int); ok {
|
|
||||||
fragsNum++
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s убил %s ✗ *%d*", p.name, c.entity, fragsNum), fragsNum
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s убил %s", p.name, c.entity), 1
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ms.apply(ctx, fmt.Sprintf("kill:%s:%s", p.id, c.entity), time.Minute/2, f)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = pb.update(ctx, achievementMaxFrags, achievementPeaceable)
|
err = pb.update(ctx, achievementMaxFrags, achievementPeaceable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
34
main.go
34
main.go
@ -55,11 +55,15 @@ func main() {
|
|||||||
os.Exit(5)
|
os.Exit(5)
|
||||||
}
|
}
|
||||||
|
|
||||||
ch := newCommandHandler()
|
mc := newMessageCleaner(bot, &wg)
|
||||||
pb := newPlayersBoard()
|
|
||||||
ms := NewMessageStorage()
|
|
||||||
|
|
||||||
ctx, cancelFunc := createContext(&cfg, bot, ch, db, pb, ms)
|
ch := newCommandHandler()
|
||||||
|
|
||||||
|
pb := newPlayersBoard()
|
||||||
|
|
||||||
|
fms := newFragMessages()
|
||||||
|
|
||||||
|
ctx, cancelFunc := createContext(&cfg, bot, mc, ch, db, pb, fms)
|
||||||
|
|
||||||
getLogger(ctx).Infof("Run...")
|
getLogger(ctx).Infof("Run...")
|
||||||
|
|
||||||
@ -69,8 +73,8 @@ func main() {
|
|||||||
os.Exit(5)
|
os.Exit(5)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runPlayerBoard(ctx, pb, &wg)
|
||||||
runCommandHandler(ctx, ch, &wg)
|
runCommandHandler(ctx, ch, &wg)
|
||||||
runMessageStorage(ctx, ms, &wg)
|
|
||||||
runHttpServer(ctx, cfg.Http, &wg)
|
runHttpServer(ctx, cfg.Http, &wg)
|
||||||
runSignalHandler(ctx, cancelFunc)
|
runSignalHandler(ctx, cancelFunc)
|
||||||
|
|
||||||
@ -79,6 +83,16 @@ func main() {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runPlayerBoard(ctx context.Context, pb *playersBoard, wg *sync.WaitGroup) {
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
pb.run(ctx)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
func runCommandHandler(ctx context.Context, ch *commandHandler, wg *sync.WaitGroup) {
|
func runCommandHandler(ctx context.Context, ch *commandHandler, wg *sync.WaitGroup) {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
@ -89,16 +103,6 @@ func runCommandHandler(ctx context.Context, ch *commandHandler, wg *sync.WaitGro
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMessageStorage(ctx context.Context, ms *messageStorage, wg *sync.WaitGroup) {
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
ms.run(ctx)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func runHttpServer(ctx context.Context, addr string, wg *sync.WaitGroup) {
|
func runHttpServer(ctx context.Context, addr string, wg *sync.WaitGroup) {
|
||||||
server := http.Server{
|
server := http.Server{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
|
91
messageCleaner.go
Normal file
91
messageCleaner.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type messageToClean struct {
|
||||||
|
messID int
|
||||||
|
chatID int64
|
||||||
|
timer *time.Timer
|
||||||
|
}
|
||||||
|
|
||||||
|
type messageCleaner struct {
|
||||||
|
botApi *tgbotapi.BotAPI
|
||||||
|
wg *sync.WaitGroup
|
||||||
|
messages []*messageToClean
|
||||||
|
mx sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMessageCleaner(bot *tgbotapi.BotAPI, wg *sync.WaitGroup) *messageCleaner {
|
||||||
|
return &messageCleaner{
|
||||||
|
botApi: bot,
|
||||||
|
wg: wg,
|
||||||
|
messages: make([]*messageToClean, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *messageCleaner) add(ctx context.Context, messID int, chatID int64, d time.Duration) {
|
||||||
|
m.mx.Lock()
|
||||||
|
defer m.mx.Unlock()
|
||||||
|
|
||||||
|
for _, ms := range m.messages {
|
||||||
|
if ms.chatID == chatID && ms.messID == messID {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer m.wg.Done()
|
||||||
|
|
||||||
|
ms := &messageToClean{
|
||||||
|
messID: messID,
|
||||||
|
chatID: chatID,
|
||||||
|
timer: time.NewTimer(d),
|
||||||
|
}
|
||||||
|
|
||||||
|
m.messages = append(m.messages, ms)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ms.timer.C:
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
|
||||||
|
m.remove(messID, chatID)
|
||||||
|
|
||||||
|
_, _ = m.botApi.DeleteMessage(tgbotapi.DeleteMessageConfig{
|
||||||
|
MessageID: messID,
|
||||||
|
ChatID: chatID,
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *messageCleaner) remove(messID int, chatID int64) {
|
||||||
|
m.mx.Lock()
|
||||||
|
defer m.mx.Unlock()
|
||||||
|
|
||||||
|
for i, ms := range m.messages {
|
||||||
|
if ms.chatID == chatID && ms.messID == messID {
|
||||||
|
m.messages = append(m.messages[:i], m.messages[i+1:]...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *messageCleaner) resetTimer(messID int, chatID int64, d time.Duration) {
|
||||||
|
m.mx.Lock()
|
||||||
|
defer m.mx.Unlock()
|
||||||
|
|
||||||
|
for _, ms := range m.messages {
|
||||||
|
if ms.chatID == chatID && ms.messID == messID {
|
||||||
|
ms.timer.Reset(d)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,131 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
|
||||||
)
|
|
||||||
|
|
||||||
type messageData struct {
|
|
||||||
key string
|
|
||||||
messID int
|
|
||||||
chatID int64
|
|
||||||
data interface{}
|
|
||||||
timer *time.Timer
|
|
||||||
}
|
|
||||||
|
|
||||||
type messageStorage struct {
|
|
||||||
m sync.Mutex
|
|
||||||
messages []*messageData
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMessageStorage() *messageStorage {
|
|
||||||
return &messageStorage{
|
|
||||||
messages: make([]*messageData, 0, 20),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteMessageFromTelegram(ctx context.Context, messID int, chatID int64) {
|
|
||||||
botApi := getBotApi(ctx)
|
|
||||||
|
|
||||||
_, err := botApi.DeleteMessage(tgbotapi.DeleteMessageConfig{
|
|
||||||
MessageID: messID,
|
|
||||||
ChatID: chatID,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
getLogger(ctx).Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *messageStorage) run(ctx context.Context) {
|
|
||||||
<-ctx.Done()
|
|
||||||
|
|
||||||
ms.m.Lock()
|
|
||||||
defer ms.m.Unlock()
|
|
||||||
|
|
||||||
for _, m := range ms.messages {
|
|
||||||
deleteMessageFromTelegram(ctx, m.messID, m.chatID)
|
|
||||||
}
|
|
||||||
|
|
||||||
ms.messages = ms.messages[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *messageStorage) runTimeCleaner(ctx context.Context, md *messageData, d time.Duration) {
|
|
||||||
if d <= 0 {
|
|
||||||
md.timer = nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t := time.NewTimer(d)
|
|
||||||
md.timer = t
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
<-t.C
|
|
||||||
|
|
||||||
ms.m.Lock()
|
|
||||||
defer ms.m.Unlock()
|
|
||||||
|
|
||||||
if md.timer == t {
|
|
||||||
for i, m := range ms.messages {
|
|
||||||
if m == md {
|
|
||||||
deleteMessageFromTelegram(ctx, m.messID, m.chatID)
|
|
||||||
ms.messages = append(ms.messages[:i], ms.messages[i+1:]...)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
type messageChanger func(interface{}) (string, interface{})
|
|
||||||
|
|
||||||
func (ms *messageStorage) apply(ctx context.Context, key string, d time.Duration, mc messageChanger) error {
|
|
||||||
ms.m.Lock()
|
|
||||||
defer ms.m.Unlock()
|
|
||||||
|
|
||||||
botApi := getBotApi(ctx)
|
|
||||||
cfg := getConfig(ctx)
|
|
||||||
|
|
||||||
for _, md := range ms.messages {
|
|
||||||
if md.key == key {
|
|
||||||
text, data := mc(md.data)
|
|
||||||
|
|
||||||
mess := tgbotapi.NewEditMessageText(md.chatID, md.messID, text)
|
|
||||||
mess.ParseMode = tgbotapi.ModeMarkdown
|
|
||||||
_, err := botApi.Send(mess)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
md.data = data
|
|
||||||
ms.runTimeCleaner(ctx, md, d)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
text, data := mc(nil)
|
|
||||||
|
|
||||||
mess := tgbotapi.NewMessage(cfg.ChatID, text)
|
|
||||||
mess.ParseMode = tgbotapi.ModeMarkdown
|
|
||||||
m, err := botApi.Send(mess)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
md := &messageData{
|
|
||||||
key: key,
|
|
||||||
messID: m.MessageID,
|
|
||||||
chatID: cfg.ChatID,
|
|
||||||
data: data,
|
|
||||||
}
|
|
||||||
|
|
||||||
ms.messages = append(ms.messages, md)
|
|
||||||
ms.runTimeCleaner(ctx, md, d)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -7,7 +7,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
|
||||||
"github.com/hako/durafmt"
|
"github.com/hako/durafmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type achievement uint8
|
type achievement uint8
|
||||||
@ -51,10 +53,11 @@ var allAchievement = []achievement{
|
|||||||
}
|
}
|
||||||
|
|
||||||
type playerInfo struct {
|
type playerInfo struct {
|
||||||
playerID string
|
playerID string
|
||||||
isOnline bool
|
playerMessageID int
|
||||||
achievements []achievement
|
isOnline bool
|
||||||
messageText string
|
achievements []achievement
|
||||||
|
messageText string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *playerInfo) setOnline(v bool) *playerInfo {
|
func (p *playerInfo) setOnline(v bool) *playerInfo {
|
||||||
@ -71,6 +74,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (p *playerInfo) updatePlayerInfo(ctx context.Context) error {
|
func (p *playerInfo) updatePlayerInfo(ctx context.Context) error {
|
||||||
|
botApi := getBotApi(ctx)
|
||||||
|
conf := getConfig(ctx)
|
||||||
db := getDB(ctx)
|
db := getDB(ctx)
|
||||||
|
|
||||||
lines := make([]string, 0, 10)
|
lines := make([]string, 0, 10)
|
||||||
@ -127,21 +132,46 @@ func (p *playerInfo) updatePlayerInfo(ctx context.Context) error {
|
|||||||
text := strings.Join(lines, "\n")
|
text := strings.Join(lines, "\n")
|
||||||
|
|
||||||
if text != p.messageText {
|
if text != p.messageText {
|
||||||
messStorage := getMessageStorage(ctx)
|
|
||||||
err := messStorage.apply(ctx, fmt.Sprintf("playerBoard:%s", p.playerID), 0, func(interface{}) (string, interface{}) {
|
|
||||||
return text, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
var c tgbotapi.Chattable
|
||||||
return err
|
|
||||||
|
if p.playerMessageID == 0 {
|
||||||
|
mess := tgbotapi.NewMessage(conf.ChatID, text)
|
||||||
|
mess.ParseMode = tgbotapi.ModeMarkdown
|
||||||
|
|
||||||
|
c = mess
|
||||||
|
} else {
|
||||||
|
mess := tgbotapi.NewEditMessageText(conf.ChatID, p.playerMessageID, text)
|
||||||
|
mess.ParseMode = tgbotapi.ModeMarkdown
|
||||||
|
|
||||||
|
c = mess
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m, err := botApi.Send(c)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to send message")
|
||||||
|
}
|
||||||
|
|
||||||
|
p.playerMessageID = m.MessageID
|
||||||
p.messageText = text
|
p.messageText = text
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *playerInfo) deletePlayerInfo(ctx context.Context) error {
|
||||||
|
botApi := getBotApi(ctx)
|
||||||
|
conf := getConfig(ctx)
|
||||||
|
|
||||||
|
mess := tgbotapi.NewDeleteMessage(conf.ChatID, p.playerMessageID)
|
||||||
|
_, err := botApi.Send(mess)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to send message")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *playerInfo) setAchievement(ach achievement) {
|
func (p *playerInfo) setAchievement(ach achievement) {
|
||||||
for _, a := range p.achievements {
|
for _, a := range p.achievements {
|
||||||
if a == ach {
|
if a == ach {
|
||||||
@ -219,13 +249,11 @@ func (pb *playersBoard) getPlayerBoard(playerID string) *playerInfo {
|
|||||||
pb.mx.Lock()
|
pb.mx.Lock()
|
||||||
defer pb.mx.Unlock()
|
defer pb.mx.Unlock()
|
||||||
|
|
||||||
pi := &playerInfo{
|
pb.players = append(pb.players, &playerInfo{
|
||||||
playerID: playerID,
|
playerID: playerID,
|
||||||
}
|
})
|
||||||
|
|
||||||
pb.players = append(pb.players, pi)
|
return pb.players[len(pb.players)-1]
|
||||||
|
|
||||||
return pi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pb *playersBoard) updateAchievements(ctx context.Context, ach achievement) error {
|
func (pb *playersBoard) updateAchievements(ctx context.Context, ach achievement) error {
|
||||||
@ -319,3 +347,19 @@ func (pb *playersBoard) update(ctx context.Context, as ...achievement) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pb *playersBoard) run(ctx context.Context) {
|
||||||
|
log := getLogger(ctx)
|
||||||
|
|
||||||
|
<-ctx.Done()
|
||||||
|
|
||||||
|
pb.mx.Lock()
|
||||||
|
defer pb.mx.Unlock()
|
||||||
|
|
||||||
|
for _, p := range pb.players {
|
||||||
|
err := p.deletePlayerInfo(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user