// package warbot -- бот для игры в wartank package warbot import ( "context" "fmt" "log" "strings" "time" "wartank/pkg/components/safe_bool" "wartank/pkg/types" "wartank/server/serv_bots/warbot/angar" "wartank/server/serv_bots/warbot/tank" "wartank/server/serv_bots/warbot/warbot_config" "wartank/server/serv_bots/warbot/warbot_net" ) // ВарБот -- бот для игры в вартанк type ВарБот struct { сервер types.ИСервер store types.IStore танк *tank.Танк errFinal error // Финальная ошибка работы, если была ангар types.ИАнгар сеть types.ИБотСеть еслиРаботает *safe_bool.БезопБул еслиАвтозапуск *safe_bool.БезопБул конфиг *warbot_config.ВарБотКонфиг // Конфиг бота для хранения в базе кнт context.Context // Контекст бота фтОтмена func() // Функция отменя контекста бота } // ЗагрузитьВарБот -- загружает бота из базы func ЗагрузитьВарБот(сервер types.ИСервер, логин string) (*ВарБот, error) { { // Предусловия if сервер == nil { return nil, fmt.Errorf("ЗагрузитьВарБот(): IApp is nil") } if логин == "" { return nil, fmt.Errorf("ЗагрузитьВарБот(): name is empty") } } log.Printf("ЗагрузитьВарБот(): name=%q\n", логин) store := сервер.Store() strData, err := store.Get("/bots/" + логин) if err != nil { if !strings.Contains(err.Error(), "not found") { return nil, fmt.Errorf("ЗагрузитьВарБот(): in load bot %q from store, err=\n\t%w", логин, err) } return nil, fmt.Errorf("ЗагрузитьВарБот(): bot %q not found in store", логин) } конфиг := &warbot_config.ВарБотКонфиг{} if err = конфиг.Unmarshall(strData); err != nil { return nil, fmt.Errorf("ЗагрузитьВарБот(): in unmarshall WarBotConfig(%q) from store, err=\n\t%w", логин, err) } сам, err := создатьЯдроВарБот(сервер, конфиг) if err != nil { return nil, fmt.Errorf("ЗагрузитьВарБот(): in make core for bot %q, err=\n\t%w", логин, err) } // go сам.рестарт() return сам, nil } // Каждые два часа перезапускает себя func (сам *ВарБот) рестарт() { time.Sleep(time.Hour * 2) сам.Закончить() сам, ош := ЗагрузитьВарБот(сам.сервер, сам.конфиг.Логин_) if ош != nil { panic(fmt.Errorf("ВарБот.рестарт(): при загрузке своего тела, ош=\n\t%w", ош)) } log.Printf("ВарБот.рестарт(): бот %q перезагружен\n", сам.конфиг.Логин_) } // НовВарБот -- возвращает новый WarBot func НовВарБот(сервер types.ИСервер, логин, пароль string, еслиАвто bool) (*ВарБот, error) { { // Предусловия if сервер == nil { return nil, fmt.Errorf("НовВарБот(): IApp is nil") } if логин == "" { return nil, fmt.Errorf("НовВарБот(): login is empty") } if пароль == "" { return nil, fmt.Errorf("НовВарБот(): pass is empty") } } log.Printf("НовВарБот(): name=%q\n", логин) config := &warbot_config.ВарБотКонфиг{ ЕслиАвтозапуск_: еслиАвто, Логин_: логин, Пароль_: пароль, } сам, err := создатьЯдроВарБот(сервер, config) if err != nil { return nil, fmt.Errorf("НовВарБот(): in make core bot %q, err=\n\t%w", логин, err) } if err := сам.сохр(); err != nil { return nil, fmt.Errorf("НовВарБот(): in self save to store, err=\n\t%w", err) } return сам, nil } // Создаёт ядро бота func создатьЯдроВарБот(серв types.ИСервер, конфиг *warbot_config.ВарБотКонфиг) (*ВарБот, error) { { // Предусловия if серв == nil { return nil, fmt.Errorf("NewWarBot(): IServer==nil") } if конфиг == nil { return nil, fmt.Errorf("NewWarBot(): WarBotConfig==nil") } } танк, ош := tank.NewTank() if ош != nil { return nil, fmt.Errorf("NewWarBot(): при создании параметров танка, ош=\n\t%w", ош) } ctx, fnCancel := context.WithCancel(серв.CtxApp()) сам := &ВарБот{ сервер: серв, store: серв.Store(), танк: танк, еслиРаботает: safe_bool.НовБезопБул(), еслиАвтозапуск: safe_bool.НовБезопБул(), конфиг: конфиг, кнт: ctx, фтОтмена: fnCancel, } var err error { // WarBotNet сам.сеть, err = warbot_net.НовВарБотСеть(сам) if err != nil { return nil, fmt.Errorf("NewWarBot(): in make IBotNet, err=\n\t%w", err) } } сам.ангар, err = angar.НовАнгар(сам) if err != nil { return nil, fmt.Errorf("NewWarBot(): bot(%q) in make IAngar, err=\n\t%w", сам.Имя(), err) } if сам.конфиг.ЕслиАвтозапуск_ { сам.еслиАвтозапуск.Уст() сам.Пуск() } return сам, nil } // Сервер -- возвращает ссылку на объект сервера func (сам *ВарБот) Сервер() types.ИСервер { return сам.сервер } // ЕслиПуск -- возвращает признак, что бот подключен func (сам *ВарБот) ЕслиПуск() bool { return сам.еслиРаботает.Получ() } // Имя -- возвращает имя бота func (сам *ВарБот) Имя() string { return сам.конфиг.Логин() } // Пароль -- возвращает пароль бота func (сам *ВарБот) Пароль() string { return сам.конфиг.Пароль_ } // Пуск -- запускает бот в работу func (сам *ВарБот) Пуск() (err error) { if сам.еслиРаботает.Получ() { return nil } if err := сам.ангар.Пуск(); err != nil { return fmt.Errorf("WarBot.Run(): bot(%q) in run angar, err=\n\t%w", сам.Имя(), err) } сам.еслиРаботает.Уст() return nil } // Error -- возвращает финальную ошибку работы, если была func (сам *ВарБот) Error() error { return сам.errFinal } // Ангар -- возвращает ангар игры func (сам *ВарБот) Ангар() types.ИАнгар { return сам.ангар } // Танк -- возвращает объект танка func (сам *ВарБот) Танк() types.ИТанк { return сам.танк } // Сеть -- возвращает ссылку на свой сетевой клиент func (сам *ВарБот) Сеть() types.ИБотСеть { return сам.сеть } // АвтоИграЕсли -- возвращает признак автоматичского запуска бота func (сам *ВарБот) АвтоИграЕсли() bool { return сам.еслиАвтозапуск.Получ() } // АвтоИграУст -- устанавливает признак автоматического запуска бота func (сам *ВарБот) АвтоИграУст() { log.Printf("WarBot.SetAutoGame()") сам.еслиАвтозапуск.Уст() сам.конфиг.ЕслиАвтозапуск_ = true сам.saveConfig() } // АвтоИграСброс -- сбрасывает признак автоматического запуска бота func (сам *ВарБот) АвтоИграСброс() { log.Printf("WarBot.ResetAutoGame()") сам.еслиАвтозапуск.Уст() сам.конфиг.ЕслиАвтозапуск_ = false сам.saveConfig() } // Сохраняет конфиг бота func (сам *ВарБот) saveConfig() { log.Printf("WarBot.saveConfig()") strConf := сам.конфиг.Marshall() err := сам.store.Put("/bots/"+сам.Имя(), strConf) if err != nil { log.Printf("WarBot.saveConfig(): err=\n\t%v\n", err) } } // Кнт -- возвращает контекст бота func (сам *ВарБот) Кнт() context.Context { return сам.кнт } // Закончить -- отменяет контекст бота func (сам *ВарБот) Закончить() { сам.фтОтмена() } // Сохраняет себя в базу func (сам *ВарБот) сохр() error { err := сам.store.Put("/bots/"+сам.Имя(), сам.конфиг.Marshall()) if err != nil { return fmt.Errorf("WarBot.save(): in self save to store bot(%q), err=\n\t%w", сам.Имя(), err) } return nil }