mirror of
https://github.com/dancojocaru2000/CfrTrainInfoTelegramBot.git
synced 2025-02-22 17:19:39 +02:00
Handle unsubscription well
This commit is contained in:
parent
fa20c381a3
commit
be940ffebe
5 changed files with 144 additions and 41 deletions
5
.idea/vcs.xml
generated
5
.idea/vcs.xml
generated
|
@ -9,6 +9,11 @@
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
</profile>
|
</profile>
|
||||||
</component>
|
</component>
|
||||||
|
<component name="GitSharedSettings">
|
||||||
|
<option name="FORCE_PUSH_PROHIBITED_PATTERNS">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
|
|
7
main.go
7
main.go
|
@ -257,7 +257,7 @@ func handler(ctx context.Context, b *tgBot.Bot, update *models.Update, subs *sub
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: Update message to contain unsubscribe button
|
log.Printf("DEBUG: Subscribed: chatID %d, trainNumber %s, date %s, groupIndex %d", update.CallbackQuery.Message.Chat.ID, trainNumber, date.Format("2006-01-02"), groupIndex)
|
||||||
response = &handlers.HandlerResponse{
|
response = &handlers.HandlerResponse{
|
||||||
CallbackAnswer: &tgBot.AnswerCallbackQueryParams{
|
CallbackAnswer: &tgBot.AnswerCallbackQueryParams{
|
||||||
Text: fmt.Sprintf("Subscribed successfully!"),
|
Text: fmt.Sprintf("Subscribed successfully!"),
|
||||||
|
@ -287,7 +287,7 @@ func handler(ctx context.Context, b *tgBot.Bot, update *models.Update, subs *sub
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: Update message to contain unsubscribe button
|
log.Printf("DEBUG: Unsubscribed: chatID %d, trainNumber %s, date %s, groupIndex %d", update.CallbackQuery.Message.Chat.ID, trainNumber, date.Format("2006-01-02"), groupIndex)
|
||||||
response = &handlers.HandlerResponse{
|
response = &handlers.HandlerResponse{
|
||||||
CallbackAnswer: &tgBot.AnswerCallbackQueryParams{
|
CallbackAnswer: &tgBot.AnswerCallbackQueryParams{
|
||||||
Text: fmt.Sprintf("Unsubscribed successfully!"),
|
Text: fmt.Sprintf("Unsubscribed successfully!"),
|
||||||
|
@ -301,6 +301,9 @@ func handler(ctx context.Context, b *tgBot.Bot, update *models.Update, subs *sub
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.Printf("WARN : Unknown callback query method: %s", splitted[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,11 @@ func HandleTrainNumberCommand(ctx context.Context, trainNumber string, date time
|
||||||
Message: &bot.SendMessageParams{
|
Message: &bot.SendMessageParams{
|
||||||
Text: fmt.Sprintf("The train %s was not found.", trainNumber),
|
Text: fmt.Sprintf("The train %s was not found.", trainNumber),
|
||||||
},
|
},
|
||||||
|
ShouldUnsubscribe: func() bool {
|
||||||
|
now := time.Now().In(utils.Location)
|
||||||
|
midnightYesterday := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, utils.Location)
|
||||||
|
return date.Before(midnightYesterday)
|
||||||
|
}(),
|
||||||
}, false
|
}, false
|
||||||
case errors.Is(err, api.ServerError):
|
case errors.Is(err, api.ServerError):
|
||||||
log.Printf("ERROR: In handle train number: %s", err.Error())
|
log.Printf("ERROR: In handle train number: %s", err.Error())
|
||||||
|
@ -53,6 +58,11 @@ func HandleTrainNumberCommand(ctx context.Context, trainNumber string, date time
|
||||||
Message: &bot.SendMessageParams{
|
Message: &bot.SendMessageParams{
|
||||||
Text: fmt.Sprintf("Unknown server error when searching for train %s.", trainNumber),
|
Text: fmt.Sprintf("Unknown server error when searching for train %s.", trainNumber),
|
||||||
},
|
},
|
||||||
|
ShouldUnsubscribe: func() bool {
|
||||||
|
now := time.Now().In(utils.Location)
|
||||||
|
midnightYesterday := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, utils.Location)
|
||||||
|
return date.Before(midnightYesterday)
|
||||||
|
}(),
|
||||||
}, false
|
}, false
|
||||||
default:
|
default:
|
||||||
log.Printf("ERROR: In handle train number: %s", err.Error())
|
log.Printf("ERROR: In handle train number: %s", err.Error())
|
||||||
|
@ -63,6 +73,32 @@ func HandleTrainNumberCommand(ctx context.Context, trainNumber string, date time
|
||||||
groupIndex = 0
|
groupIndex = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldUnsubscribe := func() bool {
|
||||||
|
if len(trainData.Groups) <= groupIndex {
|
||||||
|
groupIndex = 0
|
||||||
|
}
|
||||||
|
now := time.Now().In(utils.Location)
|
||||||
|
midnightYesterday := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, utils.Location)
|
||||||
|
lastStation := trainData.Groups[groupIndex].
|
||||||
|
Stations[len(trainData.Groups[groupIndex].Stations)-1]
|
||||||
|
if now.After(lastStation.Arrival.
|
||||||
|
ScheduleTime.Add(time.Hour * 6)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if trainData.Groups[groupIndex].
|
||||||
|
Status != nil && trainData.Groups[groupIndex].
|
||||||
|
Status.Station == lastStation.Name &&
|
||||||
|
trainData.Groups[groupIndex].Status.
|
||||||
|
State == "arrival" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if date.Before(midnightYesterday) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}()
|
||||||
|
|
||||||
message := bot.SendMessageParams{}
|
message := bot.SendMessageParams{}
|
||||||
if groupIndex == -1 {
|
if groupIndex == -1 {
|
||||||
message.Text = fmt.Sprintf("Train %s %s contains multiple groups. Please choose one.", trainData.Rank, trainData.Number)
|
message.Text = fmt.Sprintf("Train %s %s contains multiple groups. Please choose one.", trainData.Rank, trainData.Number)
|
||||||
|
@ -136,7 +172,9 @@ func HandleTrainNumberCommand(ctx context.Context, trainNumber string, date time
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
buttonKind := TrainInfoResponseButtonIncludeSub
|
buttonKind := TrainInfoResponseButtonIncludeSub
|
||||||
if isSubscribed {
|
if shouldUnsubscribe {
|
||||||
|
buttonKind = TrainInfoResponseButtonExcludeSub
|
||||||
|
} else if isSubscribed {
|
||||||
buttonKind = TrainInfoResponseButtonIncludeUnsub
|
buttonKind = TrainInfoResponseButtonIncludeUnsub
|
||||||
}
|
}
|
||||||
message.ReplyMarkup = GetTrainNumberCommandResponseButtons(trainData.Number, group.Stations[0].Departure.ScheduleTime, groupIndex, buttonKind)
|
message.ReplyMarkup = GetTrainNumberCommandResponseButtons(trainData.Number, group.Stations[0].Departure.ScheduleTime, groupIndex, buttonKind)
|
||||||
|
@ -154,6 +192,7 @@ func HandleTrainNumberCommand(ctx context.Context, trainNumber string, date time
|
||||||
|
|
||||||
return &HandlerResponse{
|
return &HandlerResponse{
|
||||||
Message: &message,
|
Message: &message,
|
||||||
|
ShouldUnsubscribe: shouldUnsubscribe,
|
||||||
}, true
|
}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ type HandlerResponse struct {
|
||||||
CallbackAnswer *bot.AnswerCallbackQueryParams
|
CallbackAnswer *bot.AnswerCallbackQueryParams
|
||||||
MessageEdits []*bot.EditMessageTextParams
|
MessageEdits []*bot.EditMessageTextParams
|
||||||
MessageMarkupEdits []*bot.EditMessageReplyMarkupParams
|
MessageMarkupEdits []*bot.EditMessageReplyMarkupParams
|
||||||
|
ShouldUnsubscribe bool
|
||||||
Injected struct {
|
Injected struct {
|
||||||
ChatId int64
|
ChatId int64
|
||||||
MessageId int
|
MessageId int
|
||||||
|
|
|
@ -98,15 +98,14 @@ func (sub *Subscriptions) DeleteSubscription(chatId int64, messageId int) (*SubD
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var result *SubData
|
var result SubData
|
||||||
if deleteIndex != -1 {
|
if deleteIndex != -1 {
|
||||||
result = &SubData{}
|
result = datas[deleteIndex]
|
||||||
*result = datas[deleteIndex]
|
|
||||||
datas[deleteIndex] = datas[len(datas)-1]
|
datas[deleteIndex] = datas[len(datas)-1]
|
||||||
datas = datas[:len(datas)-1]
|
datas = datas[:len(datas)-1]
|
||||||
|
|
||||||
_, err := database.WriteDB(func(db *gorm.DB) (*gorm.DB, error) {
|
_, err := database.WriteDB(func(db *gorm.DB) (*gorm.DB, error) {
|
||||||
db.Delete(result)
|
db.Delete(&result)
|
||||||
return db, db.Error
|
return db, db.Error
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -120,7 +119,7 @@ func (sub *Subscriptions) DeleteSubscription(chatId int64, messageId int) (*SubD
|
||||||
} else {
|
} else {
|
||||||
sub.data[chatId] = datas
|
sub.data[chatId] = datas
|
||||||
}
|
}
|
||||||
return result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sub *Subscriptions) CheckSubscriptions(ctx context.Context) {
|
func (sub *Subscriptions) CheckSubscriptions(ctx context.Context) {
|
||||||
|
@ -142,20 +141,29 @@ type workerData struct {
|
||||||
data SubData
|
data SubData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type unsubscribe struct {
|
||||||
|
chatId int64
|
||||||
|
messageId int
|
||||||
|
}
|
||||||
|
|
||||||
|
type workerResponseData struct {
|
||||||
|
unsubscribe *unsubscribe
|
||||||
|
}
|
||||||
|
|
||||||
func (sub *Subscriptions) executeChecks(ctx context.Context) {
|
func (sub *Subscriptions) executeChecks(ctx context.Context) {
|
||||||
sub.mutex.RLock()
|
sub.mutex.RLock()
|
||||||
defer sub.mutex.RUnlock()
|
|
||||||
|
|
||||||
// Only allow 8 concurrent requests
|
// Only allow 8 concurrent requests
|
||||||
// TODO: Make configurable instead of hardcoded
|
// TODO: Make configurable instead of hardcoded
|
||||||
workerCount := 8
|
workerCount := 8
|
||||||
workerChan := make(chan workerData, workerCount)
|
workerChan := make(chan workerData, workerCount)
|
||||||
wg := &sync.WaitGroup{}
|
responseChan := make(chan *workerResponseData, workerCount)
|
||||||
|
defer close(responseChan)
|
||||||
for i := 0; i < workerCount; i++ {
|
for i := 0; i < workerCount; i++ {
|
||||||
wg.Add(1)
|
go checkWorker(ctx, workerChan, responseChan)
|
||||||
go checkWorker(ctx, workerChan, wg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
for _, datas := range sub.data {
|
for _, datas := range sub.data {
|
||||||
for i := range datas {
|
for i := range datas {
|
||||||
workerChan <- workerData{
|
workerChan <- workerData{
|
||||||
|
@ -165,12 +173,42 @@ func (sub *Subscriptions) executeChecks(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(workerChan)
|
close(workerChan)
|
||||||
wg.Wait()
|
}()
|
||||||
|
|
||||||
|
responses := make([]*workerResponseData, 0, len(sub.data))
|
||||||
|
|
||||||
|
for _, datas := range sub.data {
|
||||||
|
for range datas {
|
||||||
|
if resp := <-responseChan; resp != nil && resp.unsubscribe != nil {
|
||||||
|
responses = append(responses, resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub.mutex.RUnlock()
|
||||||
|
|
||||||
|
for i := range responses {
|
||||||
|
if responses[i].unsubscribe != nil {
|
||||||
|
// Ignore error since this is optional optimisation
|
||||||
|
deletedSub, err := sub.DeleteSubscription(responses[i].unsubscribe.chatId, responses[i].unsubscribe.messageId)
|
||||||
|
if err == nil && deletedSub != nil {
|
||||||
|
_, _ = sub.tgBot.EditMessageReplyMarkup(ctx, &bot.EditMessageReplyMarkupParams{
|
||||||
|
ChatID: responses[i].unsubscribe.chatId,
|
||||||
|
MessageID: responses[i].unsubscribe.messageId,
|
||||||
|
ReplyMarkup: handlers.GetTrainNumberCommandResponseButtons(deletedSub.TrainNumber, deletedSub.Date, deletedSub.GroupIndex, handlers.TrainInfoResponseButtonExcludeSub),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkWorker(ctx context.Context, workerChan <-chan workerData, wg *sync.WaitGroup) {
|
func checkWorker(ctx context.Context, workerChan <-chan workerData, responseChan chan<- *workerResponseData) {
|
||||||
defer wg.Done()
|
|
||||||
for wData := range workerChan {
|
for wData := range workerChan {
|
||||||
|
func() {
|
||||||
|
var response *workerResponseData
|
||||||
|
defer func() {
|
||||||
|
responseChan <- response
|
||||||
|
}()
|
||||||
data := wData.data
|
data := wData.data
|
||||||
log.Printf("DEBUG: Timer tick, update for chat %d, train %s, date %s, group %d", data.ChatId, data.TrainNumber, data.Date.Format("2006-01-02"), data.GroupIndex)
|
log.Printf("DEBUG: Timer tick, update for chat %d, train %s, date %s, group %d", data.ChatId, data.TrainNumber, data.Date.Format("2006-01-02"), data.GroupIndex)
|
||||||
|
|
||||||
|
@ -179,6 +217,14 @@ func checkWorker(ctx context.Context, workerChan <-chan workerData, wg *sync.Wai
|
||||||
if !ok || resp == nil || resp.Message == nil {
|
if !ok || resp == nil || resp.Message == nil {
|
||||||
// Silently discard update errors
|
// Silently discard update errors
|
||||||
log.Printf("DEBUG: Error when updating chat %d, train %s, date %s, group %d", data.ChatId, data.TrainNumber, data.Date.Format("2006-01-02"), data.GroupIndex)
|
log.Printf("DEBUG: Error when updating chat %d, train %s, date %s, group %d", data.ChatId, data.TrainNumber, data.Date.Format("2006-01-02"), data.GroupIndex)
|
||||||
|
if resp != nil && resp.ShouldUnsubscribe {
|
||||||
|
response = &workerResponseData{
|
||||||
|
unsubscribe: &unsubscribe{
|
||||||
|
chatId: data.ChatId,
|
||||||
|
messageId: data.MessageId,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,5 +237,14 @@ func checkWorker(ctx context.Context, workerChan <-chan workerData, wg *sync.Wai
|
||||||
DisableWebPagePreview: resp.Message.DisableWebPagePreview,
|
DisableWebPagePreview: resp.Message.DisableWebPagePreview,
|
||||||
ReplyMarkup: resp.Message.ReplyMarkup,
|
ReplyMarkup: resp.Message.ReplyMarkup,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
response = &workerResponseData{}
|
||||||
|
if resp.ShouldUnsubscribe {
|
||||||
|
response.unsubscribe = &unsubscribe{
|
||||||
|
chatId: data.ChatId,
|
||||||
|
messageId: data.MessageId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue