The new logbot, not committed from the wrong terminal window this time.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
3.0 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. package bot
  2. import (
  3. "context"
  4. "log"
  5. "time"
  6. "git.aiterp.net/gisle/irc"
  7. "git.aiterp.net/rpdata/logbot3/internal/models"
  8. "git.aiterp.net/rpdata/logbot3/internal/models/channels"
  9. )
  10. var botKey = "git.aiterp.net/rpdata/logbot.Bot.key"
  11. // The Bot is the IRC client.
  12. type Bot struct {
  13. client *irc.Client
  14. ctx context.Context
  15. ctxCancel context.CancelFunc
  16. loopCtx context.Context
  17. loopCancel context.CancelFunc
  18. }
  19. // New creates a new Bot.
  20. func New(ctx context.Context, nick string, alternatives []string, user string, realName string) *Bot {
  21. client := irc.New(ctx, irc.Config{
  22. Nick: nick,
  23. User: user,
  24. RealName: realName,
  25. Alternatives: alternatives,
  26. SendRate: 2,
  27. SkipSSLVerification: false,
  28. })
  29. bot := &Bot{
  30. client: client,
  31. }
  32. client.SetValue(botKey, bot)
  33. return bot
  34. }
  35. // Connect connects the bot to the IRC server. This will disconnect already
  36. // established connections.
  37. func (bot *Bot) Connect(server string, ssl bool, maxRetries int) (err error) {
  38. if bot.ctxCancel != nil {
  39. bot.ctxCancel()
  40. }
  41. bot.ctx, bot.ctxCancel = context.WithCancel(bot.client.Context())
  42. retries := 0
  43. for maxRetries == 0 || retries < maxRetries {
  44. err = bot.client.Connect(server, ssl)
  45. if err != nil {
  46. log.Println("Connect failed:", err.Error())
  47. if maxRetries > 0 && retries < maxRetries {
  48. retries++
  49. log.Printf("Retrying in 5s (Retry %d/%d)", retries, maxRetries)
  50. } else {
  51. log.Println("Retrying in 5s (No retry limit)")
  52. }
  53. time.Sleep(time.Second * 10)
  54. continue
  55. }
  56. return nil
  57. }
  58. return err
  59. }
  60. func (bot *Bot) loop() {
  61. bot.loopCtx, bot.loopCancel = context.WithCancel(bot.ctx)
  62. channelChanges, err := channels.SubscribeLogged(bot.ctx)
  63. if err != nil {
  64. log.Println("Failed to get channel changes:", err)
  65. return
  66. }
  67. for {
  68. select {
  69. case channel := <-channelChanges:
  70. {
  71. channels := []models.Channel{channel}
  72. deadline := time.After(time.Second * 1)
  73. buffering := true
  74. for buffering {
  75. select {
  76. case channel := <-channelChanges:
  77. channels = append(channels, channel)
  78. case <-deadline:
  79. buffering = false
  80. }
  81. }
  82. decisions := make(map[string]bool)
  83. for _, channel := range channels {
  84. decisions[channel.Name] = channel.Logged
  85. }
  86. joins := make([]string, 0, len(decisions))
  87. parts := make([]string, 0, len(decisions))
  88. for channelName, logged := range decisions {
  89. if logged {
  90. if bot.client.Channel(channelName) != nil {
  91. continue
  92. }
  93. joins = append(joins, channelName)
  94. } else {
  95. if bot.client.Channel(channelName) == nil {
  96. continue
  97. }
  98. parts = append(parts, channelName)
  99. }
  100. }
  101. if len(joins) > 0 {
  102. bot.client.Join(joins...)
  103. }
  104. if len(parts) > 0 {
  105. bot.client.Part(parts...)
  106. }
  107. }
  108. case <-bot.loopCtx.Done():
  109. {
  110. log.Println("Spinning down bot loop.")
  111. return
  112. }
  113. }
  114. }
  115. }
  116. func (bot *Bot) stopLoop() {
  117. if bot.loopCancel != nil {
  118. bot.loopCancel()
  119. }
  120. }