Ver código fonte

d01 Удаление старого клиента

SVI 3 anos atrás
pai
commit
27eba9b5b2

+ 0 - 86
desktop/desktop.go

@@ -1,86 +0,0 @@
-// package desktop -- главный тип локального приложения
-package desktop
-
-import (
-	"fmt"
-	"log"
-
-	"wartank/desktop/dict_bot"
-	"wartank/desktop/root"
-	"wartank/desktop/store_net"
-	"wartank/desktop/web_socket"
-	"wartank/desktop/win_main"
-	"wartank/pkg/components/kernel"
-	"wartank/pkg/types"
-)
-
-// Desktop -- главный тип локального приложения
-type Desktop struct {
-	*kernel.Kernel
-	store   types.IStore
-	winMain *win_main.WinMain
-	ws      types.IWebSocket
-	root    types.IRoot
-	dictBot types.IDictBot
-}
-
-// NewDesktop -- возвращает новый объект настольного приложения
-func NewDesktop() (*Desktop, error) {
-	log.Println("NewDesktop()")
-	kernel, err := kernel.NewKernel()
-	if err != nil {
-		return nil, fmt.Errorf("NewDesktop(): in create IKernel, err=\n\t%w", err)
-	}
-	sf := &Desktop{
-		Kernel: kernel,
-	}
-	sf.ws, err = web_socket.NewWebSocket(sf)
-	if err != nil {
-		return nil, fmt.Errorf("NewDesktop(): in create IWebSocket, err=\n\t%w", err)
-	}
-	sf.store, err = store_net.NewStoreNet(sf)
-	if err != nil {
-		return nil, fmt.Errorf("NewDesktop(): in create IStore, err=\n\t%w", err)
-	}
-	sf.root, err = root.NewRoot(sf)
-	if err != nil {
-		return nil, fmt.Errorf("NewDesktop(): in create IRoot, err=\n\t%w", err)
-	}
-	sf.dictBot, err = dict_bot.NewDictBot(sf)
-	if err != nil {
-		return nil, fmt.Errorf("NewDesktop(): in create IGamers, err=\n\t%w", err)
-	}
-	sf.winMain, err = win_main.NewWinMain(sf)
-	if err != nil {
-		return nil, fmt.Errorf("NewDesktop(): in create WinMain, err=\n\t%w", err)
-	}
-	return sf, nil
-}
-
-// Run -- запускает десктоп в работу
-func (sf *Desktop) Run() error {
-	sf.Slog().Infof("Desktop.Run()\n")
-	sf.winMain.Run()
-	sf.Wg().Wait()
-	return nil
-}
-
-// Store -- возвращает хранилище
-func (sf *Desktop) Store() types.IStore {
-	return sf.store
-}
-
-// Ws -- возвращает веб-сокет
-func (sf *Desktop) Ws() types.IWebSocket {
-	return sf.ws
-}
-
-// Root -- возвращает объект рута
-func (sf *Desktop) Root() types.IRoot {
-	return sf.root
-}
-
-// DictBot -- возвращает объект списка ботов игрока
-func (sf *Desktop) DictBot() types.IDictBot {
-	return sf.dictBot
-}

+ 0 - 27
desktop/dict_bot/bot/bot.go

@@ -1,27 +0,0 @@
-// package bot -- бот для хранения данных
-package bot
-
-import "fmt"
-
-// Bot -- бот для хранения данных
-type Bot struct {
-	name string
-	pass string
-}
-
-// NewBot -- возвращает нового бота
-func NewBot(name, pass string) (*Bot, error) {
-	{ // Предусловия
-		if name == "" {
-			return nil, fmt.Errorf("NewBot(): name is empty")
-		}
-		if pass == "" {
-			return nil, fmt.Errorf("NewBot(): pass is empty")
-		}
-	}
-	sf := &Bot{
-		name: name,
-		pass: pass,
-	}
-	return sf, nil
-}

+ 0 - 165
desktop/dict_bot/dict_bot.go

@@ -1,165 +0,0 @@
-// package dict_bot -- словарь ботов в игре
-package dict_bot
-
-import (
-	"encoding/json"
-	"fmt"
-	"log"
-	"strings"
-
-	"wartank/desktop/dict_bot/bot"
-	"wartank/desktop/dict_bot/win_bot_add"
-	"wartank/desktop/dict_bot/win_bot_view"
-	"wartank/desktop/dict_bot/win_bots"
-	"wartank/pkg/types"
-)
-
-// DictBot -- словарь ботов в игре
-type DictBot struct {
-	desktop types.IDesktop
-	store   types.IStore
-	ws      types.IWebSocket
-	dict    map[string]types.IBot
-	winBots *win_bots.WinBots
-}
-
-// NewDictBot -- возвращает новый словарь ботов
-func NewDictBot(desktop types.IDesktop) (*DictBot, error) {
-	if desktop == nil {
-		return nil, fmt.Errorf("NewDictBot(): IDesktop == nil")
-	}
-	sf := &DictBot{
-		desktop: desktop,
-		store:   desktop.Store(),
-		ws:      desktop.Ws(),
-		dict:    make(map[string]types.IBot),
-	}
-	sf.load()
-	return sf, nil
-}
-
-// Загружает список ботов, к этому моменту логин рута точно прошёл
-func (sf *DictBot) load() {
-	log.Println("DictBot.load()")
-	dictResp, err := sf.ws.Read("/bot/list/load")
-	if err != nil {
-		if strings.Contains(err.Error(), "not found") {
-			return
-		}
-		log.Printf("DictBot.load(): in get bot, err=\n\t%v\n", err)
-		return
-	}
-	strErr := dictResp["err"]
-	if strErr != "" {
-		if strings.Contains(strErr, "not found") { // Это был первый запуск
-			lstBot := make([]string, 0)
-			binList, _ := json.Marshal(&lstBot)
-			dictReq := make(map[string]string)
-			dictReq["binData"] = string(binList)
-			err := sf.ws.Write("/bot/list/save", dictReq)
-			if err != nil {
-				log.Printf("DictBot.load(): in write new list bot, err=\n\t%v\n", strErr)
-			}
-		} else {
-			log.Printf("DictBot.load(): in response, err=\n\t%v\n", strErr)
-		}
-	}
-	log.Printf("DictBot.load(): dictResp=%#v\n", dictResp)
-	strList := dictResp["/bot/list"]
-	lstBot := make([]string, 0)
-	err = json.Unmarshal([]byte(strList), &lstBot)
-	if err != nil {
-		log.Printf("DictBot.load(): in unmarshal list bot, err=\n\t%v\n", err)
-		return
-	}
-	for _, bot := range lstBot {
-		sf.dict[bot] = ""
-	}
-}
-
-// Show -- показывает окно списка ботов
-func (sf *DictBot) Show() {
-	log.Println("DictBot.Show()")
-	dictBot := make(map[string]string)
-	for key := range sf.dict {
-		dictBot[key] = ""
-	}
-	var err error
-	sf.winBots, err = win_bots.NewWinBots(sf.desktop, sf.addShow, sf.view, dictBot)
-	if err != nil {
-		log.Printf("DictBot.Show(): in create WinBots, err=\n\t%v\n", err)
-		return
-	}
-	go sf.winBots.Run()
-}
-
-// Показывает окно добавления бота
-func (sf *DictBot) addShow() {
-	log.Println("DictBot.addShow()")
-	winBotAdd, err := win_bot_add.NewWinBotAdd(sf.desktop, sf.addNew)
-	if err != nil {
-		log.Printf("DictBot.addShow(): in create WinBotAdd, err=\n\t%v\n", err)
-		return
-	}
-	go winBotAdd.Run()
-}
-
-// Команда обратного вызова для добавления нового бота
-func (sf *DictBot) addNew(name, pass string) {
-	log.Printf("DictBot.addNew(): name=%q\tpass=%q\n", name, pass)
-	_, isOk := sf.dict[name]
-	if isOk {
-		log.Printf("DictBot.addNew(): бот с именем(%q) уже существует\n", name)
-		return
-	}
-	bot, err := bot.NewBot(name, pass)
-	if err != nil {
-		log.Printf("DictBot.addNew(): in add new bot(%q), err=\n\t%v\n", name, err)
-		return
-	}
-	sf.dict[name] = bot
-	{ // Работа с хранилищем
-		// Сохранить бота в хранилище
-		err = sf.store.Put("/bot/"+name, pass)
-		if err != nil {
-			log.Printf("DictBot.addNew(): in save new bot(%q), err=\n\t%v\n", name, err)
-			return
-		}
-		// Обновить список ботов
-		lstBot := make([]string, 0)
-		for key := range sf.dict {
-			lstBot = append(lstBot, key)
-		}
-		// Сохранить обновлённый список ботов
-		binNewList, err := json.Marshal(&lstBot)
-		if err != nil {
-			log.Printf("DictBot.addNew(): in marshal new list bots, err=\n\t%v\n", err)
-			return
-		}
-		err = sf.store.Put("/bot/list", string(binNewList))
-		if err != nil {
-			log.Printf("DictBot.addNew(): in save new bot(%q), err=\n\t%v\n", name, err)
-			return
-		}
-	}
-
-	if sf.winBots == nil {
-		return
-	}
-	dictBot := make(map[string]string)
-	for key := range sf.dict {
-		dictBot[key] = ""
-	}
-	sf.winBots.UpdateList(dictBot)
-}
-
-// Команда просмотра существующего бота
-func (sf *DictBot) view(nameBot string) {
-	log.Printf("DictBot.view(): nameBot=%q\n", nameBot)
-	winBotView, err := win_bot_view.NewWinBotView(sf.desktop, nameBot)
-	if err != nil {
-		log.Printf("DictBot.view(): in create win view on bot(%q), err=\n\t%v\n", nameBot, err)
-		return
-	}
-	go winBotView.Run()
-}

+ 0 - 87
desktop/dict_bot/win_bot_add/win_bot_add.go

@@ -1,87 +0,0 @@
-// package win_bot_add -- добавляет новый бот
-package win_bot_add
-
-import (
-	_ "embed"
-	"fmt"
-	"log"
-	"net/url"
-	"runtime"
-
-	"github.com/zserge/lorca"
-
-	"wartank/pkg/types"
-)
-
-//go:embed win_bot_add.html
-var strWinHtml string
-
-// WinBotAdd -- окно добавления бота
-type WinBotAdd struct {
-	desktop types.IDesktop
-	store   types.IStore
-	win     lorca.UI
-	ws      types.IWebSocket
-	fnAdd   func(name, pass string)
-}
-
-// NewWinBotAdd -- возвращает новое окно добавления бота
-func NewWinBotAdd(desktop types.IDesktop, fnAdd func(name, pass string)) (*WinBotAdd, error) {
-	{ // Предусловия
-		if desktop == nil {
-			return nil, fmt.Errorf("NewWinBotAdd(): IDesktop == nil")
-		}
-		if fnAdd == nil {
-			return nil, fmt.Errorf("NewWinBotAdd(): fnAdd == nil")
-		}
-	}
-
-	sf := &WinBotAdd{
-		desktop: desktop,
-		store:   desktop.Store(),
-		ws:      desktop.Ws(),
-		fnAdd:   fnAdd,
-	}
-
-	args := []string{}
-	if runtime.GOOS == "linux" {
-		args = append(args, "--class=Lorca")
-	}
-	var err error
-	sf.win, err = lorca.New("data:text/html,"+url.PathEscape(strWinHtml), "", 640, 480, args...)
-	if err != nil {
-		return nil, fmt.Errorf("NewWinBotAdd(): in create win, err=\n\t%w", err)
-	}
-	go sf.close()
-	return sf, nil
-}
-
-// Работает в отдельном потоке, главный цикл окна
-func (sf *WinBotAdd) Run() {
-	log.Println("NewWinBotAdd.Run()")
-	sf.win.Bind("close_win", sf.onClose)
-	sf.win.Bind("add", sf.onBotAdd)
-	<-sf.win.Done() // Ожидание закрытия окна
-}
-
-// Добавляет пользователя по требованию
-func (sf *WinBotAdd) onBotAdd() {
-	log.Printf("NewWinBotAdd.onBotAdd()\n")
-	name := sf.win.Eval(`document.getElementById("/bot/name").value`).String()
-	pass := sf.win.Eval(`document.getElementById("/bot/pass").value`).String()
-	go sf.fnAdd(name, pass)
-	sf.onClose()
-}
-
-// Закрывает приложение
-func (sf *WinBotAdd) onClose() {
-	log.Println("NewWinBotAdd.onClose()")
-	sf.win.Close()
-}
-
-// close -- ожидает отмены глобального контекста
-func (sf *WinBotAdd) close() {
-	<-sf.desktop.CtxApp().Done()
-	log.Println("NewWinBotAdd.close()")
-	sf.win.Close()
-}

+ 0 - 69
desktop/dict_bot/win_bot_add/win_bot_add.html

@@ -1,69 +0,0 @@
-<!DOCTYPE html>
-<html lang="ru">
-
-	<head>
-		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-		<title>WarTank bot</title>
-		<meta name="author" content="SVI">
-		<style>
-			html {
-				height: 100%;
-			}
-
-			body {
-				margin: 0;
-				color: #fff;
-				/* Растягиваем body по высоте html */
-				min-height: 100%;
-				display: grid;
-				grid-template-rows: auto 1fr auto;
-			}
-
-			header {
-				background: rgb(88, 88, 184);
-			}
-
-			main {
-				background: rgb(141, 112, 112);
-			}
-
-			footer {
-				background: black;
-			}
-
-			.my-label {
-				display: inline-block;
-				background: rgb(12, 54, 56);
-				font-family: 'Courier New', Courier, monospace;
-				margin-top: 0.5em;
-				margin-left: 0.5em;
-			}
-		</style>
-	</head>
-
-	<body>
-		<header role="banner">
-			<b>WarTank bot [FunnySoft 2022]</b>
-		</header>
-		<main role="main">
-			<h2>Добавление бота</h2>
-			<div class="my-label">
-				Бот:<div>
-					Логин:<input id="/bot/name" type="text" />
-					Пароль:<input id="/bot/pass" type="text" />
-				</div>
-				<button type="button" name="add" value="Доб" onclick="add()">Добавить</button>
-				<div style="background:red;" id="/bot/err"></div>
-			</div>
-			<hr width="95%" height="4px">
-			<div>
-				<button style="background:red;" type="button" name="close" value="Закрыть"
-					onclick="close_win()">Закрыть</button>
-			</div>
-		</main>
-		<footer role="contentinfo">
-			<div class="footer">Окно добавления бота</div>
-		</footer>
-	</body>
-
-</html>

+ 0 - 211
desktop/dict_bot/win_bot_view/win_bot_view.go

@@ -1,211 +0,0 @@
-// package win_bot_view -- просмотр состояния бота
-package win_bot_view
-
-import (
-	_ "embed"
-	"fmt"
-	"log"
-	"net/url"
-	"runtime"
-	"time"
-
-	"github.com/zserge/lorca"
-
-	"wartank/pkg/types"
-)
-
-//go:embed win_bot_view.html
-var strWinHtml string
-
-// WinBotView -- окно просмотра бота
-type WinBotView struct {
-	desktop types.IDesktop
-	store   types.IStore
-	win     lorca.UI
-	ws      types.IWebSocket
-	name    string
-}
-
-// NewWinBotView -- возвращает новое окно просмотра бота
-func NewWinBotView(desktop types.IDesktop, name string) (*WinBotView, error) {
-	{ // Предусловия
-		if desktop == nil {
-			return nil, fmt.Errorf("NewWinBotView(): IDesktop == nil")
-		}
-		if name == "" {
-			return nil, fmt.Errorf("NewWinBotView(): name шы уьзен")
-		}
-	}
-
-	sf := &WinBotView{
-		desktop: desktop,
-		store:   desktop.Store(),
-		ws:      desktop.Ws(),
-		name:    name,
-	}
-
-	args := []string{}
-	if runtime.GOOS == "linux" {
-		args = append(args, "--class=Lorca")
-	}
-	var err error
-	sf.win, err = lorca.New("data:text/html,"+url.PathEscape(strWinHtml), "", 640, 480, args...)
-	if err != nil {
-		return nil, fmt.Errorf("NewWinBotView(): in create win, err=\n\t%w", err)
-	}
-	go sf.close()
-	return sf, nil
-}
-
-// Работает в отдельном потоке, главный цикл окна
-func (sf *WinBotView) Run() {
-	log.Println("WinBotView.Run()")
-	sf.win.Bind("close_win", sf.onClose)
-	for {
-		select {
-		case <-sf.win.Done(): // Ожидание закрытия окна
-			sf.close()
-			return
-		default: // Дежурный вывод информации
-			go sf.update()
-			time.Sleep(time.Millisecond * 500)
-		}
-	}
-}
-
-// Обновляет информацию в окне
-func (sf *WinBotView) update() {
-	dictReq := make(map[string]string)
-	dictReq["name"] = sf.name
-	dictResp, err := sf.ws.Call("/bot/status", dictReq)
-	if err != nil {
-		log.Printf("WinBotView.update(): in read bot(%q),err=\n\t%v\n", sf.name, err)
-		return
-	}
-
-	// log.Printf("WinBotView.update(): dictRes=%#v\n", dictResp)
-
-	{ // Имя
-		name := dictResp["/bot/name"]
-		js := fmt.Sprintf(
-			`function UpdateName(){
-			var _el=document.getElementById("/bot/name");
-			_el.innerText=%q
-			}
-		UpdateName()`, name)
-		sf.win.Eval(js)
-	}
-	{ // Если онлайн
-		isOnline := dictResp["/bot/online"]
-		js := fmt.Sprintf(
-			`function UpdateIsOnlime(){
-			var _el=document.getElementById("/bot/online");
-			_el.innerText=%q
-			}
-			UpdateIsOnlime()`, isOnline)
-		sf.win.Eval(js)
-	}
-	{ // Топливо
-		fuel := dictResp["/bot/fuel"]
-		js := fmt.Sprintf(
-			`function UpdateFuel(){
-			var _el=document.getElementById("/bot/fuel");
-			_el.innerText=%q
-			}
-			UpdateFuel()`, fuel)
-		sf.win.Eval(js)
-	}
-	{ // Золото
-		gold := dictResp["/bot/gold"]
-		js := fmt.Sprintf(
-			`function UpdateGold(){
-			var _el=document.getElementById("/bot/gold");
-			_el.innerText=%q
-			}
-			UpdateGold()`, gold)
-		sf.win.Eval(js)
-	}
-	{ // Серебро
-		silver := dictResp["/bot/silver"]
-		js := fmt.Sprintf(
-			`function UpdateSilver(){
-			var _el=document.getElementById("/bot/silver");
-			_el.innerText=%q
-			}
-			UpdateSilver()`, silver)
-		sf.win.Eval(js)
-	}
-	{ // Серебро-время
-		silverTime := dictResp["/bank/silver-time"]
-		js := fmt.Sprintf(
-			`function UpdateSilverTime(){
-			var _el=document.getElementById("/bank/silver-time");
-			_el.innerText=%q
-			}
-			UpdateSilverTime()`, silverTime)
-		sf.win.Eval(js)
-	}
-	{ // Серебро-режим
-		silverMode := dictResp["/bank/silver-mode"]
-		js := fmt.Sprintf(
-			`function UpdateSilverMode(){
-			var _el=document.getElementById("/bank/silver-mode");
-			_el.innerText=%q
-			}
-			UpdateSilverMode()`, silverMode)
-		sf.win.Eval(js)
-	}
-	{ // Серебро-всего
-		silverAll := dictResp["/angar/silver-all"]
-		js := fmt.Sprintf(
-			`function UpdateSilverAll(){
-			var _el=document.getElementById("/angar/silver-all");
-			_el.innerText=%q
-			}
-			UpdateSilverAll()`, silverAll)
-		sf.win.Eval(js)
-	}
-	{ // Шахта-время
-		mineTime := dictResp["/bot/mine-time"]
-		js := fmt.Sprintf(
-			`function UpdateMineTime(){
-			var _el=document.getElementById("/bot/mine-time");
-			_el.innerText=%q
-			}
-			UpdateMineTime()`, mineTime)
-		sf.win.Eval(js)
-	}
-	{ // Шахта-режим
-		mineMode := dictResp["/bot/mine-mode"]
-		js := fmt.Sprintf(
-			`function UpdateMineMode(){
-			var _el=document.getElementById("/bot/mine-mode");
-			_el.innerText=%q
-			}
-			UpdateMineMode()`, mineMode)
-		sf.win.Eval(js)
-	}
-	{ // Шахта-руда
-		mineRuda := dictResp["/mine/ruda"]
-		js := fmt.Sprintf(
-			`function UpdateMineRuda(){
-			var _el=document.getElementById("/mine/ruda");
-			_el.innerText=%q
-			}
-			UpdateMineRuda()`, mineRuda)
-		sf.win.Eval(js)
-	}
-}
-
-// Закрывает окно
-func (sf *WinBotView) onClose() {
-	log.Println("WinBotView.onClose()")
-	sf.win.Close()
-}
-
-// close -- ожидает отмены глобального контекста
-func (sf *WinBotView) close() {
-	<-sf.desktop.CtxApp().Done()
-	log.Println("WinBotView.close()")
-	sf.win.Close()
-}

+ 0 - 110
desktop/dict_bot/win_bot_view/win_bot_view.html

@@ -1,110 +0,0 @@
-<!DOCTYPE html>
-<html lang="ru">
-
-	<head>
-		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-		<title>WarTank bot</title>
-		<meta name="author" content="SVI">
-		<style>
-			html {
-				height: 100%;
-			}
-
-			body {
-				margin: 0;
-				color: #fff;
-				/* Растягиваем body по высоте html */
-				min-height: 100%;
-				display: grid;
-				grid-template-rows: auto 1fr auto;
-			}
-
-			header {
-				background: rgb(88, 88, 184);
-			}
-
-			main {
-				background: rgb(141, 112, 112);
-			}
-
-			footer {
-				background: black;
-			}
-
-			.my-label {
-				display: inline-block;
-				background: rgb(12, 54, 56);
-				font-family: 'Courier New', Courier, monospace;
-				margin-top: 0.5em;
-				margin-left: 6px;
-				border-radius: 3px;
-			}
-		</style>
-	</head>
-
-	<body>
-		<header role="banner">
-			<b>WarTank bot [FunnySoft 2022]</b>
-		</header>
-		<main role="main">
-			<b>Просмотр бота</b>
-			<div>
-				<div class="my-label">Логин:
-					<div id="/bot/name" type="text"></div>
-				</div>
-				<div class="my-label">Онлайн:
-					<div id="/bot/online" type="text"></div>
-				</div>
-				<div class="my-label">Топливо:
-					<div id="/bot/fuel" type="text"></div>
-				</div>
-				<div class="my-label">Золото:
-					<div id="/bot/gold" type="text"></div>
-				</div>
-				<div class="my-label">Серебро-бот:
-					<div id="/bot/silver" type="text"></div>
-				</div>
-				<hr width="95%" height="4px">
-			</div>
-			<b>База</b>
-			<hr width="95%" height="4px">
-			<div>
-				<div>
-					<b>Банк</b><br>
-					<div class="my-label">Серебро-время:
-						<div id="/bank/silver-time" type="text"></div>
-					</div>
-					<div class="my-label">Серебро-режим:
-						<div id="/bank/silver-mode" type="text"></div>
-					</div>
-					<div class="my-label">Серебро-всего:
-						<div id="/angar/silver-all" type="text"></div>
-					</div>
-					<hr width="95%" height="4px">
-				</div>
-				<div>
-					<b>Шахта</b><br>
-					<div class="my-label">Шахта-время:
-						<div id="/bot/mine-time" type="text"></div>
-					</div>
-					<div class="my-label">Шахта-режим:
-						<div id="/bot/mine-mode" type="text"></div>
-					</div>
-					<div class="my-label">Руда:
-						<div id="/mine/ruda" type="text"></div>
-					</div>
-					<hr width="95%" height="4px">
-				</div>
-			</div>
-			<div style="background:red;" id="/bot/err"></div>
-			<div>
-				<button style="background:red;" type="button" name="close" value="Закрыть"
-					onclick="close_win()">Закрыть</button>
-			</div>
-		</main>
-		<footer role="contentinfo">
-			<div class="footer">Окно просмотра бота</div>
-		</footer>
-	</body>
-
-</html>

+ 0 - 127
desktop/dict_bot/win_bots/win_bots.go

@@ -1,127 +0,0 @@
-// package win_bots -- окно управления ботами
-package win_bots
-
-import (
-	_ "embed"
-	"fmt"
-	"log"
-	"net/url"
-	"runtime"
-
-	"github.com/zserge/lorca"
-
-	"wartank/pkg/types"
-)
-
-//go:embed win_bots.html
-var strWinHtml string
-
-// WinBots -- окно управления ботами
-type WinBots struct {
-	desktop types.IDesktop
-	store   types.IStore
-	win     lorca.UI
-	ws      types.IWebSocket
-	fnAdd   func()
-	fnView  func(nameBot string)
-	dictBot map[string]string // Список ботов
-}
-
-// NewWinBots -- возвращает новое окно управления ботами
-func NewWinBots(desktop types.IDesktop, fnAdd func(), fnView func(nameBot string), dictBot map[string]string) (*WinBots, error) {
-	{ // Предусловия
-		if desktop == nil {
-			return nil, fmt.Errorf("NewWinBots(): IDesktop == nil")
-		}
-		if fnAdd == nil {
-			return nil, fmt.Errorf("NewWinBots(): fnAdd == nil")
-		}
-		if fnView == nil {
-			return nil, fmt.Errorf("NewWinBots(): fnView == nil")
-		}
-		if dictBot == nil {
-			return nil, fmt.Errorf("NewWinBots(): dictBot == nil")
-		}
-	}
-
-	sf := &WinBots{
-		desktop: desktop,
-		store:   desktop.Store(),
-		ws:      desktop.Ws(),
-		fnAdd:   fnAdd,
-		fnView:  fnView,
-		dictBot: dictBot,
-	}
-
-	args := []string{}
-	if runtime.GOOS == "linux" {
-		args = append(args, "--class=Lorca")
-	}
-	var err error
-	sf.win, err = lorca.New("data:text/html,"+url.PathEscape(strWinHtml), "", 640, 480, args...)
-	if err != nil {
-		return nil, fmt.Errorf("NewWinBots(): in create win, err=\n\t%w", err)
-	}
-	go sf.close()
-	return sf, nil
-}
-
-// Обновляет список ботов
-func (sf *WinBots) UpdateList(dictBot map[string]string) {
-	log.Println("WinBots.UpdateList()")
-	sf.dictBot = dictBot
-	sf.setBots()
-}
-
-// Работает в отдельном потоке, главный цикл окна
-func (sf *WinBots) Run() {
-	log.Println("WinBots.Run()")
-	sf.win.Bind("close_win", sf.onClose)
-	sf.win.Bind("user_add", sf.onUsersAdd)
-	sf.win.Bind("user_view", sf.onUsersAdd)
-	sf.setBots()
-	<-sf.win.Done() // Ожидание закрытия окна
-}
-
-// Заполняет список ботов
-func (sf *WinBots) setBots() {
-	log.Println("WinBots.setBots()")
-	strList := ""
-	count := 0
-	for key := range sf.dictBot {
-		strCount := fmt.Sprint(count)
-		strList += `<div style="color:#eee;margin-top:3px;" id="/bot/` + strCount + `">` + key +
-			`&nbsp;&nbsp;&nbsp;<button type="button" name="add" value="Посм" onclick="bot_` + strCount + `()">Посмотреть</button></div>`
-		sf.win.Bind("bot_"+strCount, func() {
-			go sf.fnView(key)
-		})
-		count++
-	}
-	js := fmt.Sprintf(`
-	function SetBotList(){
-		var _el=document.getElementById("/bot/list");
-		_el.innerHTML=%q
-	}
-	SetBotList()
-	`, strList)
-	sf.win.Eval(js)
-}
-
-// Добавляет бота по требованию
-func (sf *WinBots) onUsersAdd() {
-	log.Printf("WinBots.onUsersAdd()\n")
-	go sf.fnAdd()
-}
-
-// Закрывает приложение
-func (sf *WinBots) onClose() {
-	log.Println("WinBots.onClose()")
-	sf.win.Close()
-}
-
-// close -- ожидает отмены глобального контекста
-func (sf *WinBots) close() {
-	<-sf.desktop.CtxApp().Done()
-	log.Println("WinBots.close()")
-	sf.win.Close()
-}

+ 0 - 68
desktop/dict_bot/win_bots/win_bots.html

@@ -1,68 +0,0 @@
-<!DOCTYPE html>
-<html lang="ru">
-
-	<head>
-		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-		<title>WarTank bot</title>
-		<meta name="author" content="SVI">
-		<style>
-			html {
-				height: 100%;
-			}
-
-			body {
-				margin: 0;
-				color: #fff;
-				/* Растягиваем body по высоте html */
-				min-height: 100%;
-				display: grid;
-				grid-template-rows: auto 1fr auto;
-			}
-
-			header {
-				background: rgb(88, 88, 184);
-			}
-
-			main {
-				background: rgb(141, 112, 112);
-			}
-
-			footer {
-				background: black;
-			}
-
-			.my-label {
-				display: inline-block;
-				background: rgb(12, 54, 56);
-				font-family: 'Courier New', Courier, monospace;
-				margin-top: 0.5em;
-				margin-left: 0.5em;
-			}
-		</style>
-	</head>
-
-	<body>
-		<header role="banner">
-			<b>WarTank bot [FunnySoft 2022]</b>
-		</header>
-		<main role="main">
-			<h2>Управление ботами</h2>
-			<div class="my-label">
-				Боты:<div id="/bot/list"></div>
-				<hr width="95%" height="4px">
-				<button type="button" name="add" value="Доб" onclick="user_add()">Добавить</button>
-				<div style="background:red;" id="/bot/list/err"></div>
-			</div>
-			<hr width="95%" height="4px">
-			<div>
-				<br>
-				<button style="background:red;" type="button" name="close" value="Закрыть"
-					onclick="close_win()">Закрыть</button>
-			</div>
-		</main>
-		<footer role="contentinfo">
-			<div class="footer">Окно управления игроками игры.</div>
-		</footer>
-	</body>
-
-</html>

+ 0 - 177
desktop/root/root.go

@@ -1,177 +0,0 @@
-// package root -- объект рута
-package root
-
-import (
-	"fmt"
-	"log"
-	"strings"
-	"time"
-
-	"wartank/desktop/root/win_root_login"
-	"wartank/desktop/root/win_root_set"
-	"wartank/pkg/components/safebool"
-	"wartank/pkg/types"
-)
-
-// Root -- объект рута
-type Root struct {
-	desktop      types.IDesktop
-	ws           types.IWebSocket
-	isLogin      *safebool.SafeBool
-	isPassSet    *safebool.SafeBool
-	winRootMake  *win_root_set.WinRootMake
-	winRootLogin *win_root_login.WinRootLogin
-}
-
-// NewRoot -- вовзращает новый объект рута
-func NewRoot(desktop types.IDesktop) (*Root, error) {
-	log.Println("NewRoot()")
-	if desktop == nil {
-		return nil, fmt.Errorf("NewRoot(): IDesktop == nil")
-	}
-	sf := &Root{
-		desktop:   desktop,
-		ws:        desktop.Ws(),
-		isLogin:   safebool.NewSafeBool(),
-		isPassSet: safebool.NewSafeBool(),
-	}
-	sf.checkRoot()
-	return sf, nil
-}
-
-// Проверяет, есть ли рут в системе
-func (sf *Root) checkRoot() {
-	log.Println("Root.checkRoot()")
-	for { // Цикл ожидания рут-пароля (если его нет)
-		isExists := sf.checkIsExists()
-		if !isExists {
-			sf.makePassRoot() // Раз пользователь сам создал пароль, то и проверка логина не нужна
-			return
-		}
-		// Пароля уже есть, проверяем логин
-		sf.checkLogin()
-		return
-	}
-
-	// Запрос пароля рута
-
-	// winUsers, err := win_users.NewWinUsers(sf.desktop)
-	// if err != nil {
-	// 	log.Printf("Root.checkRoot(): in create WinUsers, err=\n\t%v\n", err)
-	// 	return
-	// }
-	// go winUsers.Run()
-}
-
-// Проверка логина
-func (sf *Root) checkLogin() {
-	log.Println("Root.checkLogin()")
-	sf.makeWinLogin()
-	strPass := sf.winRootLogin.GetPass()
-	dictReq := make(map[string]string)
-	dictReq["pass"] = strPass
-	for {
-		dictResp, err := sf.ws.Call("/root/password/check", dictReq)
-		if err != nil {
-			err = fmt.Errorf("Root.checkLogin(): при выполнении запроса, err=\n\t%w", err)
-			sf.winRootLogin.SetError(err)
-			time.Sleep(time.Second * 2)
-			continue
-		}
-		log.Printf("WinRootLogin.onCheckPass(): resp=%q\n", dictResp)
-		strErr := dictResp["err"]
-		if strErr != "" {
-			err = fmt.Errorf("Root.checkLogin(): при сравнении паролей, err=\n\t%q", strErr)
-			sf.winRootLogin.SetError(err)
-			time.Sleep(time.Second * 2)
-			for {
-				oldPass := strPass
-				strPass = sf.winRootLogin.GetPass()
-				if oldPass != strPass {
-					break
-				}
-				time.Sleep(time.Millisecond * 100)
-			}
-			dictReq["pass"] = strPass
-			continue
-		}
-		// Всё ништяк
-		sf.winRootLogin.Close()
-		sf.isPassSet.Set()
-		return
-	}
-}
-
-// Показывает окно логина
-func (sf *Root) makeWinLogin() {
-	log.Println("Root.makeWinLogin()")
-	var err error
-	for {
-		sf.winRootLogin, err = win_root_login.NewWinRootLogin(sf.desktop)
-		if err != nil {
-			log.Printf("Root.makeWinLogin(): in create WinRootLogin, err=\n\t%v\n", err)
-			time.Sleep(time.Second * 2)
-			continue
-		}
-		break
-	}
-	go sf.winRootLogin.Run()
-}
-
-// Проверка на существование пароля рута
-func (sf *Root) checkIsExists() bool {
-	log.Println("Root.checkIsExists()")
-	var strErr string
-	for {
-		dictRoot, err := sf.ws.Read("/root/password/is_exists")
-		if err != nil {
-			log.Printf("Root.checkRoot(): in get password root, err=\n\t%v\n", err)
-			time.Sleep(time.Second * 2)
-			continue
-		}
-		strErr = dictRoot["err"]
-		if strings.Contains(strErr, "leveldb: not found") {
-			log.Printf("Root.checkRoot(): первый запуск, пароль рута не задан\n")
-			return false
-		}
-		strIsExists := dictRoot["/root/password/is_exists"]
-		if strIsExists == "true" {
-			return true
-		}
-		return false
-	}
-}
-
-// Создаёт пароль рута
-func (sf *Root) makePassRoot() {
-	log.Println("Root.makePassRoot()")
-	sf.makeWinRootMake()
-	strPass := sf.winRootMake.GetPass()
-	dictReq := make(map[string]string)
-	dictReq["pass"] = strPass
-	for {
-		err := sf.ws.Write("/root/password/set", dictReq)
-		if err != nil {
-			sf.winRootMake.SetError(err)
-			time.Sleep(time.Second * 2)
-			continue
-		}
-		sf.winRootMake.Close()
-		break
-	}
-}
-
-// Показывает окно создания пароля рута
-func (sf *Root) makeWinRootMake() {
-	var err error
-	for {
-		sf.winRootMake, err = win_root_set.NewWinRootMake(sf.desktop)
-		if err == nil {
-			go sf.winRootMake.Run()
-			return
-		}
-		log.Printf("Root.makeWinRootMake(): in create WinRoot, err=\n\t%v\n", err)
-		time.Sleep(time.Second * 2)
-		continue
-	}
-}

+ 0 - 106
desktop/root/win_root_login/win_root_login.go

@@ -1,106 +0,0 @@
-// package win_root_login -- запрашивает рутовый пароль при запуске
-package win_root_login
-
-import (
-	_ "embed"
-	"fmt"
-	"log"
-	"net/url"
-	"runtime"
-	"sync"
-	"time"
-
-	"github.com/zserge/lorca"
-
-	"wartank/pkg/types"
-)
-
-//go:embed win_root_login.html
-var strWinHtml string
-
-// WinRootLogin --  запрашивает рутовый пароль на приложение
-type WinRootLogin struct {
-	desktop  types.IDesktop
-	store    types.IStore
-	win      lorca.UI
-	ws       types.IWebSocket
-	block    sync.Mutex
-	rootPass string
-}
-
-// NewWinRootLogin -- возвращает новое окно запроса пароля для рута
-func NewWinRootLogin(desktop types.IDesktop) (*WinRootLogin, error) {
-	if desktop == nil {
-		return nil, fmt.Errorf("NewWinRootLogin(): IDesktop == nil")
-	}
-	sf := &WinRootLogin{
-		desktop: desktop,
-		store:   desktop.Store(),
-		ws:      desktop.Ws(),
-	}
-
-	args := []string{}
-	if runtime.GOOS == "linux" {
-		args = append(args, "--class=Lorca")
-	}
-	var err error
-	sf.win, err = lorca.New("data:text/html,"+url.PathEscape(strWinHtml), "", 640, 480, args...)
-	if err != nil {
-		return nil, fmt.Errorf("NewWinRootLogin(): in create win, err=\n\t%w", err)
-	}
-	go sf.close()
-
-	return sf, nil
-}
-
-// GetPass -- возвращает полученный пароль из формы
-func (sf *WinRootLogin) GetPass() string {
-	fnCheck := func() bool {
-		sf.block.Lock()
-		defer sf.block.Unlock()
-		return sf.rootPass == ""
-	}
-	for fnCheck() {
-		time.Sleep(time.Millisecond * 20)
-	}
-	sf.block.Lock()
-	defer sf.block.Unlock()
-	return sf.rootPass
-}
-
-func (sf *WinRootLogin) SetError(err error) {
-	js := fmt.Sprintf(`
-	function SetErrorGet(){
-		var _el=document.getElementById("/root/password/err");
-		_el.innerText="WinRootLogin.onCheckPass(): ошибка проверки пароля, err=\n\t%v"
-	}
-	SetErrorGet()
-	`, err)
-	sf.win.Eval(js)
-}
-
-func (sf *WinRootLogin) Close() {
-	sf.win.Close()
-}
-
-// Работает в отдельном потоке, главный цикл окна
-func (sf *WinRootLogin) Run() {
-	log.Println("WinRootLogin.Run()")
-	sf.win.Bind("check_pass", sf.onCheckPass)
-	<-sf.win.Done() // Ожидание закрытия окна
-}
-
-// Проверяет пароль рута
-func (sf *WinRootLogin) onCheckPass() {
-	log.Printf("WinRootLogin.onCheckPass()\n")
-	sf.block.Lock()
-	defer sf.block.Unlock()
-	sf.rootPass = sf.win.Eval(`document.getElementById("/root/password/val").value`).String()
-}
-
-// close -- ожидает отмены глобального контекста
-func (sf *WinRootLogin) close() {
-	<-sf.desktop.CtxApp().Done()
-	log.Println("WinRoot.close()")
-	sf.win.Close()
-}

+ 0 - 62
desktop/root/win_root_login/win_root_login.html

@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html lang="ru">
-
-	<head>
-		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-		<title>WarTank bot</title>
-		<meta name="author" content="SVI">
-		<style>
-			html {
-				height: 100%;
-			}
-
-			body {
-				margin: 0;
-				color: #fff;
-				/* Растягиваем body по высоте html */
-				min-height: 100%;
-				display: grid;
-				grid-template-rows: auto 1fr auto;
-			}
-
-			header {
-				background: rgb(88, 88, 184);
-			}
-
-			main {
-				background: rgb(141, 112, 112);
-			}
-
-			footer {
-				background: black;
-			}
-
-			.my-label {
-				display: inline-block;
-				background: rgb(12, 54, 56);
-				font-family: 'Courier New', Courier, monospace;
-				margin-top: 0.5em;
-				margin-left: 0.5em;
-			}
-		</style>
-	</head>
-
-	<body>
-		<header role="banner">
-			<b>WarTank bot [FunnySoft 2022]</b>
-		</header>
-		<main role="main">
-			<h2>Ввод пароля пользователя</h2>
-			<div class="my-label">
-				Пароль:<input id="/root/password/val" type="text" />
-				<button type="button" name="save" value="Вход" onclick="check_pass()">Вход</button>
-				<div style="background:red;" id="/root/password/err"></div>
-			</div>
-			<hr width="95%" height="4px">
-		</main>
-		<footer role="contentinfo">
-			<div class="footer">Для правильной работы программы необходимо запустить <code>server</code>.</div>
-		</footer>
-	</body>
-
-</html>

+ 0 - 133
desktop/root/win_root_set/win_root_set.go

@@ -1,133 +0,0 @@
-// package win_root_set -- задаёт рутовый пароль на приложение
-package win_root_set
-
-import (
-	_ "embed"
-	"fmt"
-	"log"
-	"net/url"
-	"runtime"
-	"sync"
-	"time"
-
-	"github.com/zserge/lorca"
-
-	"wartank/pkg/types"
-)
-
-//go:embed win_root_set.html
-var strWinHtml string
-
-// WinRootMake --  задаёт рутовый пароль на приложение
-type WinRootMake struct {
-	desktop  types.IDesktop
-	store    types.IStore
-	win      lorca.UI
-	ws       types.IWebSocket
-	rootPass string // Пароль рута из формы
-	block    sync.Mutex
-}
-
-// NewWinRootMake -- возвращает новое окно пароля для рута
-func NewWinRootMake(desktop types.IDesktop) (*WinRootMake, error) {
-	if desktop == nil {
-		return nil, fmt.Errorf("NewWinRootMake(): IDesktop == nil")
-	}
-	sf := &WinRootMake{
-		desktop: desktop,
-		store:   desktop.Store(),
-		ws:      desktop.Ws(),
-	}
-
-	args := []string{}
-	if runtime.GOOS == "linux" {
-		args = append(args, "--class=Lorca")
-	}
-	var err error
-	sf.win, err = lorca.New("data:text/html,"+url.PathEscape(strWinHtml), "", 640, 480, args...)
-	if err != nil {
-		return nil, fmt.Errorf("WinRoot(): in create win, err=\n\t%w", err)
-	}
-	go sf.close()
-
-	return sf, nil
-}
-
-// GetPass -- возвращает полученный пароль из формы
-func (sf *WinRootMake) GetPass() string {
-	fnCheck := func() bool {
-		sf.block.Lock()
-		defer sf.block.Unlock()
-		return len(sf.rootPass) > 7
-	}
-	for !fnCheck() {
-		time.Sleep(time.Millisecond * 20)
-	}
-	sf.block.Lock()
-	defer sf.block.Unlock()
-	return sf.rootPass
-}
-
-// SetError -- устанавливает признак ошибки при операциях с паролем
-func (sf *WinRootMake) SetError(err error) {
-	js := fmt.Sprintf(`
-	function SetErrorSave(){
-		var _el=document.getElementById("/root/password/err");
-		_el.innerText="WinRootMake.onSetPass(): ошибка передачи при сохранении пароля, err=\n\t%v"
-	}
-	SetErrorSave()`, err)
-	sf.win.Eval(js)
-}
-
-func (sf *WinRootMake) Close() {
-	sf.win.Close()
-}
-
-// Работает в отдельном потоке, главный цикл окна
-func (sf *WinRootMake) Run() {
-	log.Println("WinRootMake.Run()")
-	sf.win.Bind("close_win", sf.onClose)
-	sf.win.Bind("set_pass", sf.onSetPass)
-	<-sf.win.Done() // Ожидание закрытия окна
-}
-
-// Сохраняет пароль рута
-func (sf *WinRootMake) onSetPass() {
-	log.Printf("WinRootMake.onSetPass()\n")
-	sf.block.Lock()
-	defer sf.block.Unlock()
-	sf.rootPass = sf.win.Eval(`document.getElementById("/root/password/val").value`).String()
-	if len(sf.rootPass) < 8 {
-		js := `
-		function SetError(){
-			var _el=document.getElementById("/root/password/err");
-			_el.innerText="WinRootMake.onSetPass(): пароль слишком короткий"
-		}
-		SetError()
-		`
-		sf.win.Eval(js)
-		return
-	}
-	js := `
-	function ResetError(){
-		var _el=document.getElementById("/root/password/err");
-		_el.innerText=""
-	}
-	ResetError()
-	`
-	sf.win.Eval(js)
-	log.Printf("WinRootMake.onSetPass(): pass=%q\n", sf.rootPass)
-}
-
-// Закрывает приложение
-func (sf *WinRootMake) onClose() {
-	log.Println("WinRootMake.onClose()")
-	sf.win.Close()
-}
-
-// close -- ожидает отмены глобального контекста
-func (sf *WinRootMake) close() {
-	<-sf.desktop.CtxApp().Done()
-	log.Println("WinRootMake.close()")
-	sf.win.Close()
-}

+ 0 - 67
desktop/root/win_root_set/win_root_set.html

@@ -1,67 +0,0 @@
-<!DOCTYPE html>
-<html lang="ru">
-
-	<head>
-		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-		<title>WarTank bot</title>
-		<meta name="author" content="SVI">
-		<style>
-			html {
-				height: 100%;
-			}
-
-			body {
-				margin: 0;
-				color: #fff;
-				/* Растягиваем body по высоте html */
-				min-height: 100%;
-				display: grid;
-				grid-template-rows: auto 1fr auto;
-			}
-
-			header {
-				background: rgb(88, 88, 184);
-			}
-
-			main {
-				background: rgb(141, 112, 112);
-			}
-
-			footer {
-				background: black;
-			}
-
-			.my-label {
-				display: inline-block;
-				background: rgb(12, 54, 56);
-				font-family: 'Courier New', Courier, monospace;
-				margin-top: 0.5em;
-				margin-left: 0.5em;
-			}
-		</style>
-	</head>
-
-	<body>
-		<header role="banner">
-			<b>WarTank bot [FunnySoft 2022]</b>
-		</header>
-		<main role="main">
-			<h2>ВНИМАНИЕ!<br>Этот пароль будет установлен на весь сервер!</h2>
-			<div id="status"><b>Пароль для root:</b></div>
-			<div class="my-label">
-				Пароль:<input id="/root/password/val" type="text" />
-				<button type="button" name="save" value="Сохранить" onclick="set_pass()">Сохранить</button>
-				<div style="background:red;" id="/root/password/err"></div>
-			</div>
-			<hr width="95%" height="4px">
-			<div>
-				<button style="background:red;" type="button" name="close" value="Закрыть"
-					onclick="close_win()">Закрыть</button>
-			</div>
-		</main>
-		<footer role="contentinfo">
-			<div class="footer">Для правильной работы программы необходимо запустить <code>server</code>.</div>
-		</footer>
-	</body>
-
-</html>

+ 0 - 76
desktop/store_net/store_net.go

@@ -1,76 +0,0 @@
-// package store_net -- реализация сетевого хранилища
-package store_net
-
-import (
-	"fmt"
-
-	"github.com/sirupsen/logrus"
-
-	"wartank/pkg/types"
-)
-
-// StoreNet -- реализвция сетевого хранилища
-type StoreNet struct {
-	desktop types.IDesktop
-	ws      types.IWebSocket
-}
-
-// NewStoreNet -- возвращает новый объект сетевого хранилища
-func NewStoreNet(desktop types.IDesktop) (*StoreNet, error) {
-	logrus.Infof("NewStoreNet()")
-	if desktop == nil {
-		return nil, fmt.Errorf("NewStoreNet(): IDesktop = =nil")
-	}
-	sf := &StoreNet{
-		desktop: desktop,
-		ws:      desktop.Ws(),
-	}
-	return sf, nil
-}
-
-// Find -- поиск объекта в хранилище
-func (sf *StoreNet) Find(prefix string) (map[string]string, error) {
-	logrus.Debugf("StoreNet.Find()")
-	mapReq := make(map[string]string)
-	mapReq["cmd"] = "/store/find"
-	mapReq["key"] = prefix
-
-	dictResp, err := sf.ws.Call("/store/find", mapReq)
-	if err != nil {
-		return nil, fmt.Errorf("StoreNet.Find(): in write StoreNet, err=\n\t%w", err)
-	}
-	strErr := dictResp["err"]
-	if strErr != "" {
-		return nil, fmt.Errorf("StoreNet.Find(): in response, err=\n\t%v", strErr)
-	}
-	return dictResp, nil
-}
-
-// Get -- получает содержимое записи по ключу
-func (sf *StoreNet) Get(key string) (string, error) {
-	logrus.Debugf("StoreNet.Get()")
-
-	dictResp, err := sf.ws.Read(key)
-	if err != nil {
-		return "", fmt.Errorf("StoreNet.Get(): in read StoreNet, err=\n\t%w", err)
-	}
-	strErr := dictResp["err"]
-	if string(strErr) != "" {
-		return "", fmt.Errorf("StoreNet.Get(): in response, err=\n\t%v", strErr)
-	}
-	strResp := dictResp["res"]
-	return strResp, nil
-}
-
-// Put -- помещает запись в хранилище
-func (sf *StoreNet) Put(key string, val string) error {
-	logrus.Debugf("StoreNet.Put()")
-	dictReq := make(map[string]string)
-	dictReq["key"] = key
-	dictReq["val"] = val
-	err := sf.ws.Write("/store/put", dictReq)
-	if err != nil {
-		return fmt.Errorf("StoreNet.Get(): in write StoreNet, err=\n\t%w", err)
-	}
-	return nil
-}

+ 0 - 218
desktop/web_socket/web_socket.go

@@ -1,218 +0,0 @@
-// package web_socket -- реализация высокоуровнего веб-сокета для работы десктопа
-package web_socket
-
-import (
-	"encoding/json"
-	"fmt"
-	"log"
-	"net/url"
-	"os"
-	"sync"
-	"time"
-
-	"github.com/gorilla/websocket"
-
-	"wartank/pkg/components/safebool"
-	"wartank/pkg/types"
-)
-
-const (
-	strWebSocket = "web_socket"
-	TypeMsgBin   = 2
-)
-
-// WebSocket -- реализация высокоуровнего веб-сокета для работы десктопа
-type WebSocket struct {
-	kern      types.IKernel
-	slog      types.ISlog
-	url       string
-	isConnect *safebool.SafeBool
-	ws        *websocket.Conn
-	block     sync.RWMutex
-}
-
-// NewWebSocket -- возвращает новый веб-сокет
-func NewWebSocket(kern types.IKernel) (*WebSocket, error) {
-	log.Println("NewWebSocket()")
-	if kern == nil {
-		return nil, fmt.Errorf("NewWebSocket(): IKernel == nil")
-	}
-	url := os.Getenv("SERVER_URL")
-	if url == "" {
-		return nil, fmt.Errorf("NewWebSocket(): env SERVER_URL not set")
-	}
-	sf := &WebSocket{
-		kern:      kern,
-		slog:      kern.Slog(),
-		url:       url,
-		isConnect: safebool.NewSafeBool(),
-	}
-
-	sf.connect()
-	go sf.close()
-	return sf, nil
-}
-
-// Подключает веб-сокет к серверу
-func (sf *WebSocket) connect() {
-	log.Println("WebSocket.connect()")
-	fnConnect := func() {
-		u := url.URL{Scheme: "ws", Host: sf.url, Path: "/api/ws"}
-		strUrl := u.String()
-		log.Printf("WebSocket.connect(): wait connect to %q\n", strUrl)
-		var err error
-		sf.ws, _, err = websocket.DefaultDialer.Dial(strUrl, nil)
-		if err != nil {
-			log.Printf("WebSocket.connect(): in dial, err=\n\t%v\n", err)
-			time.Sleep(time.Second * 2)
-			return
-		}
-		sf.isConnect.Set()
-		log.Println("WebSocket.connect(): ok")
-	}
-	for !sf.isConnect.Get() {
-		select {
-		case <-sf.kern.CtxApp().Done():
-			return
-		default:
-			fnConnect()
-		}
-
-	}
-}
-
-// Read -- потокобезопасное чтение топика сервера
-func (sf *WebSocket) Read(topic string) (map[string]string, error) {
-	sf.block.Lock()
-	defer sf.block.Unlock()
-	dictResp, err := sf.read(topic)
-	if err != nil {
-		return nil, fmt.Errorf("WebSocket.Read(): in read, err=\n\t%w", err)
-	}
-	return dictResp, nil
-}
-
-// Скрытая потоко-небезопасна функция
-func (sf *WebSocket) read(topic string) (dictResp map[string]string, err error) {
-	var binResp []byte
-	for {
-		dictReq := make(map[string]string)
-		dictReq["topic"] = topic
-		binReq, err := json.Marshal(dictReq)
-		if err != nil {
-			return nil, fmt.Errorf("WebSocket.read(): in marshall topic(%q), err=\n\t%w", topic, err)
-		}
-		err = sf.ws.WriteMessage(TypeMsgBin, binReq)
-		if err != nil {
-			sf.slog.Errorf("WebSocket.read(): in write msg, err=\n\t%v\n", err)
-			sf.ws.Close()
-			sf.isConnect.Reset()
-			sf.connect()
-			continue
-		}
-
-		_, binResp, err = sf.ws.ReadMessage()
-		if err != nil {
-			sf.slog.Errorf("WebSocket.read(): in read msg, err=\n\t%v\n", err)
-			sf.ws.Close()
-			sf.isConnect.Reset()
-			sf.connect()
-			continue
-		}
-		break
-	}
-	dictResp = make(map[string]string)
-	err = json.Unmarshal(binResp, &dictResp)
-	if err != nil {
-		return nil, fmt.Errorf("WebSocket.read(): in unmarshal binResp, err=\n\t%w", err)
-	}
-	return dictResp, nil
-}
-
-// Write -- потокобезопасная запись топика
-func (sf *WebSocket) Write(topic string, dictReq map[string]string) error {
-	sf.block.Lock()
-	defer sf.block.Unlock()
-	err := sf.write(topic, dictReq)
-	if err != nil {
-		return fmt.Errorf("WebSocket.Write(): in write, err=\n\t%w", err)
-	}
-	return nil
-}
-
-// Скрытая потоко-небезопасна функция
-func (sf *WebSocket) write(topic string, dictReq map[string]string) error {
-	dictReq["topic"] = topic
-	binData, err := json.Marshal(dictReq)
-	if err != nil {
-		return fmt.Errorf("WebSocket.write(): in marshal msg, err=\n\t%w", err)
-	}
-	for {
-		err = sf.ws.WriteMessage(TypeMsgBin, binData)
-		if err != nil {
-			sf.slog.Errorf("WebSocket.write(): in write msg, err=\n\t%v\n", err)
-			sf.isConnect.Reset()
-			sf.ws.Close()
-			sf.connect()
-			continue
-		}
-		return nil
-	}
-}
-
-// IsConnect -- потокобезопасный признак подключенности сервера
-func (sf *WebSocket) IsConnect() bool {
-	sf.block.RLock()
-	defer sf.block.RUnlock()
-	return sf.isConnect.Get()
-}
-
-// Call -- потокобезопасный вызов удалённого топика
-func (sf *WebSocket) Call(topic string, dictReq map[string]string) (dictResp map[string]string, err error) {
-	sf.block.Lock()
-	defer sf.block.Unlock()
-	var binResp []byte
-	for {
-		dictReq["topic"] = topic
-		binReq, err := json.Marshal(dictReq)
-		if err != nil {
-			return nil, fmt.Errorf("WebSocket.Call(): in marshall topic(%q), err=\n\t%w", topic, err)
-		}
-		err = sf.ws.WriteMessage(TypeMsgBin, binReq)
-		if err != nil {
-			sf.slog.Errorf("WebSocket.Call(): in write msg, err=\n\t%v\n", err)
-			sf.ws.Close()
-			sf.isConnect.Reset()
-			sf.connect()
-			continue
-		}
-
-		_, binResp, err = sf.ws.ReadMessage()
-		if err != nil {
-			sf.slog.Errorf("WebSocket.Call(): in read msg, err=\n\t%v\n", err)
-			sf.ws.Close()
-			sf.isConnect.Reset()
-			sf.connect()
-			continue
-		}
-		break
-	}
-	dictResp = make(map[string]string)
-	err = json.Unmarshal(binResp, &dictResp)
-	if err != nil {
-		return nil, fmt.Errorf("WebSocket.Call(): in unmarshal binResp, err=\n\t%w", err)
-	}
-	return dictResp, nil
-}
-
-// Потокобезопасное ожидание закрытия в отдельном потоке
-func (sf *WebSocket) close() {
-	<-sf.kern.Done()
-	sf.block.Lock()
-	defer sf.block.Unlock()
-	if !sf.isConnect.Get() {
-		return
-	}
-	sf.isConnect.Reset()
-	sf.ws.Close()
-}

+ 0 - 141
desktop/win_main/win_main.go

@@ -1,141 +0,0 @@
-// package win_main -- главное окно приложения
-package win_main
-
-import (
-	_ "embed"
-	"fmt"
-	"log"
-	"net/url"
-	"runtime"
-	"sync"
-	"time"
-
-	"github.com/zserge/lorca"
-
-	// "wartank/desktop/win_users"
-	"wartank/pkg/components/safebool"
-	"wartank/pkg/types"
-)
-
-const (
-	strWinMainName = "win_main" // Контрольная строка для сторожа потоков
-)
-
-//go:embed win_main.html
-var strWinHtml string
-
-// WinMain -- главное окно приложения
-type WinMain struct {
-	desktop types.IDesktop
-	store   types.IStore
-	win     lorca.UI
-	block   sync.Mutex
-	isWork  *safebool.SafeBool
-	ws      types.IWebSocket
-}
-
-// NewWinMain -- возвращает новое окно десктопа
-func NewWinMain(desktop types.IDesktop) (*WinMain, error) {
-	if desktop == nil {
-		return nil, fmt.Errorf("NewWinMain(): IDesktop == nil")
-	}
-	sf := &WinMain{
-		desktop: desktop,
-		store:   desktop.Store(),
-		isWork:  safebool.NewSafeBool(),
-		ws:      desktop.Ws(),
-	}
-	args := []string{}
-	if runtime.GOOS == "linux" {
-		args = append(args, "--class=Lorca")
-	}
-	var err error
-	sf.win, err = lorca.New("data:text/html,"+url.PathEscape(strWinHtml), "", 640, 480, args...)
-	if err != nil {
-		return nil, fmt.Errorf("NewWinMain(): in create win, err=\n\t%w", err)
-	}
-	go sf.close()
-	return sf, nil
-}
-
-// Работает в отдельном потоке, главный цикл окна
-func (sf *WinMain) Run() {
-	log.Println("WinMain.Run()")
-	sf.win.Bind("close_win", sf.onClose)
-	sf.win.Bind("bot_list", sf.onUsers)
-	go sf.timeServer()
-	<-sf.win.Done() // Ожидание закрытия окна
-	sf.desktop.CancelApp()
-}
-
-// Открывает окно с пользователями
-func (sf *WinMain) onUsers() {
-	log.Println("WinMain.onUsers()")
-	go sf.desktop.DictBot().Show()
-}
-
-// Проверяет наличие работающего сервера, работает в отдельном потоке
-func (sf *WinMain) timeServer() {
-	for {
-		time.Sleep(time.Second * 2)
-		timeBeg := time.Now().UTC().UnixMicro()
-		dictResp, err := sf.ws.Read("/server/time")
-		if err != nil {
-			log.Printf("WinMain.timeServer(): in send request to server, err=\n\t%v\n", err)
-			sf.desktop.CancelApp()
-			return
-		}
-		timeEnd := time.Now().UTC().UnixMicro() - timeBeg
-		strErr := dictResp["err"]
-		if strErr != "" {
-			js := fmt.Sprintf(`
-		function SetTimeServer(){
-			var _el = document.getById("/server/time");
-			_el.innerText=%q;
-		}
-		SetTimeServer()
-		`, err)
-			sf.win.Eval(js)
-			continue
-		}
-		strTime := dictResp["/server/time"]
-
-		js := fmt.Sprintf(`
-		function SetTimeServer(){
-			var _el = document.getElementById("/server/time");
-			_el.innerText=%q;
-		}
-		SetTimeServer()
-		`, strTime)
-		sf.win.Eval(js)
-
-		js = fmt.Sprintf(`
-		function SetPingServer(){
-			var _el = document.getElementById("/server/ping");
-			_el.innerText="%v мкСек";
-		}
-		SetPingServer()
-		`, timeEnd)
-		sf.win.Eval(js)
-	}
-}
-
-// Закрывает приложение
-func (sf *WinMain) onClose() {
-	log.Println("WinMain.onClose()")
-	sf.win.Close()
-}
-
-// close -- ожидает отмены глобального контекста
-func (sf *WinMain) close() {
-	<-sf.desktop.CtxApp().Done()
-	log.Println("WinMain.close()")
-	sf.block.Lock()
-	defer sf.block.Unlock()
-	if !sf.isWork.Get() {
-		return
-	}
-	sf.isWork.Reset()
-	sf.win.Close()
-	sf.desktop.Wg().Done(strWinMainName)
-}

+ 0 - 70
desktop/win_main/win_main.html

@@ -1,70 +0,0 @@
-<!DOCTYPE html>
-<html lang="ru">
-
-	<head>
-		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
-		<title>WarTank bot</title>
-		<meta name="author" content="SVI">
-		<style>
-			html {
-				height: 100%;
-			}
-
-			body {
-				margin: 0;
-				color: #fff;
-				/* Растягиваем body по высоте html */
-				min-height: 100%;
-				display: grid;
-				grid-template-rows: auto 1fr auto;
-			}
-
-			header {
-				background: rgb(88, 88, 184);
-			}
-
-			main {
-				background: rgb(141, 112, 112);
-			}
-
-			footer {
-				background: black;
-			}
-
-			.my-label {
-				display: inline-block;
-				background: rgb(12, 54, 56);
-				font-family: 'Courier New', Courier, monospace;
-				margin-top: 0.5em;
-				margin-left: 0.5em;
-			}
-		</style>
-	</head>
-
-	<body>
-		<header role="banner">
-			<b>WarTank bot [FunnySoft 2022]</b>
-		</header>
-		<main role="main">
-			<div id="status"><b>Статус:</b></div>
-			<div class="my-label">
-				Время сервера:<div id="/server/time"></div>
-			</div>
-			<div class="my-label">
-				Пинг сервера:<div id="/server/ping"></div>
-			</div>
-			<div class="my-label">
-				Аптайм сервера:<div id="/serv/uptime"></div>
-			</div>
-			<hr width="95%" height="4px">
-			<div>
-				<button type="button" name="users" value="Полз" onclick="bot_list()">Список ботов</button>
-				<button style="background:red;" type="button" name="close" value="Выход" onclick="close_win()">Выход</button>
-			</div>
-		</main>
-		<footer role="contentinfo">
-			<div class="footer">Для правильной работы программы необходимо запустить <code>server</code>.</div>
-		</footer>
-	</body>
-
-</html>

BIN
desktop_lorca.zip