-
Notifications
You must be signed in to change notification settings - Fork 4
/
ask.go
86 lines (69 loc) · 2.18 KB
/
ask.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package tgo
import (
"context"
"fmt"
"time"
)
// GetChatAndSenderID extracts and returns the chat ID and sender ID from a given message.
func GetChatAndSenderID(msg *Message) (chatID, senderID int64) {
chatID = msg.Chat.Id
if msg.From != nil {
senderID = msg.From.Id
} else if msg.SenderChat != nil {
senderID = msg.SenderChat.Id
} else {
senderID = msg.Chat.Id
}
return chatID, senderID
}
// getAskUID returns a unique identifier for the ask operation based on the chat ID and sender ID.
func getAskUID(chatID, senderID int64) string {
return fmt.Sprintf("ask:%d:%d", chatID, senderID)
}
// waitForAnswer waits for an answer from the given UID within the specified timeout duration.
// It returns the received answer message or an error if the timeout is exceeded.
func (bot *Bot) waitForAnswer(uid string, timeout time.Duration) (*Message, error) {
waiter := make(chan *Message, 1)
bot.askMut.Lock()
bot.asks[uid] = waiter
bot.askMut.Unlock()
defer func() {
bot.askMut.Lock()
delete(bot.asks, uid)
bot.askMut.Unlock()
close(waiter)
}()
aCtx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
select {
case answer := <-waiter:
return answer, nil
case <-aCtx.Done():
return nil, aCtx.Err()
}
}
// sendAnswerIfAsked sends the message into the asks channel if it was a response to an ask.
// It returns true if the message was the response to an ask or false otherwise.
func (bot *Bot) sendAnswerIfAsked(msg *Message) (sent bool) {
bot.askMut.RLock()
receiver, ok := bot.asks[getAskUID(GetChatAndSenderID(msg))]
bot.askMut.RUnlock()
if ok {
receiver <- msg
return true
}
return false
}
// Ask sends a question message to the specified chat and waits for an answer within the given timeout duration.
// It returns the question message, the received answer message, and any error that occurred.
func (bot *Bot) Ask(chatId, userId int64, msg Sendable, timeout time.Duration) (question, answer *Message, err error) {
if msg.GetChatID() == nil {
msg.SetChatID(chatId)
}
question, err = bot.Send(msg)
if err != nil {
return nil, nil, err
}
answer, err = bot.waitForAnswer(getAskUID(chatId, userId), timeout)
return question, answer, err
}