Browse Source

d01 Добавление операций с бото-фермой

SVI 2 years ago
parent
commit
b160c3d05a

+ 4 - 2
README.md

@@ -25,8 +25,10 @@ sudo apt-get install libasound2-dev
 
 ## Запуск
 
-Бот работает с веб-мордой. После запуска надо зайти на
-[localhost:18050](http://localhost:18050/).
+Бот работает с RPC-мордой. После запуска сервера надо запустить десктоп клиент:
+
+- при работе: [localhost:18050](http://localhost:18050/)
+- при разработке: [localhost:18050](http://localhost:18060/)
 
 ## Цели сборки
 

+ 8 - 0
desktop/bot/bot.go

@@ -0,0 +1,8 @@
+// package bot -- объект бота
+package bot
+
+// Bot -- объект бота
+type Bot struct {
+	Login_ string
+	Pass_  string
+}

+ 24 - 0
desktop/client_serv/client_serv.go

@@ -13,6 +13,8 @@ import (
 type ClientServ struct {
 	client *rpc.Client
 	url    string
+	login  string // Логин на бото-ферму
+	pass   string // Логин на бото-ферму
 }
 
 // NewClientServ -- возвращает новый клиент к бото-серверу
@@ -56,5 +58,27 @@ func (sf *ClientServ) Login(login, pass string) error {
 	if resp.Result != "ok" {
 		return fmt.Errorf("ClientServ.Login(): resp=%q", resp.Result)
 	}
+	sf.login = login
+	sf.pass = pass
+	return nil
+}
+
+// AddBot -- добавляет бота на сервер
+func (sf *ClientServ) AddBot(login, pass string) error {
+	log.Println("ClientServ.AddBot()")
+	req := &serv_rpc.AddBotReq{
+		Login:    sf.login,
+		Pass:     sf.pass,
+		BotLogin: login,
+		BotPass:  pass,
+	}
+	resp := &serv_rpc.AddBotResp{}
+	err := sf.client.Call("ServRpc.AddBot", req, resp)
+	if err != nil {
+		return fmt.Errorf("ClientServ.AddBot(): err=\n\t%w", err)
+	}
+	if resp.Result != "ok" {
+		return fmt.Errorf("ClientServ.AddBot(): resp=%q", resp.Result)
+	}
 	return nil
 }

+ 47 - 0
desktop/config/config.go

@@ -0,0 +1,47 @@
+// package config -- конфигурация для клиента
+package config
+
+import (
+	"encoding/json"
+	"log"
+	"os"
+	"wartank/desktop/bot"
+)
+
+// Config -- конфигурация для клиента
+type Config struct {
+	Host_    string              `json:"host"`      // Хост
+	Login_   string              `json:"login"`     // Логин
+	Pass_    string              `json:"password"`  // Пароль
+	DictBot_ map[string]*bot.Bot `json:"list_bots"` // Список ботов
+}
+
+// NewConfig -- возвращает новый конфиг
+func NewConfig() *Config {
+	sf := &Config{
+		DictBot_: map[string]*bot.Bot{},
+	}
+	sf.load()
+	return sf
+}
+
+// Save -- сохраняет конфиг по требованию
+func (sf *Config) Save() {
+	binData, _ := json.MarshalIndent(sf, "", "\t")
+	err := os.WriteFile("./config.json", binData, 0600)
+	if err != nil {
+		log.Printf("Config.Save(): err=%v", err)
+	}
+}
+
+// Загружает конфиг при старте
+func (sf *Config) load() {
+	binData, err := os.ReadFile("./config.json")
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(binData, sf)
+	if err != nil {
+		return
+	}
+}

+ 83 - 61
desktop/desktop.go

@@ -3,12 +3,18 @@ package desktop
 
 import (
 	"fmt"
+	"log"
+	"os"
 	"time"
 
 	"github.com/charmbracelet/bubbles/textinput"
 	tea "github.com/charmbracelet/bubbletea"
 
+	"wartank/desktop/bot"
 	"wartank/desktop/client_serv"
+	"wartank/desktop/config"
+	"wartank/desktop/win_bots_add_login"
+	"wartank/desktop/win_bots_add_pass"
 	"wartank/desktop/win_bots_menu"
 	"wartank/desktop/win_config"
 	"wartank/desktop/win_config_server"
@@ -17,6 +23,7 @@ import (
 	"wartank/desktop/win_config_server_pass_input"
 	"wartank/desktop/win_default"
 	"wartank/desktop/win_server_connect"
+	"wartank/desktop/win_server_login"
 	"wartank/pkg/alias"
 	"wartank/pkg/cons"
 	"wartank/pkg/types"
@@ -24,26 +31,26 @@ import (
 
 // Desktop -- консольный клиент для вар-танка
 type Desktop struct {
-	TeaModel
-	winName     alias.AWinName                    // Режим показа на экране
-	p           *tea.Program                      // Объект приложения
-	client      *client_serv.ClientServ           // Клиент подключния к бото-серверу
-	isConnect   bool                              // Признак подключения к бот-серверу
-	isLogin     bool                              // Признак логина на сервер
-	isMakeAdmin bool                              // Признак создания админа
-	dictWin     map[alias.AWinName]types.ITermWin // Список окон показа
+	conf       *config.Config
+	winName    alias.AWinName                    // Режим показа на экране
+	p          *tea.Program                      // Объект приложения
+	client     *client_serv.ClientServ           // Клиент подключния к бото-серверу
+	isConnect  bool                              // Признак подключения к бот-серверу
+	isLogin    bool                              // Признак логина на сервер
+	dictWin    map[alias.AWinName]types.ITermWin // Список окон показа
+	botCurrent *bot.Bot
 }
 
-var desk *Desktop
+// var desk *Desktop
 
 func NewDesktop() (*Desktop, error) {
 	sf := &Desktop{
-		client:  client_serv.NewClientServ(),
-		dictWin: make(map[alias.AWinName]types.ITermWin),
+		client:     client_serv.NewClientServ(),
+		dictWin:    make(map[alias.AWinName]types.ITermWin),
+		conf:       config.NewConfig(),
+		botCurrent: &bot.Bot{},
 	}
-	sf.TeaModel = NewModel()
 	sf.p = tea.NewProgram(sf, tea.WithAltScreen(), tea.WithANSICompressor())
-	desk = sf
 	{ // Создание окон
 		{ // WinDefault
 			winDefault, err := win_default.NewWinDefault(sf)
@@ -94,6 +101,13 @@ func NewDesktop() (*Desktop, error) {
 			}
 			sf.dictWin[winServerConnect.Name()] = winServerConnect
 		}
+		{ // WinServerLogin
+			winServerLogin, err := win_server_login.NewWinServerLogin(sf)
+			if err != nil {
+				return nil, fmt.Errorf("NewDesktop(): in create WinServerLogin, err=\n\t%w", err)
+			}
+			sf.dictWin[winServerLogin.Name()] = winServerLogin
+		}
 		{ // WinBotsMenu
 			winBotsMenu, err := win_bots_menu.NewWinBotsMenu(sf)
 			if err != nil {
@@ -101,6 +115,20 @@ func NewDesktop() (*Desktop, error) {
 			}
 			sf.dictWin[winBotsMenu.Name()] = winBotsMenu
 		}
+		{ // WinBotsAddLogin
+			winBotsAddLogin, err := win_bots_add_login.NewWinBotsAddLogin(sf)
+			if err != nil {
+				return nil, fmt.Errorf("NewDesktop(): in create WinBotsAddLogin, err=\n\t%w", err)
+			}
+			sf.dictWin[winBotsAddLogin.Name()] = winBotsAddLogin
+		}
+		{ // WinBotsAddPass
+			winBotsAddPass, err := win_bots_add_pass.NewWinBotsAddPass(sf)
+			if err != nil {
+				return nil, fmt.Errorf("NewDesktop(): in create WinBotsAddPass, err=\n\t%w", err)
+			}
+			sf.dictWin[winBotsAddPass.Name()] = winBotsAddPass
+		}
 	}
 	sf.winName = cons.WinDefault
 	go sf.tick()
@@ -112,26 +140,6 @@ func (sf *Desktop) SetWin(winName alias.AWinName) {
 	sf.winName = winName
 }
 
-type TeaModel struct {
-	textInput textinput.Model
-	host      string // Имя хоста сервера (с портом)
-	login     string // Логин для сервера
-	pass      string // Пароль для сервера
-}
-
-func NewModel() TeaModel {
-	ti := textinput.New()
-	ti.Placeholder = "localhost"
-	ti.Focus()
-	ti.CharLimit = 156
-	ti.Width = 20
-
-	m := TeaModel{
-		textInput: ti,
-	}
-	return m
-}
-
 func (sf *Desktop) tick() {
 	for {
 		time.Sleep(time.Second * 1)
@@ -166,35 +174,24 @@ func (sf *Desktop) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 			return sf, tea.Quit
 		}
 	}
-	mod_, cmd_ := sf.dictWin[sf.winName].Update(msg)
+	mod_, _ := sf.dictWin[sf.winName].Update(msg)
 	if mod_ != nil {
-		return mod_, cmd_
+		return sf, nil
 	}
-	/*
-		 case ModeShowMenuBot:
-		 	// Может клавиша нажата
-		 	switch msg := msg.(type) {
-			case tea.KeyMsg:
-				switch msg.String() { // Да, нажато, а что именно?
-				case "esc": // Нажатие "esc" прекращает показ меню
-					desk.winName = ModeConfig
-				}
-		 	}
-		// Возвращает обновлённую модель дляe Bubble Tea runtime для обработки.
-		//Здесь команду возвращать надо.
-	*/
-	return desk, cmd
+	return sf, cmd
 }
 
 func (sf *Desktop) View() string {
+	_s := fmt.Sprintf("Desktop.View(): winName=%q\n", sf.winName)
+	os.WriteFile("./out.log", []byte(_s), 0600)
 	s := time.Now().Local().Format("[ WarTank ] = 2006-01-02 15:04:05.000")
-	s += fmt.Sprintf("\tХост=%q\tЛогин=%q\tПароль=%q\tПодключено=%v\tЛогин=%v\tЕстьАдмин=%v\n\n", desk.host, desk.login, desk.pass, desk.isConnect, desk.isLogin, desk.isMakeAdmin)
-	s += desk.dictWin[desk.winName].View()
-	/*
-		case ModeShowMenuBot: // Меню бото-фермы
-			s += desk.winMenuBotoFerma()
-		}
-	*/
+	s += fmt.Sprintf("\tХост=%q\tЛогин=%q\tПароль=%q\tПодключено=%v\tЛогин=%v\n\n",
+		sf.conf.Host_,
+		sf.conf.Login_,
+		sf.conf.Pass_,
+		sf.isConnect,
+		sf.isLogin)
+	s += _s + sf.dictWin[sf.winName].View()
 	return s
 }
 
@@ -210,22 +207,25 @@ func (sf *Desktop) IsConnect() bool {
 
 // SetHost -- устанавливает имя хоста бото-фермы
 func (sf *Desktop) SetHost(hostName string) {
-	sf.host = hostName
+	sf.conf.Host_ = hostName
+	sf.conf.Save()
 }
 
 // SetLogin -- устанавливает логин бото-фермы
 func (sf *Desktop) SetLogin(login string) {
-	sf.login = login
+	sf.conf.Login_ = login
+	sf.conf.Save()
 }
 
 // SetPass -- устанавливает пароль бото-фермы
 func (sf *Desktop) SetPass(password string) {
-	sf.pass = password
+	sf.conf.Pass_ = password
+	sf.conf.Save()
 }
 
 // Connect -- подключает клиент к бото-ферме
 func (sf *Desktop) Connect() error {
-	err := sf.client.Connect(sf.host)
+	err := sf.client.Connect(sf.conf.Host_)
 	sf.isConnect = false
 	if err != nil {
 		return fmt.Errorf("Desktop.Connect(): err=\n\t%v", err)
@@ -236,7 +236,7 @@ func (sf *Desktop) Connect() error {
 
 // MakeLogin -- выполняет вход на бото-ферму
 func (sf *Desktop) MakeLogin() error {
-	err := sf.client.Login(sf.login, sf.pass)
+	err := sf.client.Login(sf.conf.Login_, sf.conf.Pass_)
 	sf.isLogin = false
 	if err != nil {
 		return fmt.Errorf("Desktop.MakeLogin(): in login to server, err=\n\t%v", err)
@@ -244,3 +244,25 @@ func (sf *Desktop) MakeLogin() error {
 	sf.isLogin = true
 	return nil
 }
+
+// SetBotLogin -- устанавливает логин текущего бота
+func (sf *Desktop) SetBotLogin(login string) {
+	sf.botCurrent.Login_ = login
+}
+
+// SetBotPass -- устанавливает пароль текущего бота
+func (sf *Desktop) SetBotPass(password string) {
+
+	sf.botCurrent.Pass_ = password
+	bot := sf.conf.DictBot_[sf.botCurrent.Login_]
+	if bot != nil {
+		return
+	}
+	err := sf.client.AddBot(sf.botCurrent.Login_, sf.botCurrent.Pass_)
+	if err != nil {
+		log.Printf("Desktop.SetBotPass(): in make request, err=\n\t%v\n", err)
+		return
+	}
+	sf.conf.DictBot_[sf.botCurrent.Login_] = sf.botCurrent
+	sf.conf.Save()
+}

+ 72 - 0
desktop/win_bots_add_login/win_bots_add.go

@@ -0,0 +1,72 @@
+// package win_bots_add_login -- окно добавления логина бота на бото-ферму
+package win_bots_add_login
+
+import (
+	"fmt"
+
+	"github.com/charmbracelet/bubbles/textinput"
+	tea "github.com/charmbracelet/bubbletea"
+
+	"wartank/desktop/win_base"
+	"wartank/pkg/alias"
+	"wartank/pkg/cons"
+	"wartank/pkg/types"
+)
+
+// WinBotsAddLogin -- конфигурация для добавления логина бота на бото-ферму вар-танк
+type WinBotsAddLogin struct {
+	*win_base.WinBase
+	textInput textinput.Model
+}
+
+// NewWinBotsAddLogin -- возвращает новое окно для ввода логина бота при добавлению на бото-ферму вар-танк
+func NewWinBotsAddLogin(desk types.IDesktop) (*WinBotsAddLogin, error) {
+	winBase, err := win_base.NewWinBase(desk, cons.WinBotsAddLogin)
+	if err != nil {
+		return nil, fmt.Errorf("NewWinBotsAdd(): in create WinBase, err=\n\t%w", err)
+	}
+	sf := &WinBotsAddLogin{
+		WinBase:   winBase,
+		textInput: textinput.New(),
+	}
+	sf.textInput.Placeholder = "wartank"
+	sf.textInput.Focus()
+	sf.textInput.Width = 30
+	_ = tea.Model(sf)
+	return sf, nil
+}
+
+// Init -- настраивает окно для бабл-теа
+func (sf *WinBotsAddLogin) Init() tea.Cmd {
+	return textinput.Blink
+}
+
+// Update -- обрабатывает команду цикла
+func (sf *WinBotsAddLogin) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	winName := alias.AWinName("")
+	switch msg := msg.(type) {
+	// Может клавиша нажата
+	case tea.KeyMsg:
+		switch msg.String() { // Да, нажато, а что именно?
+		case "esc": // Вернуться на шаг назад
+			winName = cons.WinBotsMenu
+		case "enter": // Нажатие "enter" вводит фактическое значение
+			sf.Desk().SetBotLogin(sf.textInput.Value())
+			winName = cons.WinBotsAddPass
+		default:
+			sf.textInput, _ = sf.textInput.Update(msg)
+		}
+	}
+	if winName != "" {
+		sf.Desk().SetWin(winName)
+	}
+	return nil, nil
+}
+
+// View -- перерисовывание окна по требованию
+func (sf *WinBotsAddLogin) View() string {
+	s := "=Добавление логина бота на бото-ферму вар-танк=\n\n"
+	s += fmt.Sprintf(">%v\n", sf.textInput.View())
+	s += "\n\n[ctrl+q]-выход [esc]-назад\n"
+	return s
+}

+ 72 - 0
desktop/win_bots_add_pass/win_bots_add.go

@@ -0,0 +1,72 @@
+// package win_bots_add_pass -- окно добавления пароля бота на бото-ферму
+package win_bots_add_pass
+
+import (
+	"fmt"
+
+	"github.com/charmbracelet/bubbles/textinput"
+	tea "github.com/charmbracelet/bubbletea"
+
+	"wartank/desktop/win_base"
+	"wartank/pkg/alias"
+	"wartank/pkg/cons"
+	"wartank/pkg/types"
+)
+
+// WinBotsAddPass -- конфигурация для добавления пароля бота на бото-ферму вар-танк
+type WinBotsAddPass struct {
+	*win_base.WinBase
+	textInput textinput.Model
+}
+
+// NewWinBotsAddPass -- возвращает новое окно для ввода пароля бота при добавлению на бото-ферму вар-танк
+func NewWinBotsAddPass(desk types.IDesktop) (*WinBotsAddPass, error) {
+	winBase, err := win_base.NewWinBase(desk, cons.WinBotsAddPass)
+	if err != nil {
+		return nil, fmt.Errorf("NewWinBotsAddPass(): in create WinBase, err=\n\t%w", err)
+	}
+	sf := &WinBotsAddPass{
+		WinBase:   winBase,
+		textInput: textinput.New(),
+	}
+	sf.textInput.Placeholder = "wartank"
+	sf.textInput.Focus()
+	sf.textInput.Width = 30
+	_ = tea.Model(sf)
+	return sf, nil
+}
+
+// Init -- настраивает окно для бабл-теа
+func (sf *WinBotsAddPass) Init() tea.Cmd {
+	return textinput.Blink
+}
+
+// Update -- обрабатывает команду цикла
+func (sf *WinBotsAddPass) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	winName := alias.AWinName("")
+	switch msg := msg.(type) {
+	// Может клавиша нажата
+	case tea.KeyMsg:
+		switch msg.String() { // Да, нажато, а что именно?
+		case "esc": // Вернуться на шаг назад
+			winName = cons.WinBotsMenu
+		case "enter": // Нажатие "enter" вводит фактическое значение
+			sf.Desk().SetBotPass(sf.textInput.Value())
+			winName = cons.WinBotsMenu
+		default:
+			sf.textInput, _ = sf.textInput.Update(msg)
+		}
+	}
+	if winName != "" {
+		sf.Desk().SetWin(winName)
+	}
+	return nil, nil
+}
+
+// View -- перерисовывание окна по требованию
+func (sf *WinBotsAddPass) View() string {
+	s := "=Добавление пароля бота на бото-ферму вар-танк=\n\n"
+	s += fmt.Sprintf(">%v\n", sf.textInput.View())
+	s += "\n\n[ctrl+q]-выход [esc]-назад\n"
+	return s
+}

+ 72 - 0
desktop/win_bots_list/win_bot_list.go

@@ -0,0 +1,72 @@
+// package win_bots_list -- окно списка ботов на бото-ферме
+package win_bots_list
+
+import (
+	"fmt"
+
+	"github.com/charmbracelet/bubbles/textinput"
+	tea "github.com/charmbracelet/bubbletea"
+
+	"wartank/desktop/win_base"
+	"wartank/pkg/alias"
+	"wartank/pkg/cons"
+	"wartank/pkg/types"
+)
+
+// WinBotsList -- конфигурация для добавления пароля бота на бото-ферму вар-танк
+type WinBotsList struct {
+	*win_base.WinBase
+	textInput textinput.Model
+}
+
+// NewWinBotsAddPass -- возвращает новое окно для ввода пароля бота при добавлению на бото-ферму вар-танк
+func NewWinBotsAddPass(desk types.IDesktop) (*WinBotsList, error) {
+	winBase, err := win_base.NewWinBase(desk, cons.WinBotsAddPass)
+	if err != nil {
+		return nil, fmt.Errorf("NewWinBotsAddPass(): in create WinBase, err=\n\t%w", err)
+	}
+	sf := &WinBotsList{
+		WinBase:   winBase,
+		textInput: textinput.New(),
+	}
+	sf.textInput.Placeholder = "wartank"
+	sf.textInput.Focus()
+	sf.textInput.Width = 30
+	_ = tea.Model(sf)
+	return sf, nil
+}
+
+// Init -- настраивает окно для бабл-теа
+func (sf *WinBotsList) Init() tea.Cmd {
+	return textinput.Blink
+}
+
+// Update -- обрабатывает команду цикла
+func (sf *WinBotsList) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	winName := alias.AWinName("")
+	switch msg := msg.(type) {
+	// Может клавиша нажата
+	case tea.KeyMsg:
+		switch msg.String() { // Да, нажато, а что именно?
+		case "esc": // Вернуться на шаг назад
+			winName = cons.WinBotsMenu
+		case "enter": // Нажатие "enter" вводит фактическое значение
+			sf.Desk().SetBotPass(sf.textInput.Value())
+			winName = cons.WinBotsMenu
+		default:
+			sf.textInput, _ = sf.textInput.Update(msg)
+		}
+	}
+	if winName != "" {
+		sf.Desk().SetWin(winName)
+	}
+	return nil, nil
+}
+
+// View -- перерисовывание окна по требованию
+func (sf *WinBotsList) View() string {
+	s := "=Добавление пароля бота на бото-ферму вар-танк=\n\n"
+	s += fmt.Sprintf(">%v\n", sf.textInput.View())
+	s += "\n\n[ctrl+q]-выход [esc]-назад\n"
+	return s
+}

+ 1 - 1
desktop/win_bots_menu/win_bot_menu.go → desktop/win_bots_menu/win_bots_menu.go

@@ -40,7 +40,7 @@ func (sf *WinBotsMenu) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 		case "esc": // Вернуться на шаг назад
 			winName = cons.WinDefault
 		case "1": // Выбор один
-			winName = cons.WinConfig
+			winName = cons.WinBotsAddLogin
 		}
 	}
 	if winName != "" {

+ 1 - 1
desktop/win_server_connect/win_server_connect.go

@@ -44,7 +44,7 @@ func (sf *WinServerConnect) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	case tea.KeyMsg:
 		switch msg.String() { // Да, нажато, а что именно?
 		case "esc": // Нажатие "esc" прекращает подключение к серверу
-			winName = cons.WinConfigServer
+			winName = cons.WinConfig
 		}
 	}
 	if winName != "" {

+ 9 - 4
pkg/cons/cons.go

@@ -20,13 +20,18 @@ const (
 )
 
 const (
-	WinDefault                alias.AWinName = "winDefault"
+	WinDefault alias.AWinName = "winDefault"
+
 	WinConfig                 alias.AWinName = "winConfig"                 // Режим конфигурирования
 	WinConfigServer           alias.AWinName = "winConfigServer"           // Режим конфигуррования сервера
 	WinConfigServerHostInput  alias.AWinName = "winConfigServerHostInput"  // Режим ввода хоста сервера
 	WinConfigServerLoginInput alias.AWinName = "winConfigServerLoginInput" // Режим ввода логина на сервер
 	WinConfigServerPassInput  alias.AWinName = "winConfigServerPassInput"  // Режим ввода пароля входа на сервер
-	WinServerConnect          alias.AWinName = "winServerConnect"          // Режим подключения к серверу
-	WinServerLogin            alias.AWinName = "winServerLogin"            // Режим логина на сервер
-	WinBotsMenu               alias.AWinName = "winBotsMenu"               // Режим показа меню бото-фермы                                                // Показать меню ботов
+
+	WinServerConnect alias.AWinName = "winServerConnect" // Режим подключения к серверу
+	WinServerLogin   alias.AWinName = "winServerLogin"   // Режим логина на сервер
+
+	WinBotsMenu     alias.AWinName = "winBotsMenu"     // Режим показа меню бото-фермы
+	WinBotsAddLogin alias.AWinName = "winBotsAddLogin" // Добавление логина бота на бото-ферму
+	WinBotsAddPass  alias.AWinName = "winBotsAddPass"  // Добавление пароля бота на бото-ферму
 )

+ 4 - 0
pkg/types/idesktop.go

@@ -20,4 +20,8 @@ type IDesktop interface {
 	SetHost(host string)
 	// SetPass -- устанавливает пароль для входа на бото-ферму
 	SetPass(password string)
+	// SetBotLogin -- устанавливает логин текущего бота
+	SetBotLogin(login string)
+	// SetBotPass -- устанавливает пароль текущего бота
+	SetBotPass(password string)
 }

+ 87 - 5
server/serv_rpc/serv_rpc.go

@@ -79,15 +79,97 @@ type LoginResp struct {
 // Login -- запросвхода на сервер
 func (sf *ServRpc) Login(req *LoginReq, resp *LoginResp) error {
 	log.Println("ServRpc.Login()")
+	if !sf.checkUser(req.Login, req.Pass) {
+		if err := sf.newUser(req.Login, req.Pass); err != nil {
+			return fmt.Errorf("ServRpc.Login(): in create login(%q/%q), err=\n\t%w", req.Login, req.Pass, err)
+		}
+	}
+	resp.Result = "ok"
+	return nil
+}
+
+// Создаёт нового пользователя
+func (sf *ServRpc) newUser(login, pass string) error {
+	log.Println("ServRpc.newUser()")
+	if login == "" {
+		return fmt.Errorf("ServRpc.newUser(): login is empty")
+	}
+	if pass == "" {
+		return fmt.Errorf("ServRpc.newUser(): pass is empty")
+	}
 	store := sf.serv.Store()
-	binData, err := store.Get("/users/" + req.Login)
+	err := store.Put("/users/"+login, pass)
 	if err != nil {
-		return fmt.Errorf("ServRpc.Login(): bad account")
+		return fmt.Errorf("ServRpc.newUser(): in create user, err=\n\t%w", err)
 	}
-	strPass := string(binData)
-	if req.Pass != strPass {
-		return fmt.Errorf("ServRpc.Login():  bad  account")
+	return nil
+}
+
+// AddBotReq -- запрос добавления бота на сервер
+type AddBotReq struct {
+	Login    string
+	Pass     string
+	BotLogin string
+	BotPass  string
+}
+
+// AddBotResp -- ответ добавления бота на сервер
+type AddBotResp struct {
+	Result string
+}
+
+// AddBot -- добавляет бота на сервер
+func (sf *ServRpc) AddBot(req *AddBotReq, resp *AddBotResp) error {
+	log.Println("ServRpc.AddBot()")
+	if !sf.checkUser(req.Login, req.Pass) {
+		return fmt.Errorf("ServRpc.AddBot(): bad login/pass")
+	}
+	if !sf.checkBot(req.BotLogin, req.BotPass) {
+		if err := sf.newBot(req.BotLogin, req.BotPass); err != nil {
+			return fmt.Errorf("ServRpc.AddBot(): in save bot(%q/%q), err=\n\t%w", req.BotLogin, req.BotPass, err)
+		}
 	}
 	resp.Result = "ok"
 	return nil
 }
+
+// Создаёт нового бота по требованию
+func (sf *ServRpc) newBot(login, pass string) error {
+	log.Println("ServRpc.newBot()")
+	if login == "" {
+		return fmt.Errorf("ServRpc.newBot(): login is empty")
+	}
+	if pass == "" {
+		return fmt.Errorf("ServRpc.newBot(): pass is empty")
+	}
+	store := sf.serv.Store()
+	err := store.Put("/bots/"+login, pass)
+	if err != nil {
+		return fmt.Errorf("ServRpc.newBot(): in create bot, err=\n\t%w", err)
+	}
+	return nil
+}
+
+// Проверяет наличие бота в базе
+func (sf *ServRpc) checkBot(login, pass string) bool {
+	log.Println("ServRpc.checkBot()")
+	store := sf.serv.Store()
+	binData, err := store.Get("/bots/" + login)
+	if err != nil { // Нет такого логина бота
+		return false
+	}
+	strPass := string(binData)
+	return pass == strPass
+}
+
+// Проверяет пользователя по логину/паролю
+func (sf *ServRpc) checkUser(login, pass string) bool {
+	log.Println("ServRpc.checkUser()")
+	store := sf.serv.Store()
+	binData, err := store.Get("/users/" + login)
+	if err != nil { // Нет такого логина
+		return false
+	}
+	strPass := string(binData)
+	return pass == strPass
+}