warbot.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // package warbot -- бот для игры в wartank
  2. package warbot
  3. import (
  4. "context"
  5. "fmt"
  6. "log"
  7. "strings"
  8. "time"
  9. "wartank/pkg/alias"
  10. "wartank/pkg/components/kernel/logger"
  11. "wartank/pkg/components/safe_bool"
  12. "wartank/pkg/types"
  13. "wartank/server/serv_bots/warbot/angar"
  14. "wartank/server/serv_bots/warbot/stat_tank"
  15. "wartank/server/serv_bots/warbot/warbot_config"
  16. "wartank/server/serv_bots/warbot/warbot_net"
  17. )
  18. // ВарБот -- бот для игры в вартанк
  19. type ВарБот struct {
  20. сервер types.ИСервер
  21. store types.ИХранилище
  22. стата types.ИТанкСтат
  23. errFinal error // Финальная ошибка работы, если была
  24. ангар types.ИАнгар
  25. сеть types.ИБотСеть
  26. еслиРаботает *safe_bool.БезопБул
  27. еслиАвтозапуск *safe_bool.БезопБул
  28. конфиг *warbot_config.ВарБотКонфиг // Конфиг бота для хранения в базе
  29. кнт context.Context // Контекст бота
  30. фтОтмена func() // Функция отменя контекста бота
  31. }
  32. // ЗагрузитьВарБот -- загружает бота из базы
  33. func ЗагрузитьВарБот(сервер types.ИСервер, номер alias.БотНомер) *ВарБот {
  34. лог := logger.НовЛоггер("ВарБот")
  35. лог.Инфо("ЗагрузитьВарБот()\n")
  36. лог.Паника(сервер == nil, "ЗагрузитьВарБот(): ИСервер ==nil")
  37. лог.Паника(номер == 0, "ЗагрузитьВарБот(): номер пустой")
  38. стрНомер := fmt.Sprint(номер)
  39. log.Printf("ЗагрузитьВарБот(): номер=%q\n", стрНомер)
  40. store := сервер.Хранилище()
  41. binData, err := store.Получ("/bots/" + стрНомер)
  42. if err != nil {
  43. if !strings.Contains(err.Error(), "not found") {
  44. лог.Паника(true, "ЗагрузитьВарБот(): in load bot '%v' from store, err=\n\t%v\n", номер, err)
  45. }
  46. лог.Паника(err != nil, "ЗагрузитьВарБот(): in load bot '%v' from store, err=\n\t%v\n", номер, err)
  47. }
  48. конфиг := &warbot_config.ВарБотКонфиг{}
  49. конфиг.Unmarshal(binData)
  50. сам, err := создатьЯдроВарБот(сервер, конфиг)
  51. лог.Паника(err!=nil, "ЗагрузитьВарБот(): in make core for bot '%v', err=\n\t%v\n", номер, err)
  52. go сам.рестарт()
  53. _ = types.ИБот(сам)
  54. return сам
  55. }
  56. // Каждые два часа перезапускает себя
  57. func (сам *ВарБот) рестарт() {
  58. time.Sleep(time.Hour * 2)
  59. сам.сервер.Отменить()
  60. log.Printf("ВарБот.рестарт(): бот %q перезагружен\n", сам.конфиг.Логин_)
  61. }
  62. // НовВарБот -- возвращает новый WarBot
  63. func НовВарБот(сервер types.ИСервер, номер alias.БотНомер, логин, пароль string, еслиАвто bool) (types.ИБот, error) {
  64. { // Предусловия
  65. if сервер == nil {
  66. return nil, fmt.Errorf("НовВарБот(): IApp is nil")
  67. }
  68. if логин == "" {
  69. return nil, fmt.Errorf("НовВарБот(): login is empty")
  70. }
  71. if пароль == "" {
  72. return nil, fmt.Errorf("НовВарБот(): pass is empty")
  73. }
  74. }
  75. log.Printf("НовВарБот(): name=%q\n", логин)
  76. config := &warbot_config.ВарБотКонфиг{
  77. ЕслиАвтозапуск_: еслиАвто,
  78. Логин_: логин,
  79. Пароль_: пароль,
  80. Номер_: номер,
  81. }
  82. сам, err := создатьЯдроВарБот(сервер, config)
  83. if err != nil {
  84. return nil, fmt.Errorf("НовВарБот(): in make core bot %q, err=\n\t%w", логин, err)
  85. }
  86. if err := сам.сохр(); err != nil {
  87. return nil, fmt.Errorf("НовВарБот(): in self save to store, err=\n\t%w", err)
  88. }
  89. return сам, nil
  90. }
  91. // Создаёт ядро бота
  92. func создатьЯдроВарБот(серв types.ИСервер, конфиг *warbot_config.ВарБотКонфиг) (*ВарБот, error) {
  93. { // Предусловия
  94. if серв == nil {
  95. return nil, fmt.Errorf("NewWarBot(): IServer==nil")
  96. }
  97. if конфиг == nil {
  98. return nil, fmt.Errorf("NewWarBot(): WarBotConfig==nil")
  99. }
  100. }
  101. ctx, fnCancel := context.WithCancel(серв.Контекст())
  102. сам := &ВарБот{
  103. сервер: серв,
  104. store: серв.Хранилище(),
  105. стата: stat_tank.НовТанкСтат(),
  106. еслиРаботает: safe_bool.НовБезопБул(),
  107. еслиАвтозапуск: safe_bool.НовБезопБул(),
  108. конфиг: конфиг,
  109. кнт: ctx,
  110. фтОтмена: fnCancel,
  111. }
  112. var err error
  113. // WarBotNet
  114. сам.сеть = warbot_net.НовВарБотСеть(сам)
  115. сам.ангар, err = angar.НовАнгар(сам)
  116. if err != nil {
  117. return nil, fmt.Errorf("NewWarBot(): bot(%q) in make IAngar, err=\n\t%w", сам.Имя(), err)
  118. }
  119. if сам.конфиг.ЕслиАвтозапуск_ {
  120. сам.еслиАвтозапуск.Уст()
  121. сам.Пуск()
  122. }
  123. return сам, nil
  124. }
  125. // Сервер -- возвращает ссылку на объект сервера
  126. func (сам *ВарБот) Сервер() types.ИСервер {
  127. return сам.сервер
  128. }
  129. // ЕслиПуск -- возвращает признак, что бот подключен
  130. func (сам *ВарБот) ЕслиПуск() bool {
  131. return сам.еслиРаботает.Получ()
  132. }
  133. // Номер -- возвращает номер бота
  134. func (сам *ВарБот) Номер() alias.БотНомер {
  135. return сам.конфиг.Номер()
  136. }
  137. // Имя -- возвращает имя бота
  138. func (сам *ВарБот) Имя() string {
  139. return сам.конфиг.Логин()
  140. }
  141. // Пароль -- возвращает пароль бота
  142. func (сам *ВарБот) Пароль() string {
  143. return сам.конфиг.Пароль_
  144. }
  145. // Пуск -- запускает бот в работу
  146. func (сам *ВарБот) Пуск() {
  147. if сам.еслиРаботает.Получ() {
  148. return
  149. }
  150. сам.ангар.Пуск()
  151. сам.еслиРаботает.Уст()
  152. }
  153. // Error -- возвращает финальную ошибку работы, если была
  154. func (сам *ВарБот) Error() error {
  155. return сам.errFinal
  156. }
  157. // Ангар -- возвращает ангар игры
  158. func (сам *ВарБот) Ангар() types.ИАнгар {
  159. return сам.ангар
  160. }
  161. // Стата -- возвращает статистику танка
  162. func (сам *ВарБот) Стата() types.ИТанкСтат {
  163. return сам.стата
  164. }
  165. // Сеть -- возвращает ссылку на свой сетевой клиент
  166. func (сам *ВарБот) Сеть() types.ИБотСеть {
  167. return сам.сеть
  168. }
  169. // АвтоИграЕсли -- возвращает признак автоматического запуска бота
  170. func (сам *ВарБот) АвтоИграЕсли() bool {
  171. return сам.еслиАвтозапуск.Получ()
  172. }
  173. // АвтоИграУст -- устанавливает признак автоматического запуска бота
  174. func (сам *ВарБот) АвтоИграУст() {
  175. log.Printf("WarBot.SetAutoGame()")
  176. сам.еслиАвтозапуск.Уст()
  177. сам.конфиг.ЕслиАвтозапуск_ = true
  178. сам.сохрКонфиг()
  179. }
  180. // АвтоИграСброс -- сбрасывает признак автоматического запуска бота
  181. func (сам *ВарБот) АвтоИграСброс() {
  182. log.Printf("WarBot.ResetAutoGame()")
  183. сам.еслиАвтозапуск.Уст()
  184. сам.конфиг.ЕслиАвтозапуск_ = false
  185. сам.сохрКонфиг()
  186. }
  187. // Сохраняет конфиг бота
  188. func (сам *ВарБот) сохрКонфиг() {
  189. log.Printf("ВарБот.сохрКонфиг()")
  190. strConf := сам.конфиг.Marshall()
  191. err := сам.store.Уст("/bots/"+сам.Имя(), strConf)
  192. if err != nil {
  193. log.Printf("ВарБот.сохрКонфиг(): err=\n\t%v\n", err)
  194. }
  195. }
  196. // Контекст -- возвращает контекст бота
  197. func (сам *ВарБот) Контекст() context.Context {
  198. return сам.кнт
  199. }
  200. // Закончить -- отменяет контекст бота
  201. func (сам *ВарБот) Закончить() {
  202. сам.фтОтмена()
  203. }
  204. // Сохраняет себя в базу
  205. func (сам *ВарБот) сохр() error {
  206. стрНомер := fmt.Sprint(сам.Номер())
  207. err := сам.store.Уст("/bots/"+стрНомер, сам.конфиг.Marshall())
  208. if err != nil {
  209. return fmt.Errorf("WarBot.save(): in self save to store bot(%q), err=\n\t%w", сам.Имя(), err)
  210. }
  211. return nil
  212. }