bot.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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) SetDebug(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 nil, config.Error
  53. }
  54. msg, err := bot.api.Send(config.ToAPI())
  55. if err != nil {
  56. return nil, 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. return bot.Send(
  65. sid,
  66. Messagef(format, v...),
  67. )
  68. }
  69. // Send to the session specified its ID raw chattable from the tgbotapi.
  70. func (bot *Bot) SendRaw(
  71. sid SessionID, v tgbotapi.Chattable,
  72. ) (*Message, error) {
  73. msg, err := bot.api.Send(v)
  74. if err != nil {
  75. return nil, err
  76. }
  77. return &msg, nil
  78. }
  79. // Get session by its ID. Can be used for any scope
  80. // including private, group and channel.
  81. func (bot *Bot) GotSession(
  82. sid SessionID,
  83. ) (*Session, bool) {
  84. session, ok := bot.sessions[sid]
  85. return session, ok
  86. }
  87. func (bot *Bot) SetData(v any) *Bot {
  88. bot.data = v
  89. return bot
  90. }
  91. func (bot *Bot) Data() any {
  92. return bot.data
  93. }
  94. func (b *Bot) SetBehaviour(beh *Behaviour) *Bot {
  95. b.behaviour = beh
  96. b.sessions = make(SessionMap)
  97. return b
  98. }
  99. func (b *Bot) SetSessions(sessions SessionMap) *Bot {
  100. b.sessions = sessions
  101. return b
  102. }
  103. /*func (b *Bot) WithGroupBehaviour(beh *GroupBehaviour) *Bot {
  104. b.groupBehaviour = beh
  105. b.groupSessions = make(GroupSessionMap)
  106. return b
  107. }
  108. func (b *Bot) WithGroupSessions(sessions GroupSessionMap) *Bot {
  109. b.groupSessions = sessions
  110. return b
  111. }*/
  112. func (bot *Bot) DeleteCommands() {
  113. //tgbotapi.NewBotCommandScopeAllPrivateChats(),
  114. cfg := tgbotapi.NewDeleteMyCommands()
  115. bot.api.Request(cfg)
  116. }
  117. // Setting the command on the user side.
  118. func (bot *Bot) SetCommands(
  119. scope tgbotapi.BotCommandScope,
  120. cmdMap CommandMap,
  121. ) error {
  122. // First the private commands.
  123. names := []string{}
  124. for name := range cmdMap {
  125. names = append(names, string(name))
  126. }
  127. sort.Strings(names)
  128. cmds := []Command{}
  129. for _, name := range names {
  130. cmds = append(
  131. cmds,
  132. cmdMap[CommandName(name)],
  133. )
  134. }
  135. botCmds := []tgbotapi.BotCommand{}
  136. for _, cmd := range cmds {
  137. botCmds = append(botCmds, cmd.ToAPI())
  138. }
  139. //tgbotapi.NewBotCommandScopeAllPrivateChats(),
  140. cfg := tgbotapi.NewSetMyCommandsWithScope(
  141. scope,
  142. botCmds...,
  143. )
  144. _, err := bot.api.Request(cfg)
  145. if err != nil {
  146. return err
  147. }
  148. return nil
  149. }
  150. // Run the bot with the Behaviour.
  151. func (bot *Bot) Run() error {
  152. if bot.behaviour == nil {
  153. return errors.New("no behaviour defined")
  154. }
  155. if bot.behaviour != nil && bot.behaviour.Root == nil {
  156. return errors.New("the root widget is not set, cannot run")
  157. }
  158. uc := tgbotapi.NewUpdate(0)
  159. uc.Timeout = 10
  160. updates := bot.api.GetUpdatesChan(uc)
  161. handles := make(map[string] chan Update)
  162. if bot.behaviour != nil {
  163. chn := make(chan Update)
  164. handles["private"] = chn
  165. go bot.handlePrivate(chn)
  166. }
  167. /*if bot.groupBehaviour != nil {
  168. commanders := make(map[CommandName] BotCommander)
  169. for k, v := range bot.groupBehaviour.Commands {
  170. commanders[k] = v
  171. }
  172. bot.SetCommands(
  173. tgbotapi.NewBotCommandScopeAllGroupChats(),
  174. commanders,
  175. )
  176. chn := make(chan *Update)
  177. handles["group"] = chn
  178. handles["supergroup"] = chn
  179. go bot.handleGroup(chn)
  180. }*/
  181. me, _ := bot.API().GetMe()
  182. bot.me = me
  183. for up := range updates {
  184. u := Update{
  185. Update: up,
  186. }
  187. // Sometimes returns nil.
  188. fromChat := u.FromChat()
  189. if fromChat == nil {
  190. continue
  191. }
  192. chn, ok := handles[fromChat.Type]
  193. // Skipping non existent scope.
  194. if !ok {
  195. continue
  196. }
  197. chn <- u
  198. }
  199. return nil
  200. }
  201. // The function handles updates supposed for the private
  202. // chat with the bot.
  203. func (bot *Bot) handlePrivate(updates chan Update) {
  204. var sid SessionID
  205. for u := range updates {
  206. sid = SessionID(u.FromChat().ID)
  207. session, sessionOk := bot.sessions[sid]
  208. if u.Message != nil && !sessionOk {
  209. // Creating session if we have none
  210. // but only on text messages.
  211. session = bot.sessions.Add(bot, sid, PrivateSessionScope)
  212. // Creating the root context
  213. // that takes updates directly from
  214. // the session.
  215. rootContext := Context{
  216. session: session,
  217. update: u,
  218. input: session.updates,
  219. }
  220. go rootContext.serve()
  221. rootContext.input.Send(u)
  222. continue
  223. }
  224. if sessionOk {
  225. session.updates.Send(u)
  226. }
  227. }
  228. }