warbot.go 9.4 KB

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