bot.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. package tg
  2. import (
  3. "errors"
  4. "sort"
  5. tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
  6. )
  7. type Chat = tgbotapi.Chat
  8. type User = tgbotapi.User
  9. // The wrapper around Telegram API.
  10. type Bot struct {
  11. // Custom data value.
  12. data any
  13. api *tgbotapi.BotAPI
  14. me User
  15. // Private bot behaviour.
  16. behaviour *Behaviour
  17. // Group bot behaviour.
  18. //groupBehaviour *GroupBehaviour
  19. // Bot behaviour in channels.
  20. //channelBehaviour *ChannelBehaviour
  21. sessions SessionMap
  22. //groupSessions GroupSessionMap
  23. }
  24. // Return the new bot with empty sessions and behaviour.
  25. func NewBot(token string) (*Bot, error) {
  26. bot, err := tgbotapi.NewBotAPI(token)
  27. if err != nil {
  28. return nil, err
  29. }
  30. return &Bot{
  31. api: bot,
  32. }, nil
  33. }
  34. func (bot *Bot) Debug(debug bool) *Bot {
  35. bot.api.Debug = debug
  36. return bot
  37. }
  38. func (bot *Bot) Api() *tgbotapi.BotAPI {
  39. return bot.api
  40. }
  41. func (bot *Bot) Me() User {
  42. return bot.me
  43. }
  44. // Send the Renderable to the specified session client side.
  45. // Can be used for both group and private sessions because
  46. // SessionId represents both for chat IDs.
  47. func (bot *Bot) Send(
  48. sid SessionId, v Sendable,
  49. ) (Message, error) {
  50. config := v.SendConfig(sid, bot)
  51. if config.Error != nil {
  52. return Message{}, config.Error
  53. }
  54. msg, err := bot.api.Send(config.ToApi())
  55. if err != nil {
  56. return Message{}, err
  57. }
  58. v.SetMessage(msg)
  59. return msg, nil
  60. }
  61. func (bot *Bot) Sendf(
  62. sid SessionId, format string, v ...any,
  63. ) (Message, error){
  64. msg := Messagef(format, v...)
  65. return bot.Send(
  66. sid,
  67. &msg,
  68. )
  69. }
  70. // Send to the session specified its ID raw chattable from the tgbotapi.
  71. func (bot *Bot) SendRaw(
  72. sid SessionId, v tgbotapi.Chattable,
  73. ) (*Message, error) {
  74. msg, err := bot.api.Send(v)
  75. if err != nil {
  76. return nil, err
  77. }
  78. return &msg, nil
  79. }
  80. // Get session by its ID. Can be used for any scope
  81. // including private, group and channel.
  82. func (bot *Bot) GetSession(
  83. sid SessionId,
  84. ) (*Session, bool) {
  85. session, ok := bot.sessions[sid]
  86. return session, ok
  87. }
  88. func (b *Bot) WithBehaviour(beh *Behaviour) *Bot {
  89. b.behaviour = beh
  90. b.sessions = make(SessionMap)
  91. return b
  92. }
  93. func (b *Bot) WithSessions(sessions SessionMap) *Bot {
  94. b.sessions = sessions
  95. return b
  96. }
  97. /*func (b *Bot) WithGroupBehaviour(beh *GroupBehaviour) *Bot {
  98. b.groupBehaviour = beh
  99. b.groupSessions = make(GroupSessionMap)
  100. return b
  101. }
  102. func (b *Bot) WithGroupSessions(sessions GroupSessionMap) *Bot {
  103. b.groupSessions = sessions
  104. return b
  105. }*/
  106. func (bot *Bot) DeleteCommands() {
  107. //tgbotapi.NewBotCommandScopeAllPrivateChats(),
  108. cfg := tgbotapi.NewDeleteMyCommands()
  109. bot.api.Request(cfg)
  110. }
  111. // Setting the command on the user side.
  112. func (bot *Bot) SetCommands(
  113. scope tgbotapi.BotCommandScope,
  114. cmdMap CommandMap,
  115. ) error {
  116. // First the private commands.
  117. names := []string{}
  118. for name := range cmdMap {
  119. names = append(names, string(name))
  120. }
  121. sort.Strings(names)
  122. cmds := []*Command{}
  123. for _, name := range names {
  124. cmds = append(
  125. cmds,
  126. cmdMap[CommandName(name)],
  127. )
  128. }
  129. botCmds := []tgbotapi.BotCommand{}
  130. for _, cmd := range cmds {
  131. botCmds = append(botCmds, cmd.ToApi())
  132. }
  133. //tgbotapi.NewBotCommandScopeAllPrivateChats(),
  134. cfg := tgbotapi.NewSetMyCommandsWithScope(
  135. scope,
  136. botCmds...,
  137. )
  138. _, err := bot.api.Request(cfg)
  139. if err != nil {
  140. return err
  141. }
  142. return nil
  143. }
  144. // Run the bot with the Behaviour.
  145. func (bot *Bot) Run() error {
  146. if bot.behaviour == nil {
  147. return errors.New("no behaviour defined")
  148. }
  149. if bot.behaviour != nil && bot.behaviour.Root == nil {
  150. return errors.New("the root widget is not set, cannot run")
  151. }
  152. uc := tgbotapi.NewUpdate(0)
  153. uc.Timeout = 10
  154. updates := bot.api.GetUpdatesChan(uc)
  155. handles := make(map[string] chan Update)
  156. if bot.behaviour != nil {
  157. chn := make(chan Update)
  158. handles["private"] = chn
  159. go bot.handlePrivate(chn)
  160. }
  161. /*if bot.groupBehaviour != nil {
  162. commanders := make(map[CommandName] BotCommander)
  163. for k, v := range bot.groupBehaviour.Commands {
  164. commanders[k] = v
  165. }
  166. bot.SetCommands(
  167. tgbotapi.NewBotCommandScopeAllGroupChats(),
  168. commanders,
  169. )
  170. chn := make(chan *Update)
  171. handles["group"] = chn
  172. handles["supergroup"] = chn
  173. go bot.handleGroup(chn)
  174. }*/
  175. me, _ := bot.Api.GetMe()
  176. bot.me = me
  177. for up := range updates {
  178. u := Update{
  179. Update: up,
  180. }
  181. // Sometimes returns nil.
  182. fromChat := u.FromChat()
  183. if fromChat == nil {
  184. continue
  185. }
  186. chn, ok := handles[fromChat.Type]
  187. if !ok {
  188. continue
  189. }
  190. chn <- u
  191. }
  192. return nil
  193. }
  194. // The function handles updates supposed for the private
  195. // chat with the bot.
  196. func (bot *Bot) handlePrivate(updates chan Update) {
  197. var sid SessionId
  198. for u := range updates {
  199. sid = SessionId(u.FromChat().ID)
  200. ctx, ctxOk := bot.contexts[sid]
  201. if u.Message != nil && !ctxOk {
  202. session, sessionOk := bot.sessions[sid]
  203. if !sessionOk {
  204. // Creating session if we have none.
  205. session = bot.sessions.Add(sid, PrivateSessionScope)
  206. }
  207. session = bot.sessions[sid]
  208. // Create context on any message
  209. // if we have no one.
  210. ctx = &context{
  211. Bot: bot,
  212. Session: session,
  213. updates: NewUpdateChan(),
  214. }
  215. if !ctxOk {
  216. bot.contexts[sid] = ctx
  217. }
  218. go Context{
  219. session: session,
  220. bot: bot,
  221. Update: u,
  222. input: ctx.updates,
  223. }.serve()
  224. ctx.session.updates.Send(u)
  225. continue
  226. }
  227. if ctxOk {
  228. ctx.updates.Send(u)
  229. }
  230. }
  231. }
  232. /*
  233. func (bot *Bot) handleGroup(updates chan *Update) {
  234. var sid SessionId
  235. chans := make(map[SessionId]chan *Update)
  236. for u := range updates {
  237. sid = SessionId(u.FromChat().ID)
  238. // If no session add new.
  239. if _, ok := bot.groupSessions[sid]; !ok {
  240. bot.groupSessions.Add(sid)
  241. session := bot.groupSessions[sid]
  242. ctx := &groupContext{
  243. Bot: bot,
  244. Session: session,
  245. updates: make(chan *Update),
  246. }
  247. chn := make(chan *Update)
  248. chans[sid] = chn
  249. go ctx.handleUpdateChan(chn)
  250. }
  251. chn := chans[sid]
  252. chn <- u
  253. }
  254. }
  255. */