瀏覽代碼

SVI Подгонка под kern

SVI 1 年之前
父節點
當前提交
26abf101ba
共有 86 個文件被更改,包括 679 次插入905 次删除
  1. 1 1
      Makefile
  2. 0 8
      app/lev0/types/_inetmarket.go
  3. 5 1
      app/lev0/types/iarena_net.go
  4. 1 1
      app/lev0/types/idict_bot.go
  5. 1 1
      app/lev0/types/idiv_war_scene.go
  6. 5 1
      app/lev0/types/inet_client.go
  7. 1 1
      app/lev0/types/iparser_simple.go
  8. 4 2
      app/lev0/types/iserv_bots.go
  9. 6 2
      app/lev0/types/iweb_socket.go
  10. 4 3
      app/lev1/health/health.go
  11. 4 3
      app/lev1/manevr/manevr.go
  12. 5 9
      app/lev1/product/parser_time/parse_hour/parse_hour.go
  13. 5 12
      app/lev1/product/parser_time/parse_min/parse_min.go
  14. 10 9
      app/lev1/product/parser_time/parse_min/parse_min_test.go
  15. 5 12
      app/lev1/product/parser_time/parse_sec/parse_sec.go
  16. 2 2
      app/lev1/product/parser_time/parse_sec/parse_sec_test.go
  17. 3 3
      app/lev1/shot/shot.go
  18. 1 1
      app/lev1/web_render/web_render.go
  19. 7 14
      app/lev2/arena/arena.go
  20. 8 10
      app/lev2/arena/arena_arsenal/arena_arsenal.go
  21. 16 15
      app/lev2/arena/arena_arsenal/bf_ammo_make/bf_ammo_make.go
  22. 1 1
      app/lev2/arena/arena_arsenal/bf_ammo_stat/bf_ammo_stat.go
  23. 3 5
      app/lev2/arena/arena_battle/bf_battle_register/bf_battle_register.go
  24. 3 9
      app/lev2/arena/arena_context/arena_state/arena_state.go
  25. 3 3
      app/lev2/arena/arena_convoy/bf_glory_take/bf_glory_take.go
  26. 4 3
      app/lev2/arena/arena_death/death_register/death_register.go
  27. 3 3
      app/lev2/arena/arena_death/death_worker/process_death/health/health.go
  28. 2 2
      app/lev2/arena/arena_death/death_worker/process_death/shot/shot.go
  29. 3 3
      app/lev2/arena/arena_division/div_war/div_war.go
  30. 3 3
      app/lev2/arena/arena_division/divwar/divwar.go
  31. 15 21
      app/lev2/arena/arena_fuel_duel/bf_fuel_duel/bf_fuel_duel.go
  32. 3 2
      app/lev2/arena/arena_market/bf_gold_by/bf_gold_by.go
  33. 2 4
      app/lev2/arena/arena_masters/bf_masters_register/bf_masters_register.go
  34. 24 12
      app/lev2/arena/arena_mine/bf_mine_make/bf_mine_make.go
  35. 52 52
      app/lev2/arena/arena_missions/bf_mission_simple/bf_misson_simple.go
  36. 5 4
      app/lev2/arena/arena_net/arena_net.go
  37. 5 10
      app/lev2/arena/arena_string/arena_string.go
  38. 11 11
      app/lev3/bot/bot.go
  39. 0 1
      app/lev3/bot/bot_net/bot_net_stat/bot_net_stat.go
  40. 9 8
      app/lev3/farm_bots/dict_bot/dict_bot.go
  41. 9 6
      app/lev3/farm_bots/farm_bots.go
  42. 1 1
      app/lev3/serv_web/web_gui/page_bot_add/page_bot_add.go
  43. 7 7
      app/lev3/server_stat/server_stat.go
  44. 1 1
      app/lev4/mod_serv/mod_serv.go
  45. 2 0
      doc/svi.md
  46. 5 3
      go.mod
  47. 6 6
      go.sum
  48. 14 30
      pkg/components/counttime/counttime.go
  49. 13 46
      pkg/components/counttime/counttime_test.go
  50. 9 18
      pkg/components/parsetime/parsehour/parsehour.go
  51. 7 19
      pkg/components/parsetime/parsehour/parsehour_test.go
  52. 9 18
      pkg/components/parsetime/parsemin/parsemin.go
  53. 5 15
      pkg/components/parsetime/parsemin/parsemin_test.go
  54. 9 18
      pkg/components/parsetime/parsesec/parsesec.go
  55. 6 16
      pkg/components/parsetime/parsesec/parsesec_test.go
  56. 10 24
      pkg/components/parsetime/parsetime.go
  57. 10 30
      pkg/components/parsetime/parsetime_test.go
  58. 1 1
      vendor/gitp78su.ipnodns.ru/svi/kern/Makefile
  59. 2 2
      vendor/gitp78su.ipnodns.ru/svi/kern/kc/helpers/helpers.go
  60. 0 74
      vendor/gitp78su.ipnodns.ru/svi/kern/kc/helpers/result.txt
  61. 20 0
      vendor/gitp78su.ipnodns.ru/svi/kern/kern.go
  62. 11 16
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/kbus/dict_topic_serve/dict_topic_serve.go
  63. 15 15
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/kbus/kbus_base/kbus_base.go
  64. 13 17
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/kbus/kbus_http/client_bus_http/client_bus_http.go
  65. 14 13
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/kbus/kbus_http/kbus_http.go
  66. 2 2
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/kctx/kernel_keeper/kernel_keeper.go
  67. 4 3
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/kctx/kwg/kwg.go
  68. 6 6
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/kmodule/kmodule.go
  69. 2 2
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/kserv_http/kserv_http.go
  70. 17 17
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/kstore_kv/kstore_kv.go
  71. 5 5
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/ikernel_bus.go
  72. 3 3
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/ikernel_store.go
  73. 1 1
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/ikernel_wg.go
  74. 74 0
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/koption.go
  75. 88 0
      vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/kresult.go
  76. 二進制
      vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb
  77. 3 0
      vendor/google.golang.org/protobuf/internal/filedesc/editions.go
  78. 16 0
      vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go
  79. 0 2
      vendor/google.golang.org/protobuf/internal/strs/strings_unsafe.go
  80. 0 94
      vendor/google.golang.org/protobuf/internal/strs/strings_unsafe_go120.go
  81. 1 1
      vendor/google.golang.org/protobuf/internal/version/version.go
  82. 6 0
      vendor/google.golang.org/protobuf/proto/merge.go
  83. 2 0
      vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go
  84. 0 2
      vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe.go
  85. 0 98
      vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go120.go
  86. 5 5
      vendor/modules.txt

+ 1 - 1
Makefile

@@ -38,7 +38,7 @@ test:
 mod:
 	clear
 	go get -u ./...
-	go mod tidy -compat=1.24.0
+	go mod tidy -compat=1.22.0
 	go mod vendor
 	go fmt ./...
 lint:

+ 0 - 8
app/lev0/types/_inetmarket.go

@@ -1,8 +0,0 @@
-package types
-
-/*
-	Интерфейс к сетевому рынку.
-*/
-
-// INetMarket -- интрфейс к сетевому рынку
-type _INetMarket interface{}

+ 5 - 1
app/lev0/types/iarena_net.go

@@ -1,9 +1,13 @@
 package types
 
+import (
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+)
+
 // ИАренаСеть -- сетевые операции арены
 type ИАренаСеть interface {
 	ИБотСеть
 	// Обновить -- обновляет список строк арены из сети
 	Обновить()
-	Get(strLink string) (lstString []string, err error)
+	Get(strLink string) Result[[]string]
 }

+ 1 - 1
app/lev0/types/idict_bot.go

@@ -1,6 +1,6 @@
 package types
 
-// ИСловарьБот -- интрефейс к словарю ботов
+// ИСловарьБот -- интерфейс к словарю ботов
 type ИСловарьБот interface {
 	// Показать -- показывает словарь ботов
 	Показать()

+ 1 - 1
app/lev0/types/idiv_war_scene.go

@@ -1,7 +1,7 @@
 package types
 
 /*
-	Интерфейс к битве дивизиий
+	Интерфейс к битве дивизий
 */
 
 // ИДивизияВойнаСцена -- интерфейс к битве дивизий

+ 5 - 1
app/lev0/types/inet_client.go

@@ -1,7 +1,11 @@
 package types
 
+import (
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+)
+
 // ИСетьКлиент -- интерфейс к GET-запросу
 type ИСетьКлиент interface {
 	// Get -- теневая функция на блокировку
-	Get(strLink string) (lstString []string, err error)
+	Get(strLink string) Result[[]string]
 }

+ 1 - 1
app/lev0/types/iparser_simple.go

@@ -4,7 +4,7 @@ import (
 	. "wartank/app/lev0/alias"
 )
 
-// ИПарсерПростой -- базовый интерфейс парсеру времени
+// ИПарсерПростой -- базовый интерфейс к парсеру времени
 type ИПарсерПростой interface {
 	// Уст -- устанавливает часы
 	Уст(АВремя)

+ 4 - 2
app/lev0/types/iserv_bots.go

@@ -1,6 +1,8 @@
 package types
 
 import (
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+
 	. "wartank/app/lev0/alias"
 )
 
@@ -9,9 +11,9 @@ type ИБотоФерма interface {
 	// Get -- возвращает бота по его имени
 	Get(botNumber АБотНомер) ИБот
 	// BotStart -- запускает бота в работу
-	BotStart(botNumber АБотНомер) error
+	BotStart(botNumber АБотНомер) Result[bool]
 	// ListBot -- возвращает список ботов
 	ListBot() []ИБот
 	// НовБот -- добавляет нового бота на бото-ферму
-	НовБот(login, password string, еслиАвто bool) error
+	НовБот(login, password string, еслиАвто bool) Result[bool]
 }

+ 6 - 2
app/lev0/types/iweb_socket.go

@@ -1,13 +1,17 @@
 package types
 
+import (
+	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
+)
+
 // ИВебСокет -- интерфейс к постоянному веб-сокету сервера
 type ИВебСокет interface {
 	// Записать -- записывает топик на сервер
 	Записать(topic string, dictReq map[string]string) error
 	// Читать -- читает топик с сервера
 	Читать(topic string) (mapResp map[string]string, err error)
-	// Вызвать -- вызывает худалённую процедуру
-	Вызвать(topic string, dictReq map[string]string) (mapResp map[string]string, err error)
+	// Вызвать -- вызывает удалённую процедуру
+	Вызвать(topic string, dictReq map[string]string) Result[map[string]string]
 	// ЕслиПодключ -- возвращает признак подключенности к серверу
 	ЕслиПодключ() bool
 }

+ 4 - 3
app/lev1/health/health.go

@@ -191,13 +191,14 @@ func (сам *Здоровье) repair() {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `" class="simple-but blue"><span><span>Ремкомплект</span></span></a>`)
 	strLink = "https://wartank.ru/" + lstLink[0]
-	lstBattleOn, err := сам.Сеть().Get(strLink)
-	if err != nil {
-		// log._rintf("ERRO Health.repair(): при выполнении GET-команды ремонта, err=\n\t%v\n", err)
+	res := сам.Сеть().Get(strLink)
+	if res.IsErr() {
+		// log._rintf("ERRO Health.repair(): при выполнении GET-команды ремонта, err=\n\t%v\n", res.Error())
 		сам.isEnd.Set()
 		сам.Отменить()
 		return
 	}
+	lstBattleOn = res.Unwrap()
 	сам.СтрОбновить(lstBattleOn)
 	// sound.Repair()
 }

+ 4 - 3
app/lev1/manevr/manevr.go

@@ -176,13 +176,14 @@ func (сам *манёвр) Выполнить() {
 		strLink := lstLink[1]
 		lstLink = strings.Split(strLink, `" class="simple-but blue"><span><span>Маневр</span></span></a>`)
 		strLink = "https://wartank.ru/" + lstLink[0]
-		lstBattleOn, err := сам.Сеть().Get(strLink)
-		if err != nil {
-			сам.лог.Err("манёвр.Выполнить(): при выполнении GET-команды маневра, ош=\n\t%v", err)
+		res := сам.Сеть().Get(strLink)
+		if res.IsErr() {
+			сам.лог.Err("манёвр.Выполнить(): при выполнении GET-команды маневра, ош=\n\t%v", res.Error())
 			сам.еслиГотов.Reset()
 			time.Sleep(time.Second * 1)
 			return
 		}
+		lstBattleOn = res.Unwrap()
 		сам.СтрОбновить(lstBattleOn)
 		// sound.манёвр()
 	}

+ 5 - 9
app/lev1/product/parser_time/parse_hour/parse_hour.go

@@ -63,22 +63,18 @@ func (сам *ПарсерЧас) Уст(часы АВремя) {
 	defer сам.блок.Unlock()
 	цЧасы, err := strconv.Atoi(string(часы))
 	Hassert(err == nil, "ПарсерЧас.Уст(): часы(%q) не число, err=\n\t%v", часы, err)
-	err = сам.уст(АЧас(цЧасы))
-	Hassert(err == nil, "ПарсерЧас.Уст(): in internal set hour(%q), err=\n\t%w", часы, err)
+	сам.уст(АЧас(цЧасы))
 }
 
 // УстЧас -- устанавливает числовое значение часов
-func (сам *ПарсерЧас) УстЧас(часы АЧас) error {
+func (сам *ПарсерЧас) УстЧас(часы АЧас) {
 	сам.блок.Lock()
 	defer сам.блок.Unlock()
-	if err := сам.уст(часы); err != nil {
-		return fmt.Errorf("ПарсерЧас.УстЧас(): in internal set hour(%v), err=\n\t%w", часы, err)
-	}
-	return nil
+	сам.уст(часы)
 }
 
 // Внутренняя процедура для числовой установки часов без блокировки
-func (сам *ПарсерЧас) уст(часы АЧас) error {
+func (сам *ПарсерЧас) уст(часы АЧас) {
+	Hassert(часы < 24, "ПарсерЧас.уст(): 0<hour(%q)>23", часы)
 	сам.знач = часы
-	return nil
 }

+ 5 - 12
app/lev1/product/parser_time/parse_min/parse_min.go

@@ -62,25 +62,18 @@ func (сам *ПарсерМинут) Уст(стрМин АВремя) {
 	_цМин, err := strconv.Atoi(string(стрМин))
 	Hassert(err == nil, "ПарсерМинут.Parse(): минуты(%v) не число, err=%v", стрМин, err)
 	цМин := АМин(_цМин)
-	err = сам.уст(цМин)
-	Hassert(err == nil, "ПарсерМинут.Parse(): in internal set, err=\n\t%v", err)
+	сам.уст(цМин)
 }
 
 // УстМин -- устанавливает целочисленное значение минут
-func (сам *ПарсерМинут) УстМин(цМин АМин) error {
+func (сам *ПарсерМинут) УстМин(цМин АМин) {
 	сам.блок.Lock()
 	defer сам.блок.Unlock()
-	if err := сам.уст(цМин); err != nil {
-		return fmt.Errorf("ПарсерМинут.Set(): in internal set, err=\n\t%w", err)
-	}
-	return nil
+	сам.уст(цМин)
 }
 
 // Внутренняя установка минут
-func (сам *ПарсерМинут) уст(цМин АМин) error {
-	if цМин >= 60 {
-		return fmt.Errorf("ПарсерМинут.уст(): минуты не в диапазоне(%v) 0..60", цМин)
-	}
+func (сам *ПарсерМинут) уст(цМин АМин) {
+	Hassert(цМин < 60, "ПарсерМинут.уст(): минуты не в диапазоне(%v) 0..60", цМин)
 	сам.знач = цМин
-	return nil
 }

+ 10 - 9
app/lev1/product/parser_time/parse_min/parse_min_test.go

@@ -34,19 +34,20 @@ func (сам *tester) set() {
 // Кривое число минут
 func (сам *tester) setBad1() {
 	сам.t.Logf("=setBad1=\n")
-	if err := сам.ph.УстМин(60); err == nil {
-		сам.t.Errorf("setBad1(): err==nil\n")
-	}
-	if strHour := сам.ph.String(); strHour != "08" {
-		сам.t.Errorf("setBad1(): strHour(%q)!='08'\n", strHour)
-	}
+	defer func() {
+		if _panic := recover(); _panic == nil {
+			сам.t.Fatalf("setBad1(): panic==nil")
+		}
+		if strHour := сам.ph.String(); strHour != "08" {
+			сам.t.Errorf("setBad1(): strHour(%q)!='08'\n", strHour)
+		}
+	}()
+	сам.ph.УстМин(60)
 }
 
 func (сам *tester) setGood1() {
 	сам.t.Logf("=setGood1=\n")
-	if err := сам.ph.УстМин(8); err != nil {
-		сам.t.Errorf("setGood1(): err=\n\t%v\n", err)
-	}
+	сам.ph.УстМин(8)
 	if strHour := сам.ph.String(); strHour != "08" {
 		сам.t.Errorf("setGood1(): strHour(%q)!='08'\n", strHour)
 	}

+ 5 - 12
app/lev1/product/parser_time/parse_sec/parse_sec.go

@@ -62,25 +62,18 @@ func (сам *ПарсерСекунд) Уст(стрСек АВремя) {
 	_цСек, err := strconv.Atoi(string(стрСек))
 	Hassert(err == nil, "ПарсерСекунд.Уст(): секунды(%v) не число, ош=\n\t%v", стрСек, err)
 	цСек := АСек(_цСек)
-	err = сам.уст(цСек)
-	Hassert(err == nil, "ПарсерСекунд.Уст(): при внутренней установке, ош=\n\t%v", err)
+	сам.уст(цСек)
 }
 
 // УстСек -- устанавливает хранимое значение секунд
-func (сам *ПарсерСекунд) УстСек(цСек АСек) error {
+func (сам *ПарсерСекунд) УстСек(цСек АСек) {
 	сам.блок.Lock()
 	defer сам.блок.Unlock()
-	if ош := сам.уст(цСек); ош != nil {
-		return fmt.Errorf("ПарсерСекунд.Уст(): при установке числа секунд, ош=\n\t%w", ош)
-	}
-	return nil
+	сам.уст(цСек)
 }
 
 // Внутренняя установка значения секунд
-func (сам *ПарсерСекунд) уст(цСек АСек) error {
-	if цСек >= 60 {
-		return fmt.Errorf("ПарсерСекунд.уст(): секунды(%v) не в диапазоне 0..60", цСек)
-	}
+func (сам *ПарсерСекунд) уст(цСек АСек) {
+	Hassert(цСек < 60, "ПарсерСекунд.уст(): сек(%v)<60", цСек)
 	сам.знач = цСек
-	return nil
 }

+ 2 - 2
app/lev1/product/parser_time/parse_sec/parse_sec_test.go

@@ -14,7 +14,7 @@ type tester struct {
 	ph *ПарсерСекунд
 }
 
-func TestParsesec(t *testing.T) {
+func TestParseSec(t *testing.T) {
 	test := &tester{
 		t: t,
 	}
@@ -32,7 +32,7 @@ func (сам *tester) set() {
 
 func (сам *tester) setGood1() {
 	сам.t.Logf("=setGood1=\n")
-	_ = сам.ph.УстСек(26)
+	сам.ph.УстСек(26)
 	if strHour := сам.ph.String(); strHour != "26" {
 		сам.t.Errorf("setGood1(): strHour(%q)!='26'\n", strHour)
 	}

+ 3 - 3
app/lev1/shot/shot.go

@@ -135,7 +135,6 @@ func (сам *выстрел) shot() {
 		strOut      string
 		lstBattle   = сам.СписПолучить()
 		еслиНайдено bool
-		err         error
 	)
 	// <a href="pve?6-26.ILinkListener-currentControl-attackRegularShellLink" class="simple-but gray"><span><span>ОБЫЧНЫЕ</span></span></a>
 	for _, strOut = range lstBattle {
@@ -153,13 +152,14 @@ func (сам *выстрел) shot() {
 	strLink := strings.TrimPrefix(strOut, `<a href="`)
 	strLink = strings.TrimSuffix(strLink, `" class="simple-but gray"><span><span>ОБЫЧНЫЕ</span></span></a>`)
 	strLink = "https://wartank.ru/" + strLink
-	lstBattle, err = сам.Сеть().Get(strLink)
-	if err != nil {
+	res := сам.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Shot.shot(): при исполнении GET-команды выстрела обычным снарядом, err=\n\t%v\n", err)
 		сам.isEnd.Set()
 		сам.Бот().КонтБот().Cancel()
 		return
 	}
+	lstBattle = res.Unwrap()
 	сам.СтрОбновить(lstBattle)
 	// sound.Shot()
 	сам.Манёвр()

+ 1 - 1
app/lev1/web_render/web_render.go

@@ -43,7 +43,7 @@ func (сам *ВебРендер) Получ() string {
 }
 
 // Доб -- добавляет блок замещения
-func (сам *ВебРендер) Доб(ключ string, блок interface{}) {
+func (сам *ВебРендер) Доб(ключ string, блок any) {
 	Hassert(ключ != "", "ВебРендер.Доб(): пустой ключ")
 	сам.слвБлок[ключ] = блок
 }

+ 7 - 14
app/lev2/arena/arena.go

@@ -3,14 +3,12 @@ package arena
 
 import (
 	"log"
-	"strings"
 
 	. "gitp78su.ipnodns.ru/svi/kern"
 	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
 	"wartank/app/lev0/alias"
-	"wartank/app/lev0/cons"
 	. "wartank/app/lev0/types"
 	"wartank/app/lev1"
 	"wartank/app/lev2/arena/arena_context"
@@ -78,17 +76,7 @@ func (сам *Арена) Обновить() {
 
 // СтрОбновить -- обновляет список строк секции по требованию
 func (сам *Арена) СтрОбновить(lstString []string) {
-	err := сам.списСтр.Set(lstString)
-	if err == nil {
-		return
-	}
-	еслиБаза := strings.Contains(err.Error(), "<title>База</title>")
-	еслиАпгрейд := сам.Состояние().Получ() == cons.РежимАпгрейд
-	еслиАпгрейдПлат := сам.Состояние().Получ() == cons.РежимАпгрейдПлатный
-	if еслиБаза || еслиАпгрейд || еслиАпгрейдПлат {
-		return
-	}
-	Hassert(err == nil, "Арена.СтрОбновить(): при установке lstString, err=\n\t%v", err)
+	сам.списСтр.Set(lstString)
 }
 
 // Уровень -- возвращает уровень арены
@@ -98,7 +86,12 @@ func (сам *Арена) Уровень() ИСтатПарам {
 
 // СписПолучить -- возвращает список строк секции
 func (сам *Арена) СписПолучить() []string {
-	return сам.списСтр.Получ()
+	lstString := сам.списСтр.Получ()
+	if len(lstString) == 0 {
+		сам.Обновить()
+		lstString = сам.СписПолучить()
+	}
+	return lstString
 }
 
 // Сеть -- возвращает объект сети

+ 8 - 10
app/lev2/arena/arena_arsenal/arena_arsenal.go

@@ -2,11 +2,6 @@
 package arena_arsenal
 
 import (
-	"log"
-	"strconv"
-	"strings"
-	"time"
-
 	. "gitp78su.ipnodns.ru/svi/kern"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
@@ -80,6 +75,8 @@ func (сам *АренаАрсенал) Пуск() {
 	bf_arsenal_take.АрсеналЗабрать(сам.конт)
 }
 
+//=============================
+/*
 // Проверяет необходимость постройки
 func (сам *АренаАрсенал) проверитьПостроить() bool {
 	сам.вЛог.Добавить("Арсенал.проверитьПостроить()\n")
@@ -276,14 +273,14 @@ func (сам *АренаАрсенал) забрать() bool {
 	strLink = "https://wartank.ru/" + lstLink[0]
 	var (
 		лстАрсенал []string
-		ош         error
 	)
 	time.Sleep(time.Millisecond * 100)
-	лстАрсенал, ош = сам.Сеть().Get(strLink)
-	if ош != nil {
-		log.Printf("Арсенал.забрать(): при выполнении Get-запроса? err=\n\t%v\n", ош)
+	res := сам.Сеть().Get(strLink)
+	if res.IsErr() {
+		log.Printf("Арсенал.забрать(): при выполнении Get-запроса? err=\n\t%v\n", res.Error())
 		return false
 	}
+	лстАрсенал = res.Unwrap()
 	if len(лстАрсенал) == 0 {
 		log.Printf("Арсенал.забрать(): len lstBase(%v)==0", len(lstBase))
 		return false
@@ -296,7 +293,8 @@ func (сам *АренаАрсенал) забрать() bool {
 	сам.СтрОбновить(лстАрсенал)
 	return true
 }
-
+*/
+//====================================
 // Фугасы -- возвращает объект числа фугасов
 func (сам *АренаАрсенал) Фугасы() ИСтатПарам {
 	return сам.фугас

+ 16 - 15
app/lev2/arena/arena_arsenal/bf_ammo_make/bf_ammo_make.go

@@ -35,27 +35,28 @@ func СнарядыСделать(конт ILocalCtx) {
 func приоритет(конт ILocalCtx) {
 	арсенал := конт.Get("арсенал").Val().(ИАренаАрсенал)
 	var (
-		ремкаКол  = арсенал.Ремки().Получ()
-		фугасКол  = арсенал.Фугасы().Получ()
-		кумульКол = арсенал.Кумулятивы().Получ()
-		ббКол     = арсенал.Бронебойки().Получ()
-		снарядТип string
+		ремки      = арсенал.Ремки().Получ()
+		фугасы     = арсенал.Фугасы().Получ()
+		кумули     = арсенал.Кумулятивы().Получ()
+		бронебойки = арсенал.Бронебойки().Получ()
+		снарядТип  string
 	)
-	if ремкаКол < 70 { // Контроль ремки по времени суток и минимальному количеству ремок
-		сделатьРемку(конт)
-		return
-	}
 	{ // Контроль по числу снарядов. В равных долях без приоритетов
 		// снарядТип = стрФугасы
 		снарядТип = стрБронебойки
-		if ббКол > фугасКол {
+		if бронебойки > фугасы {
 			снарядТип = стрФугасы
 		}
 
-		if фугасКол > кумульКол {
+		if фугасы > кумули {
 			снарядТип = стрКумулятивы
 		}
-
+		if фугасы > 0 {
+			if ремки < 120 { // Контроль ремки по времени суток и минимальному количеству ремок
+				сделатьРемку(конт)
+				return
+			}
+		}
 		switch снарядТип {
 		case стрФугасы: // Мало фугасов
 			сделатьФугасы(конт)
@@ -97,7 +98,7 @@ func сделатьБронебойки(конт ILocalCtx) {
 	strLink := lstArmor[1]
 	lstArmor = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
 	strLink = "https://wartank.ru/production/" + lstArmor[0]
-	if _, err := арсенал.Сеть().Get(strLink); err != nil {
+	if res := арсенал.Сеть().Get(strLink); res.IsErr() {
 		// log._rintf("ERRO ArsenalNet.makeArmor(): in update lstArsenal,  err=\n\t%v\n", err)
 		return
 	}
@@ -131,7 +132,7 @@ func сделатьКумули(конт ILocalCtx) {
 	strLink := списКумул[1]
 	списКумул = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
 	strLink = "https://wartank.ru/production/" + списКумул[0]
-	if _, err := арсенал.Сеть().Get(strLink); err != nil {
+	if res := арсенал.Сеть().Get(strLink); res.IsErr() {
 		// log._rintf("ERRO ArsenalNet.makeКумуль(): in make product arsenal кумуль , err=\n\t%v\n", err)
 		return
 	}
@@ -166,7 +167,7 @@ func сделатьФугасы(конт ILocalCtx) {
 	strLink := списКумул[1]
 	списКумул = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
 	strLink = "https://wartank.ru/production/" + списКумул[0]
-	if _, err := арсенал.Сеть().Get(strLink); err != nil {
+	if res := арсенал.Сеть().Get(strLink); res.IsErr() {
 		// log._rintf("ERRO ArsenalNet.makeФугас(): in make request arsenal product, err=\n\t%v\n", err)
 		return
 	}

+ 1 - 1
app/lev2/arena/arena_arsenal/bf_ammo_stat/bf_ammo_stat.go

@@ -20,7 +20,7 @@ func СнарядыСтат(конт ILocalCtx) {
 	}
 	арсенал := арсенал_.Val().(ИАренаАрсенал)
 
-	if арсенал.Состояние().Получ() != cons.РежимОжидание {
+	if арсенал.Состояние().Получ() == cons.РежимНеСуществует {
 		return
 	}
 	фугасыНайти(конт)

+ 3 - 5
app/lev2/arena/arena_battle/bf_battle_register/bf_battle_register.go

@@ -4,7 +4,6 @@ package bf_battle_register
 import (
 	"strings"
 
-	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
 	"wartank/app/lev0/cons"
@@ -43,7 +42,6 @@ func регистрация(конт ILocalCtx) {
 	// https://wartank.ru/pve?{count}-1.ILinkListener-currentOverview-apply
 	var (
 		лстСражение = битва.СписПолучить()
-		err         error
 	)
 	фнГеис := func() []string {
 		if len(лстСражение) == 0 { // Уже обратный отсчёт
@@ -65,10 +63,10 @@ func регистрация(конт ILocalCtx) {
 		стрСсылка = strings.TrimSuffix(стрСсылка, `"><span><span>Взвод, подъем! В атаку!</span></span></a>`)
 		стрСсылка = "https://wartank.ru/" + стрСсылка
 		// https://wartank.ru/pve?9-1.ILinkListener-currentOverview-apply
-		лстСражение, err = битва.Сеть().Get(стрСсылка)
-		Hassert(err == nil, "регистрация(): при регистрации на сражение, ош=\n\t%v", err)
+		res := битва.Сеть().Get(стрСсылка)
+		res.Hassert("регистрация(): при регистрации на сражение")
 		битва.Состояние().Уст(cons.РежимАпгрейдПлатный)
-		return лстСражение
+		return res.Unwrap()
 	}
 
 	битва.СтрОбновить(фнГеис())

+ 3 - 9
app/lev2/arena/arena_context/arena_state/arena_state.go

@@ -32,9 +32,7 @@ func (сам *АренаСостояние) Уст(состояние alias.АА
 	defer сам.block.Unlock()
 	switch сам.знач {
 	case cons.РежимНеСуществует:
-		if состояние != cons.РежимПостроено {
-			Hassert(false, "АренаСостояние.Уст(): нельзя из 'не существует' перейти в '%v'", состояние)
-		}
+		Hassert(состояние == cons.РежимПостроено, "АренаСостояние.Уст(): нельзя из 'не существует' перейти в '%v'", состояние)
 	case cons.РежимПостроено:
 		switch состояние {
 		case cons.РежимАпгрейд, cons.РежимАпгрейдПлатный, cons.РежимОжидание, cons.РежимРабота, cons.РежимЗабрать:
@@ -69,13 +67,9 @@ func (сам *АренаСостояние) Уст(состояние alias.АА
 			return
 		}
 	case cons.РежимРабота:
-		if состояние != cons.РежимЗабрать {
-			Hassert(false, "АренаСостояние.Уст(): нельзя из 'работа' перейти в '%v'", состояние)
-		}
+		Hassert(состояние == cons.РежимЗабрать, "АренаСостояние.Уст(): нельзя из 'работа' перейти в '%v'", состояние)
 	case cons.РежимЗабрать:
-		if состояние != cons.РежимОжидание {
-			Hassert(false, "АренаСостояние.Уст(): нельзя из 'забрать' перейти в '%v'", состояние)
-		}
+		Hassert(состояние == cons.РежимОжидание, "АренаСостояние.Уст(): нельзя из 'забрать' перейти в '%v'", состояние)
 	default:
 		Hassert(false, "АренаСостояние.Уст(): нельзя из '%v' перейти в '%v'", сам.знач, состояние)
 	}

+ 3 - 3
app/lev2/arena/arena_convoy/bf_glory_take/bf_glory_take.go

@@ -76,12 +76,12 @@ func проверитьМиссияМастерРазведки(конт ILocalC
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	// https://wartank.ru/convoy?61-1.ILinkListener-missions-cc-0-c-awardLink
 	strLink = "https://wartank.ru/" + lstLink[0]
-	lstConvoy, err := конвой.Сеть().Get(strLink)
-	if err != nil {
+	res := конвой.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Конвой.checkMaster(): при выполнении команды GET, err=\n\t%v\n", err)
 		return
 	}
-	конвой.СтрОбновить(lstConvoy)
+	конвой.СтрОбновить(res.Unwrap())
 }
 
 // Забирает награду в конвое "Уничтожь 6 врагов в конвое"

+ 4 - 3
app/lev2/arena/arena_death/death_register/death_register.go

@@ -44,10 +44,11 @@ func (сам *СхваткаРегистрация) Зарегистрирова
 		стрКонтроль := "" // "https://wartank.ru/dm?0-1.ILinkListener-currentOverview-apply"
 		for {
 			time.Sleep(time.Second * 1)
-			лстСражение, err := сам.Сеть().Get(стрСсылка)
-			if err != nil {
-				log.Printf("ERRO СхваткаРегистрация.Зарегистрироваться(): при выполнении GET-команды на подъём в атаку, err=\n\t%v\n", err)
+			res := сам.Сеть().Get(стрСсылка)
+			if res.IsErr() {
+				log.Printf("ERRO СхваткаРегистрация.Зарегистрироваться(): при выполнении GET-команды на подъём в атаку, err=\n\t%v\n", res.Error())
 			}
+			лстСражение := res.Unwrap()
 			if len(лстСражение) < 113 {
 				continue
 			}

+ 3 - 3
app/lev2/arena/arena_death/death_worker/process_death/health/health.go

@@ -90,10 +90,10 @@ func (сам *Здоровье) лечить() {
 	strLink := "https://wartank.ru/pve?19-{count}.ILinkListener-currentControl-repairLink"
 	// <a href="pve?6-26.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>Ремкомплект</span></span></a>
 	strLink = strings.ReplaceAll(strLink, "{count}", fmt.Sprint(сам.счётЛечить))
-	lstBattleOn, err := сам.Сеть().Get(strLink)
-	if err != nil {
+	res := сам.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Здоровье.repair(): при выполнении GET-команды ремонта, err=\n\t%v\n", err)
 		return
 	}
-	сам.СтрОбновить(lstBattleOn)
+	сам.СтрОбновить(res.Unwrap())
 }

+ 2 - 2
app/lev2/arena/arena_death/death_worker/process_death/shot/shot.go

@@ -80,8 +80,8 @@ func (сам *Выстрел) выстрел() {
 	strLink := "https://wartank.ru/pve?6-{count}.ILinkListener-currentControl-attackRegularShellLink"
 	strLink = strings.ReplaceAll(strLink, "{count}", fmt.Sprint(сам.выстрелСчёт))
 	сам.выстрелСчёт++
-	_, err := сам.Сеть().Get(strLink)
-	if err != nil {
+	res := сам.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Shot.shot(): при исполнении GET-команды выстрела обычным снарядом, err=\n\t%v\n", err)
 		return
 	}

+ 3 - 3
app/lev2/arena/arena_division/div_war/div_war.go

@@ -177,12 +177,12 @@ func (сам *DivWar) upDivWar() {
 	linkUp := lstUp[1]
 	lstUp = strings.Split(linkUp, `"><span><span>Взвод, подъем! В атаку!</span></span></a>`)
 	linkUp = "https://wartank.ru/" + lstUp[0]
-	lstDivWar, err := сам.net.Get(linkUp)
-	if err != nil {
+	res := сам.net.Get(linkUp)
+	if res.IsErr() {
 		// log._rintf("ERRO DivWar.upDivWar(): при выполнении GET-команды на подъём в атаку, err=\n\t%v\n", err)
 		return
 	}
-	сам.СтрОбновить(lstDivWar)
+	сам.СтрОбновить(res.Unwrap())
 }
 
 // Ведёт сражение

+ 3 - 3
app/lev2/arena/arena_division/divwar/divwar.go

@@ -171,12 +171,12 @@ func (сам *DivWar) upDivWar() {
 	linkUp := lstUp[1]
 	lstUp = strings.Split(linkUp, `"><span><span>Взвод, подъем! В атаку!</span></span></a>`)
 	linkUp = "https://wartank.ru/" + lstUp[0]
-	lstDivWar, err := сам.net.Get(linkUp)
-	if err != nil {
+	res := сам.net.Get(linkUp)
+	if res.IsErr() {
 		// log._rintf("ERRO DivWar.upDivWar(): при выполнении GET-команды на подъём в атаку, err=\n\t%v\n", err)
 		return
 	}
-	сам.СтрОбновить(lstDivWar)
+	сам.СтрОбновить(res.Unwrap())
 }
 
 // Ведёт сражение

+ 15 - 21
app/lev2/arena/arena_fuel_duel/bf_fuel_duel/bf_fuel_duel.go

@@ -2,7 +2,6 @@
 package bf_fuel_duel
 
 import (
-	"fmt"
 	"strings"
 
 	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
@@ -48,9 +47,9 @@ func начатьБой(конт ILocalCtx) []string {
 	списАнгар = strings.Split(бойСсылка, `"><span><span>В бой!</span></span></a>`)
 	бойСсылка = "https://wartank.ru/" + списАнгар[0]
 	арена := конт.Get("арена_топливо_бой").Val().(ИАренаСтроение)
-	списСтрБой, err := арена.Сеть().Get(бойСсылка)
-	Hassert(err == nil, "начатьБой(): in make GET-request to battle, err=\n\t%v", err)
-	return списСтрБой
+	res := арена.Сеть().Get(бойСсылка)
+	res.Hassert("начатьБой(): in make GET-request to battle")
+	return res.Unwrap()
 }
 
 // Выбирает первого более слабого противника и делает первый выстрел
@@ -76,9 +75,9 @@ func выбратьБойСлабый(конт ILocalCtx, списСтрБой [
 		ссылкаБой = "https://wartank.ru/" + списСтрБой[0]
 	}
 	аренаБой := конт.Get("арена_топливо_бой").Val().(ИАрена)
-	списСтрВыстрел1, err := аренаБой.Сеть().Get(ссылкаБой)
-	Hassert(err == nil, "makeSelectBattle(): in GET-response select battle tank, err=\n\t%v", err)
-	return списСтрВыстрел1
+	res := аренаБой.Сеть().Get(ссылкаБой)
+	res.Hassert("makeSelectBattle(): in GET-response select battle tank")
+	return res.Unwrap() // Первый выстрел
 }
 
 // Ведёт бой в 2 выстрела (здесь только 2 и 3 выстрел -- первый сделан при слабом противнике)
@@ -87,7 +86,7 @@ func сделатьВыстрелы(конт ILocalCtx, lstShoot2 []string) {
 	var списВыстрел3 []string // Тело страницы для третьего выстрела
 	аренаБой := конт.Get("арена_топливо_бой").Val().(ИАрена)
 	ангар := конт.Get("ангар").Val().(ИАренаАнгар)
-	фнВыстрел2 := func() (err error) { // Второй выстрел
+	фнВыстрел2 := func() { // Второй выстрел
 		// _mt.Println("\tAngarNet.makeShooting().fnShoot2()")
 		defer func() {
 
@@ -112,7 +111,7 @@ func сделатьВыстрелы(конт ILocalCtx, lstShoot2 []string) {
 			}
 			if strOut == "" { // Это ситуация для третьего выстрела
 				списВыстрел3 = lstShoot2
-				return nil
+				return
 			}
 			// Вырезать ссылку из строки
 			lstShoot2 = strings.Split(strOut, `<a class="simple-but border" href="`)
@@ -126,17 +125,15 @@ func сделатьВыстрелы(конт ILocalCtx, lstShoot2 []string) {
 			lstShoot2 = strings.Split(linkShoot2, `"><span><span>Добить</span></span></a>`)
 			linkShoot2 = "https://wartank.ru/" + lstShoot2[0]
 		}
-		_, err = аренаБой.Сеть().Get(linkShoot2)
-		Hassert(err == nil, "сделатьВыстрелы(): in Get-response shoot2, err=\n\t%v", err)
+		res := аренаБой.Сеть().Get(linkShoot2)
+		res.Hassert("сделатьВыстрелы(): in Get-response shoot2")
 
 		fuel := ангар.Топливо().Получ()
 		fuel -= 30
 		ангар.Топливо().Уст(fuel)
-		return nil
 	}
-	err := фнВыстрел2()
-	Hassert(err == nil, "сделатьВыстрелы(): при выполнении выстрел-2, ош=\n\t%v", err)
-	фнВыстрел3 := func() (err error) { // Третий выстрел
+	фнВыстрел2()
+	фнВыстрел3 := func() { // Третий выстрел
 		// _mt.Println("\tAngarNet.makeShooting().fnShoot3()")
 		defer func() {
 			_ = recover()
@@ -173,15 +170,12 @@ func сделатьВыстрелы(конт ILocalCtx, lstShoot2 []string) {
 			linkShoot3 = "https://wartank.ru/" + списВыстрел3[0]
 		}
 
-		if _, err = аренаБой.Сеть().Get(linkShoot3); err != nil {
-			return fmt.Errorf("ТопливоБой.makeShooting(): in Get-response shoot3, err=\n\t%w", err)
-		}
+		res := аренаБой.Сеть().Get(linkShoot3)
+		res.Hassert("ТопливоБой.makeShooting(): in Get-response shoot3")
 		fuel := ангар.Топливо().Получ()
 		fuel -= 30
 		ангар.Топливо().Уст(fuel)
-		return nil
 	}
-	err = фнВыстрел3()
-	Hassert(err == nil, "сделатьВыстрелы().фнВыстрел3(): при выстрел-3, ош=\n\t%v", err)
+	фнВыстрел3()
 	ангар.Обновить()
 }

+ 3 - 2
app/lev2/arena/arena_market/bf_gold_by/bf_gold_by.go

@@ -68,11 +68,12 @@ func золотоКупить(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить `)
 	strLink = "https://wartank.ru/" + lstLink[0]
-	lstMarket, err := рынок.Сеть().Get(strLink)
-	if err != nil {
+	res := рынок.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Market.buyGold(): при выполнении GET-команды на покупку золота, err=\n\t%v\n", err)
 		return
 	}
+	lstMarket = res.Unwrap()
 	for _, strOut = range lstMarket {
 		if strings.Contains(strOut, `Ошибка на сервере. Сообщение админу уже отправлено.`) {
 			// log._rintf("ERRO Market.buyGold(): при получении lstMarket, strHTML=%v, err=\nt%v\n", strOut, err)

+ 2 - 4
app/lev2/arena/arena_masters/bf_masters_register/bf_masters_register.go

@@ -4,7 +4,6 @@ package bf_masters_register
 import (
 	"strings"
 
-	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 
 	"wartank/app/lev0/cons"
@@ -41,7 +40,6 @@ func регистрация(конт ILocalCtx) {
 	битва := конт.Get("pvp").Val().(ИАренаСтроение)
 	var (
 		лстБитва  = битва.СписПолучить()
-		err       error
 		стрСсылка string
 	)
 	defer func() {
@@ -72,7 +70,7 @@ func регистрация(конт ILocalCtx) {
 	_стрСсылка = strings.TrimSuffix(_стрСсылка, `" class="simple-but border"><span><span>Участвовать в битве</span></span></a>`)
 	_стрСсылка = "https://wartank.ru/" + _стрСсылка
 	// https://wartank.ru/pvp?45-5.ILinkListener-joinLink
-	лстБитва, err = битва.Сеть().Get(_стрСсылка)
-	Hassert(err == nil, "регистрация(): при регистрации на сражение, ош=\n\t%v", err)
+	res := битва.Сеть().Get(_стрСсылка)
+	res.Hassert("регистрация(): при регистрации на сражение")
 	битва.Состояние().Уст(cons.РежимАпгрейдПлатный)
 }

+ 24 - 12
app/lev2/arena/arena_mine/bf_mine_make/bf_mine_make.go

@@ -67,7 +67,7 @@ func выбратьМеталл(конт ILocalCtx) error {
 				break
 			}
 		}
-		for _, strProd := range lstMine { // Проверить руду
+		for _, strProd := range lstMine { // Проверить железо
 			if strings.Contains(strProd, `<span class="green2">Железо</span><br/>`) {
 				диктПродукция["железо"] = true
 				break
@@ -85,9 +85,9 @@ func выбратьМеталл(конт ILocalCtx) error {
 				break
 			}
 		}
+		сам.ПродуктСейчас().ИмяУст("руда")
 	}
 	фнВыбратьПродукт()
-	сам.ПродуктСейчас().ИмяУст("руда")
 	руда := сам.Руда().Получ()
 	железо := сам.Железо().Получ()
 	if диктПродукция["железо"] {
@@ -108,6 +108,12 @@ func выбратьМеталл(конт ILocalCtx) error {
 		if сталь > свинец*2 {
 			сам.ПродуктСейчас().ИмяУст("свинец")
 		}
+		// Свинец долго делать, больше 100 не надо, а руду хоть продать можно.
+		// 6 руды в час по 5 серебра = 180 серебра в сутки
+		// Свинец -- 1 за 22 часа = примерно 102 серебра в сутки
+		if свинец >= 100 {
+			сам.ПродуктСейчас().ИмяУст("руда")
+		}
 	}
 	return nil
 }
@@ -115,8 +121,8 @@ func выбратьМеталл(конт ILocalCtx) error {
 // Создаёт руду
 func рудаСделать(конт ILocalCtx) bool {
 	сам := конт.Get("шахта").Val().(ИАренаШахта)
-	lstMine, err := сам.Сеть().Get("https://wartank.ru/production/Mine")
-	if err != nil {
+	res := сам.Сеть().Get("https://wartank.ru/production/Mine")
+	if res.IsErr() {
 		// log._rintf("ERRO Шахта.сделатьРуду(): при GET-команде 'начать производство руды', err=\n\t%v\n", err)
 		return false
 	}
@@ -127,7 +133,9 @@ func рудаСделать(конт ILocalCtx) bool {
 		strLink     string
 		strNum      string
 		еслиНайдено bool
+		lstMine     = res.Unwrap()
 	)
+
 	for инд, стрВых = range lstMine {
 		if strings.Contains(стрВых, `<span class="green2">Руда</span><br/>`) { // <span class="green2">Руда</span><br/>
 			strNum = lstMine[инд+1]
@@ -149,11 +157,12 @@ func рудаСделать(конт ILocalCtx) bool {
 	_link = strings.TrimSuffix(_link, "\"><span><span>Начать производство</span></span></a>")
 	strLink = "https://wartank.ru/production/" + _link
 	// https://wartank.ru/production/Mine?19-1.ILinkListener-productions-0-production-startProduceLink
-	lstMine, err = сам.Сеть().Get(strLink)
-	if err != nil {
+	res = сам.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Шахта.сделатьРуду(): при GET-команде 'начать производство руды', err=\n\t%v\n", err)
 		return false
 	}
+	lstMine = res.Unwrap()
 	for _, стрВых = range lstMine {
 		if strings.Contains(стрВых, `><span><span>Начать производство</span></span></a>`) {
 			return false
@@ -207,11 +216,12 @@ func железоСделать(конт ILocalCtx) bool {
 	lstLink = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
 	strLink = "https://wartank.ru/production/" + lstLink[0]
 	// https://wartank.ru/production/Mine?4-1.ILinkListener-productions-1-production-startProduceLink
-	lstMine, err := сам.Сеть().Get(strLink)
-	if err != nil {
+	res := сам.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO MineNet.makeFerrum(): при GET-команде 'начать производство железа', err=\n\t%v\n", err)
 		return false
 	}
+	lstMine = res.Unwrap()
 	for _, strOut := range lstMine { // Проверка на базу
 		if strings.Contains(strOut, `<title>База</title>`) {
 			// log._rintf("ERRO MineNet.makeFerrum(): при обновлении lstMine найден lstBase")
@@ -262,11 +272,12 @@ func стальСделать(конт ILocalCtx) bool {
 	strLink = lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
 	strLink = "https://wartank.ru/production/" + lstLink[0]
-	lstMine, err := сам.Сеть().Get(strLink)
-	if err != nil {
+	res := сам.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO MineNet.makeSteel(): при GET-команде 'начать производство стали', err=\n\t%v\n", err)
 		return false
 	}
+	lstMine = res.Unwrap()
 	for _, strOut := range lstMine { // Проверка на базу
 		if strings.Contains(strOut, `<title>База</title>`) {
 			// log._rintf("ERRO MineNet.makeSteel(): при обновлении lstMine найден lstBase")
@@ -317,11 +328,12 @@ func свинецСделать(конт ILocalCtx) bool {
 	strLink = lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Начать производство</span></span></a>`)
 	strLink = "https://wartank.ru/production/" + lstLink[0]
-	lstMine, err := сам.Сеть().Get(strLink)
-	if err != nil {
+	res := сам.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Шахта.сделатьСвинец(): при GET-команде 'начать производство стали', err=\n\t%v\n", err)
 		return false
 	}
+	lstMine = res.Unwrap()
 	for _, strOut := range lstMine { // Проверка на базу
 		if strings.Contains(strOut, `<title>База</title>`) {
 			// log._rintf("ERRO Шахта.сделатьСвинец(): при обновлении lstMine найден lstBase")

+ 52 - 52
app/lev2/arena/arena_missions/bf_mission_simple/bf_misson_simple.go

@@ -14,18 +14,18 @@ func МиссииПростыеЗабрать(конт ILocalCtx) {
 	сражениеЗащита(конт)
 	сражениеНаступление(конт)
 	проведиВойну(конт)
-	battle5Fiting(конт)
-	battle6win(конт)
-	battle10Fiting(конт)
-	battleDogFyting(конт)
-	makeResource(конт)
-	kill3tanks(конт)
+	подряд5побед(конт)
+	подряд6побед(конт)
+	подряд10побед(конт)
+	победаСхватка(конт)
+	сделать10ресурсов(конт)
+	убить3танка(конт)
 	топливоДив(конт)
 	upMan(конт)
 }
 
 // Проверяет награду за уничтожить 3 танка в бою
-func kill3tanks(конт ILocalCtx) {
+func убить3танка(конт ILocalCtx) {
 	арена := конт.Get("миссии_простые").Val().(ИАрена)
 	var (
 		strOut      string
@@ -52,12 +52,12 @@ func kill3tanks(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
-		// log._rintf("ERRO Миссии.kill3tanks(): при выполнении GET-запроса, err=\n\t%v\n", err)
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
+		// log._rintf("ERRO Миссии.убить3танка(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 }
 
 // Проверяет награду оборонительного сражения
@@ -84,12 +84,12 @@ func сражениеЗащита(конт ILocalCtx) {
 	_ссылка := strings.TrimPrefix(strOut, `<a class="simple-but border" href="`)
 	_ссылка = strings.TrimSuffix(_ссылка, `"><span><span>Получить награду</span></span></a>`)
 	strLink := "https://wartank.ru/missions/" + _ссылка
-	списМиссия, err := арена.Сеть().Get(strLink)
-	if err != nil {
-		// log._rintf("ERRO Миссии.battleDefence(): при выполнении GET-запроса, err=\n\t%v\n", err)
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
+		// log._rintf("ERRO Миссии.сражениеЗащита(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(списМиссия)
+	арена.СтрОбновить(res.Unwrap())
 }
 
 // Проверяет награду за одну войну
@@ -120,12 +120,12 @@ func проведиВойну(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Миссии.battleWar(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 }
 
 // Проверяет награду наступательного сражения
@@ -162,16 +162,16 @@ func сражениеНаступление(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Миссии.battleAttack(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 }
 
 // Проверяет награду за схватку
-func battleDogFyting(конт ILocalCtx) {
+func победаСхватка(конт ILocalCtx) {
 	арена := конт.Get("миссии_простые").Val().(ИАрена)
 	var (
 		strOut      string
@@ -198,16 +198,16 @@ func battleDogFyting(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
-		// log._rintf("ERRO Миссии.battleDogFyting(): при выполнении GET-запроса, err=\n\t%v\n", err)
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
+		// log._rintf("ERRO Миссии.победаСхватка(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 }
 
 // Проверяет награду за ресурсы
-func makeResource(конт ILocalCtx) {
+func сделать10ресурсов(конт ILocalCtx) {
 	арена := конт.Get("миссии_простые").Val().(ИАрена)
 	var (
 		strOut      string
@@ -234,12 +234,12 @@ func makeResource(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
-		// log._rintf("ERRO Миссии.makeResource(): при выполнении GET-запроса, err=\n\t%v\n", err)
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
+		// log._rintf("ERRO Миссии.сделать10ресурсов(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 }
 
 // Проверяет награду за ресурсы
@@ -270,12 +270,12 @@ func upMan(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Миссии.upMan(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 	// log._rintf("INFO Миссии.upMan(): награда получена\n")
 }
 
@@ -307,16 +307,16 @@ func топливоДив(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
 		// log._rintf("ERRO Миссии.makeFuel(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 }
 
 // Проверяет награду 5 боёв
-func battle5Fiting(конт ILocalCtx) {
+func подряд5побед(конт ILocalCtx) {
 	арена := конт.Get("миссии_простые").Val().(ИАрена)
 	var (
 		strOut      string
@@ -343,16 +343,16 @@ func battle5Fiting(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
-		// log._rintf("ERRO Миссии.battle5Fiting(): при выполнении GET-запроса, err=\n\t%v\n", err)
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
+		// log._rintf("ERRO Миссии.подряд5побед(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 }
 
 // Проверяет награду 10 боёв
-func battle10Fiting(конт ILocalCtx) {
+func подряд10побед(конт ILocalCtx) {
 	арена := конт.Get("миссии_простые").Val().(ИАрена)
 	var (
 		strOut      string
@@ -379,16 +379,16 @@ func battle10Fiting(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
-		// log._rintf("ERRO Миссии.battle10Fiting(): при выполнении GET-запроса, err=\n\t%v\n", err)
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
+		// log._rintf("ERRO Миссии.подряд10побед(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 }
 
 // Проверяет награду за 6 побед подряд
-func battle6win(конт ILocalCtx) {
+func подряд6побед(конт ILocalCtx) {
 	арена := конт.Get("миссии_простые").Val().(ИАрена)
 	var (
 		strOut      string
@@ -415,10 +415,10 @@ func battle6win(конт ILocalCtx) {
 	strLink := lstLink[1]
 	lstLink = strings.Split(strLink, `"><span><span>Получить награду</span></span></a>`)
 	strLink = "https://wartank.ru/missions/" + lstLink[0]
-	lstMissions, err := арена.Сеть().Get(strLink)
-	if err != nil {
-		// log._rintf("ERRO Миссии.battle6win(): при выполнении GET-запроса, err=\n\t%v\n", err)
+	res := арена.Сеть().Get(strLink)
+	if res.IsErr() {
+		// log._rintf("ERRO Миссии.подряд6побед(): при выполнении GET-запроса, err=\n\t%v\n", err)
 		return
 	}
-	арена.СтрОбновить(lstMissions)
+	арена.СтрОбновить(res.Unwrap())
 }

+ 5 - 4
app/lev2/arena/arena_net/arena_net.go

@@ -52,13 +52,14 @@ func (сам *АренаСеть) Обновить() {
 }
 
 // Get -- выполняет GET-запрос по указанному URL
-func (сам *АренаСеть) Get(strLink string) (lstString []string, err error) {
+func (сам *АренаСеть) Get(strLink string) Result[[]string] {
 	сам.блок.Lock()
 	defer сам.блок.Unlock()
 	// log._rintf("INFO АренаСеть.Get(): link=%v\n", сам.strUrl)
 	if !strings.Contains(strLink, сам.стрУрл) {
-		return nil, fmt.Errorf("АренаСеть.Get(): strLink(%v) не содержит strUrl(%v)", strLink, сам.стрУрл)
+		err := fmt.Errorf("АренаСеть.Get(): strLink(%v) не содержит strUrl(%v)", strLink, сам.стрУрл)
+		return NewErr[[]string](err)
 	}
-	lstString = сам.клиент.Получ(strLink)
-	return lstString, nil
+	lstString := сам.клиент.Получ(strLink)
+	return NewOk(lstString)
 }

+ 5 - 10
app/lev2/arena/arena_string/arena_string.go

@@ -2,7 +2,6 @@
 package arena_string
 
 import (
-	"fmt"
 	"strings"
 	"sync"
 
@@ -38,15 +37,11 @@ func (сам *АренаСтроки) Получ() []string {
 }
 
 // Set -- устанавливает список строк для анализа
-func (сам *АренаСтроки) Set(lstString []string) error {
+func (сам *АренаСтроки) Set(lstString []string) {
 	сам.block.Lock()
 	defer сам.block.Unlock()
-	if lstString == nil {
-		return fmt.Errorf("АренаСтроки.Set(): lstString == nil")
-	}
-	if len(lstString) == 0 {
-		return fmt.Errorf("АренаСтроки.Set(): lstString ничего не содержит")
-	}
+	Hassert(lstString != nil, "АренаСтроки.Set(): lstString == nil")
+	Hassert(len(lstString) > 0, "АренаСтроки.Set(): lstString ничего не содержит")
 	isOk := false
 	for _, strControl := range lstString {
 		if strings.Contains(strControl, сам.strControl) {
@@ -56,7 +51,7 @@ func (сам *АренаСтроки) Set(lstString []string) error {
 	}
 	if isOk {
 		сам.val = lstString
-		return nil
+		return
 	}
 	// Найти заголовок
 	var strOut string
@@ -65,5 +60,5 @@ func (сам *АренаСтроки) Set(lstString []string) error {
 			break
 		}
 	}
-	return fmt.Errorf("АренаСтроки.Set(): lstString не имеет правильный title(%q), фактически(%q)", сам.strControl, strOut)
+	Hassert(false, "АренаСтроки.Set(): lstString не имеет правильный title(%q), фактически(%q)", сам.strControl, strOut)
 }

+ 11 - 11
app/lev3/bot/bot.go

@@ -3,7 +3,6 @@ package bot
 
 import (
 	"fmt"
-	"strings"
 	"time"
 
 	. "gitp78su.ipnodns.ru/svi/kern"
@@ -56,15 +55,16 @@ func ЗагрузитьВарБот(номер АБотНомер) *Бот {
 	лог.Info("ЗагрузитьВарБот(): номер=%q\n", стрНомер)
 	конт := GetKernelCtx()
 	хран := конт.Get("kernStoreKV").Val().(IKernelStoreKv)
-	binData, err := хран.Get("/bots/" + стрНомер)
-	if err != nil {
-		if !strings.Contains(err.Error(), "not found") {
-			Hassert(false, "ЗагрузитьВарБот(): in load bot '%v' from store, err=\n\t%v\n", номер, err)
-		}
-		Hassert(err == nil, "ЗагрузитьВарБот(): in load bot '%v' from store, err=\n\t%v\n", номер, err)
-	}
+	res := хран.Get("/bots/" + стрНомер)
+	// if res.IsErr() {
+	// 	if !strings.Contains(res.Error().Error(), "not found") {
+	// 		Hassert(false, "ЗагрузитьВарБот(): bot not found '%v' from store, err=\n\t%v\n", номер, res.Error())
+	// 	}
+	// 	Hassert(err == nil, "ЗагрузитьВарБот(): in load bot '%v' from store, err=\n\t%v\n", номер, err)
+	// }
+	res.Hassert("ЗагрузитьВарБот(): in load bot '%v' from store", номер)
 	конфиг := &bot_config.БотКонфиг{}
-	конфиг.Unmarshal(binData)
+	конфиг.Unmarshal(res.Unwrap())
 	сам := создатьЯдроВарБот(конфиг)
 	go сам.рестарт()
 	_ = ИБот(сам)
@@ -233,8 +233,8 @@ func (сам *Бот) автозапускИзм(знач bool) {
 func (сам *Бот) сохрКонфиг() {
 	strConf := сам.конфиг.Marshall()
 	стрНомер := fmt.Sprint(сам.Номер())
-	err := сам.хран.Set("/bots/"+стрНомер, strConf)
-	Hassert(err == nil, "ВарБот.сохрКонфиг(): err=\n\t%v\n", err)
+	res := сам.хран.Set("/bots/"+стрНомер, strConf)
+	res.Hassert("ВарБот.сохрКонфиг(): при установке номера")
 }
 
 // КонтБот -- возвращает контекст бота

+ 0 - 1
app/lev3/bot/bot_net/bot_net_stat/bot_net_stat.go

@@ -192,7 +192,6 @@ func (сам *БотСетьСтат) findLevelTank() {
 // Ищет в теле текста ангара прогресс уровня танка танка
 func (сам *БотСетьСтат) findLevelProgress() {
 	lstAngar := сам.ангар.СписПолучить()
-	Hassert(len(lstAngar) != 0, "lstAngar пустой")
 	var strOut string
 	for _, strProg := range lstAngar {
 		if strings.Contains(strProg, `class="progr"`) {

+ 9 - 8
app/lev3/farm_bots/dict_bot/dict_bot.go

@@ -1,4 +1,4 @@
-// package dict_warbot -- потокобезопасный словарь ботов
+// package dict_bot -- потокобезопасный словарь ботов
 package dict_bot
 
 import (
@@ -82,21 +82,22 @@ func (сам *СловарьБотов) save() {
 		strNumber += fmt.Sprint(botNumber) + ";"
 	}
 	strNumber = strNumber[:len(strNumber)-1]
-	err := сам.хран.Set(strBotList, []byte(strNumber))
-	if err != nil {
+	res := сам.хран.Set(strBotList, []byte(strNumber))
+	if res.IsErr() {
 		сам.конт.Cancel()
 	}
 }
 
 // Загружает всех ботов с базы
 func (сам *СловарьБотов) load() {
-	binNumber, err := сам.хран.Get(strBotList)
-	if err != nil {
-		if !strings.Contains(err.Error(), "not found") {
-			Hassert(false, "СловарьБотов.load(): при загрузке списка ботов, ош=\n\t%n\t", err)
+	res := сам.хран.Get(strBotList)
+	if res.IsErr() {
+		if !strings.Contains(res.Error().Error(), "not found") {
+			res.Hassert("СловарьБотов.load(): при загрузке списка ботов")
 		}
+		return
 	}
-	strNumbers := string(binNumber)
+	strNumbers := string(res.Unwrap())
 	if strNumbers == "" {
 		return
 	}

+ 9 - 6
app/lev3/farm_bots/farm_bots.go

@@ -33,6 +33,7 @@ func НовБотоФерма() *БотоФерма {
 		хран: конт.Get("kernStoreKV").Val().(IKernelStoreKv),
 	}
 	сам.словБот = dict_bot.НовСловарьБотов(конт)
+	_ = ИБотоФерма(сам)
 	return сам
 }
 
@@ -43,13 +44,14 @@ func (сам *БотоФерма) Get(botNumber АБотНомер) ИБот {
 }
 
 // BotStart -- запускает бота в работу по его имени
-func (сам *БотоФерма) BotStart(botNumber АБотНомер) error {
+func (сам *БотоФерма) BotStart(botNumber АБотНомер) Result[bool] {
 	bot := сам.словБот.Get(botNumber)
 	if bot == nil {
-		return fmt.Errorf("ServBots.BotStart(): bot(%v) not found", botNumber)
+		err := fmt.Errorf("ServBots.BotStart(): bot(%v) not found", botNumber)
+		return NewErr[bool](err)
 	}
 	bot.Пуск()
-	return nil
+	return NewOk(true)
 }
 
 // ListBot -- возвращает список существующих ботов
@@ -59,11 +61,12 @@ func (сам *БотоФерма) ListBot() []ИБот {
 }
 
 // НовБот -- добавляет нового бота на ферму
-func (сам *БотоФерма) НовБот(логин, пароль string, еслиАвто bool) error {
+func (сам *БотоФерма) НовБот(логин, пароль string, еслиАвто bool) Result[bool] {
 	{ // Существует ли такой бот
 		for _, бот := range сам.словБот.ListBot() {
 			if бот.Имя() == логин {
-				return nil
+				err := fmt.Errorf("БотоФерма.НовБот(): логин(%v) уже существует", логин)
+				return NewErr[bool](err)
 			}
 		}
 	}
@@ -82,5 +85,5 @@ func (сам *БотоФерма) НовБот(логин, пароль string,
 	// Нет такого бота, надо его создать
 	бот := bot.НовВарБот(сам.конт, номер, логин, пароль, еслиАвто)
 	сам.словБот.Add(бот)
-	return nil
+	return NewOk(true)
 }

+ 1 - 1
app/lev3/serv_web/web_gui/page_bot_add/page_bot_add.go

@@ -57,7 +57,7 @@ func (сам *СтраницаБотаДобавить) постДобавить
 	if запрос.Пароль == "" {
 		return кнт.Redirect("/gui/bot/add", http.StatusSeeOther)
 	}
-	if ош := сам.прилож.ServBots().НовБот(запрос.Логин_, запрос.Пароль, true); ош != nil {
+	if res := сам.прилож.ServBots().НовБот(запрос.Логин_, запрос.Пароль, true); res.IsErr() {
 		return кнт.Redirect("/gui/bot/add", http.StatusSeeOther)
 	}
 	return кнт.Redirect("/", http.StatusSeeOther)

+ 7 - 7
app/lev3/server_stat/server_stat.go

@@ -47,14 +47,14 @@ func НовСерверСтат() *СерверСтат {
 // Загружает статистику сервера
 func (сам *СерверСтат) загр() {
 	store := сам.конт.Get("kernStoreKV").Val().(IKernelStoreKv)
-	бинДанные, ош := store.Get("server_stat")
-	if ош != nil {
-		if strings.Contains(ош.Error(), "not found") {
+	res := store.Get("server_stat")
+	if res.IsErr() {
+		if strings.Contains(res.Error().Error(), "not found") {
 			return
 		}
-		Hassert(false, "СерверСтат.загр(): при загрузке статистики из хранилища, ош=\n\t%v\n", ош)
+		Hassert(false, "СерверСтат.загр(): при загрузке статистики из хранилища, ош=\n\t%v\n", res.Error())
 	}
-	ош = json.Unmarshal(бинДанные, сам)
+	ош := json.Unmarshal(res.Unwrap(), сам)
 	Hassert(ош == nil, "СерверСтат.загр(): при декодировании статистики из JSON, ош=\n\t%v\n", ош)
 	go сам.пуск()
 }
@@ -87,8 +87,8 @@ func (сам *СерверСтат) сохр() {
 		бинДанные, ош := json.Marshal(сам)
 		Hassert(ош == nil, "СерверСтат.сохр(): при кодировании статистики в JSON, ош=\n\t%v\n", ош)
 		store := сам.конт.Get("kernStoreKV").Val().(IKernelStoreKv)
-		ош = store.Set("server_stat", бинДанные)
-		Hassert(ош == nil, "СерверСтат.сохр(): при сохранении статистики в хранилище, ош=\n\t%v\n", ош)
+		res := store.Set("server_stat", бинДанные)
+		res.Hassert("СерверСтат.сохр(): при сохранении статистики в хранилище")
 	}
 	фнСохр()
 }

+ 1 - 1
app/lev4/mod_serv/mod_serv.go

@@ -18,7 +18,7 @@ import (
 type МодульСервер struct {
 	IKernelModule
 	конт      IKernelCtx
-	ботоФерма *farm_bots.БотоФерма
+	ботоФерма ИБотоФерма
 	сервСтат  ИСерверСтат
 	лог       ILogBuf
 }

+ 2 - 0
doc/svi.md

@@ -48,6 +48,8 @@ export NFQWS_OPT="
 
 ## Языковые модели
 
+https://www.youtube.com/watch?v=dbSyu26x4aM 1С песня
+
 ```text
 llama3.1:8b
 qwen2.5-coder:1.5b-base

+ 5 - 3
go.mod

@@ -2,9 +2,11 @@ module wartank
 
 go 1.24.0
 
+toolchain go1.24.1
+
 require (
 	github.com/gofiber/fiber/v2 v2.52.6
-	gitp78su.ipnodns.ru/svi/kern v1.11.0
+	gitp78su.ipnodns.ru/svi/kern v1.15.0
 )
 
 require (
@@ -32,7 +34,7 @@ require (
 	go.opentelemetry.io/otel v1.35.0 // indirect
 	go.opentelemetry.io/otel/metric v1.35.0 // indirect
 	go.opentelemetry.io/otel/trace v1.35.0 // indirect
-	golang.org/x/net v0.37.0 // indirect
+	golang.org/x/net v0.38.0 // indirect
 	golang.org/x/sys v0.31.0 // indirect
-	google.golang.org/protobuf v1.36.5 // indirect
+	google.golang.org/protobuf v1.36.6 // indirect
 )

+ 6 - 6
go.sum

@@ -55,8 +55,8 @@ github.com/valyala/fasthttp v1.59.0/go.mod h1:GTxNb9Bc6r2a9D0TWNSPwDz78UxnTGBViY
 github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
 github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-gitp78su.ipnodns.ru/svi/kern v1.11.0 h1:h7VGleV9VrdDBAyK/U+wXNEtbJlpVDgFOO7QIRJpFWQ=
-gitp78su.ipnodns.ru/svi/kern v1.11.0/go.mod h1:+8wsxQThUx9wegfPZffhRJx+s+hnyDHv4n3ODMQm6+w=
+gitp78su.ipnodns.ru/svi/kern v1.15.0 h1:wwCiHyDBthHNX1emlDooXkBrQV3z7axUfog/NZS6BV4=
+gitp78su.ipnodns.ru/svi/kern v1.15.0/go.mod h1:fjY82pQa1UeGRC1CbqV0g0+ZttDKVCOsqbuDUEpPedM=
 go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
 go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
 go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
@@ -72,8 +72,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
-golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
+golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
+golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -91,8 +91,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
-google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=

+ 14 - 30
pkg/components/counttime/counttime.go

@@ -1,8 +1,6 @@
 package counttime
 
 import (
-	"fmt"
-	// "log"
 	"sync"
 	"time"
 
@@ -90,8 +88,7 @@ func (sf *CountTime) run() {
 		if sf.timeTarget.Get() > int(timeNow) {
 			val := sf.timeTarget.Get() - int(timeNow)
 			val -= 1
-			err := sf.Set(val)
-			Hassert(err == nil, "err=%v", err)
+			sf.Set(val)
 			continue
 		}
 		sf.chCall <- 1
@@ -111,59 +108,46 @@ func (sf *CountTime) Get() int {
 }
 
 // Parse -- устанавливает число оставшихся сек
-func (sf *CountTime) Parse(val string) error {
+func (sf *CountTime) Parse(val string) {
 	sf.block.Lock()
 	defer sf.block.Unlock()
-	if val == "" {
-		return fmt.Errorf("CountTime.Set(): val is empty")
-	}
-	err := sf.parser.Parse(val)
-	Hassert(err == nil, "err=%v", err)
+	Hassert(val != "", "CountTime.Set(): val is empty")
+	sf.parser.Parse(val)
 	_val := sf.parser.Hour().Get()*3600 + sf.parser.Min().Get()*60 + sf.parser.Min().Get()
 	sf.val.Set(_val)
 	_val = int(time.Now().UTC().Unix()) + sf.val.Get()
 	sf.timeTarget.Set(_val)
-	return nil
 }
 
 // Set -- устанавливает число оставшихся сек
-func (sf *CountTime) Set(val int) error {
+func (sf *CountTime) Set(val int) {
 	sf.block.Lock()
 	defer sf.block.Unlock()
-	if val < 0 {
-		return fmt.Errorf("CountTime.Set(): val(%v)<0", val)
-	}
+	Hassert(val >= 0, "CountTime.Set(): val(%v)<0", val)
 	sf.val.Set(val)
 	{ // Обновить локальные счётчики
 		if val < 60 {
 			sf.parser.Hour().Reset()
 			sf.parser.Min().Reset()
-			err := sf.parser.Sec().Set(val)
-			Hassert(err == nil, "err==%v", err)
-			return nil
+			sf.parser.Sec().Set(val)
+			return
 		}
 		if 60 < val && val < 3600 {
 			sf.parser.Hour().Reset()
 			iMin := val / 60
-			err := sf.parser.Min().Set(iMin)
-			Hassert(err == nil, "err=%v", err)
+			sf.parser.Min().Set(iMin)
 			val -= iMin * 60
-			err = sf.parser.Sec().Set(val)
-			Hassert(err == nil, "err=%v", err)
-			return nil
+			sf.parser.Sec().Set(val)
+			return
 		}
-		err := sf.parser.Hour().Set(val / 3600)
-		Hassert(err == nil, "err=%v", err)
+		sf.parser.Hour().Set(val / 3600)
 		val -= sf.parser.Hour().Get() * 3600
-		err = sf.parser.Min().Set(val / 60)
-		Hassert(err == nil, "err=%v", err)
+		sf.parser.Min().Set(val / 60)
 		val -= sf.parser.Min().Get() * 60
-		err = sf.parser.Sec().Set(val)
-		Hassert(err == nil, "err=%v", err)
+		sf.parser.Sec().Set(val)
 		val = int(time.Now().UTC().Unix()) + sf.val.Get()
 		sf.timeTarget.Set(val)
 	}
-	return nil
 }
 
 // String -- возвращает строковое представление оставшихся сек

+ 13 - 46
pkg/components/counttime/counttime_test.go

@@ -5,7 +5,6 @@ import (
 	"time"
 
 	. "gitp78su.ipnodns.ru/svi/kern"
-	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
 )
 
@@ -17,7 +16,6 @@ import (
 type tester struct {
 	t      *testing.T
 	ct     *CountTime
-	err    error
 	isCall ISafeBool // Признак обратного вызова
 }
 
@@ -55,8 +53,7 @@ func (sf *tester) cancel() {
 func (sf *tester) checkTick() {
 	ct := NewCountTime()
 	{ // Секундный тик
-		err := ct.Parse("00:00:08")
-		Hassert(err == nil, "err=%v", err)
+		ct.Parse("00:00:08")
 		time.Sleep(time.Second * 1)
 		ct.chTick <- 1
 		time.Sleep(time.Millisecond * 20)
@@ -73,8 +70,7 @@ func (sf *tester) checkTick() {
 	}
 	{ // Проверка обратного вызова прямо сейчас
 		strTime := time.Now().UTC().Format("15:04:05")
-		err := ct.Parse(strTime)
-		Hassert(err == nil, "err=%v", err)
+		ct.Parse(strTime)
 		if val := ct.String(); val != strTime {
 			sf.t.Errorf("checkTick(): счётчик(%v)!=%s", val, strTime)
 		}
@@ -82,8 +78,7 @@ func (sf *tester) checkTick() {
 		// Выход из функции -- и есть факт обратного вызова
 		sf.call()
 		{ // Проверка отсутствия обратного вызова прямо сейчас
-			err := ct.Parse("00:00:00")
-			Hassert(err == nil, "err=%v", err)
+			ct.Parse("00:00:00")
 			ct.chTick <- 1
 			// Выход из функции -- и есть факт обратного вызова
 			sf.call()
@@ -97,20 +92,14 @@ func (sf *tester) checkTick() {
 }
 
 func (sf *tester) setStrBad1(strBad string) {
-	if sf.err = sf.ct.Parse(strBad); sf.err == nil {
-		sf.t.Errorf("setStrBad1(): BAD-2 err==nil")
-	}
+	sf.ct.Parse(strBad)
 }
 
 // Устанавливает строковое значение времени
 func (sf *tester) setStr() {
 	go sf.call()
 	ct := NewCountTime()
-	{ // BAD-1 пустая строка
-		if sf.err = ct.Parse(""); sf.err == nil {
-			sf.t.Errorf("setStr(): BAD-1 err==nil")
-		}
-	}
+	ct.Parse("") // BAD-1 пустая строка
 	// BAD-2 неформатная строка
 	sf.setStrBad1(":::")
 	// BAD-3 кривые часы
@@ -139,36 +128,18 @@ func (sf *tester) setStr() {
 	sf.setStrBad1("-1:02:03")
 	// BAD-15 кривые часы +минуты + секунды
 	//sf.setStrBad1("24:02:03")
-	{ // GOOD-1 секунды
-		if sf.err = ct.Parse("03"); sf.err != nil {
-			sf.t.Errorf("setStr(): GOOD-1 err=%v", sf.err)
-		}
-	}
-	{ // GOOD-2 минуты секунды
-		if sf.err = ct.Parse("02:03"); sf.err != nil {
-			sf.t.Errorf("setStr(): GOOD-2 err=%v", sf.err)
-		}
-	}
-	{ // GOOD-3 часы минуты секунды
-		if sf.err = ct.Parse("01:02:03"); sf.err != nil {
-			sf.t.Errorf("setStr(): GOOD-3 err=%v", sf.err)
-		}
-	}
+	ct.Parse("03")       // GOOD-1 секунды
+	ct.Parse("02:03")    // GOOD-2 минуты секунды
+	ct.Parse("01:02:03") // GOOD-3 часы минуты секунды
 }
 
 // Устанавливает число секунд для отсчёта
 func (sf *tester) setInt() {
 	go sf.call()
 	ct := NewCountTime()
-	{ // Bad-1 Отрицательное число
-		if sf.err = ct.Set(-1); sf.err == nil {
-			sf.t.Errorf("setInt(): BAD-1 err==nil")
-		}
-	}
-	{ // GOOD-1
-		if sf.err = ct.Set(8); sf.err != nil {
-			sf.t.Errorf("setInt(): GOOD-1 err=%v", sf.err)
-		}
+	ct.Set(-1) // Bad-1 Отрицательное число
+	{          // GOOD-1
+		ct.Set(8)
 		if ct.parser.Hour().Get() != 0 {
 			sf.t.Errorf("setInt(): GOOD-1 hour(%v)!=0", sf.ct.parser.Hour().Get())
 		}
@@ -183,9 +154,7 @@ func (sf *tester) setInt() {
 		}
 	}
 	{ // GOOD-2
-		if sf.err = ct.Set(121); sf.err != nil {
-			sf.t.Errorf("setInt(): GOOD-2 err=%v", sf.err)
-		}
+		ct.Set(121)
 		if ct.parser.Hour().Get() != 0 {
 			sf.t.Errorf("setInt(): GOOD-2 hour(%v)!=0", sf.ct.parser.Hour().Get())
 		}
@@ -200,9 +169,7 @@ func (sf *tester) setInt() {
 		}
 	}
 	{ // GOOD-3
-		if sf.err = ct.Set(7203); sf.err != nil {
-			sf.t.Errorf("setInt(): GOOD-3 err=%v", sf.err)
-		}
+		ct.Set(7203)
 		if ct.parser.Hour().Get() != 2 {
 			sf.t.Errorf("setInt(): GOOD-3 hour(%v)!=2", sf.ct.parser.Hour().Get())
 		}

+ 9 - 18
pkg/components/parsetime/parsehour/parsehour.go

@@ -4,6 +4,8 @@ import (
 	"fmt"
 	"strconv"
 	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 )
 
 /*
@@ -44,34 +46,23 @@ func (sf *ParseHour) Reset() {
 }
 
 // Parse -- устанавливает значение часов
-func (sf *ParseHour) Parse(strHour string) error {
+func (sf *ParseHour) Parse(strHour string) {
 	sf.block.Lock()
 	defer sf.block.Unlock()
 	iHour, err := strconv.Atoi(strHour)
-	if err != nil {
-		return fmt.Errorf("ParseHour.Parse(): часы(%q) не число, err=\n\t%w", strHour, err)
-	}
-	if err := sf.set(iHour); err != nil {
-		return fmt.Errorf("ParseHour.Parse(): in internal set hour(%q), err=\n\t%w", strHour, err)
-	}
-	return nil
+	Hassert(err == nil, "ParseHour.Parse(): часы(%q) не число, err=\n\t%w", strHour, err)
+	sf.set(iHour)
 }
 
 // Set - -устанавливает числовое значение часов
-func (sf *ParseHour) Set(iHour int) error {
+func (sf *ParseHour) Set(iHour int) {
 	sf.block.Lock()
 	defer sf.block.Unlock()
-	if err := sf.set(iHour); err != nil {
-		return fmt.Errorf("ParseHour.Set(): in internal set hour(%v), err=\n\t%w", iHour, err)
-	}
-	return nil
+	sf.set(iHour)
 }
 
 // Внутренняя процедура для числовой установки часов без блокировки
-func (sf *ParseHour) set(iHour int) error {
-	if iHour < 0 {
-		return fmt.Errorf("ParseHour.set(): часы(%v) < 0", iHour)
-	}
+func (sf *ParseHour) set(iHour int) {
+	Hassert(iHour >= 0, "ParseHour.set(): часы(%v) < 0", iHour)
 	sf.val = iHour
-	return nil
 }

+ 7 - 19
pkg/components/parsetime/parsehour/parsehour_test.go

@@ -41,17 +41,13 @@ func (sf *tester) set() {
 }
 func (sf *tester) setGood1() {
 	sf.t.Logf("=setGood1=\n")
-	if err := sf.ph.Set(8); err != nil {
-		sf.t.Errorf("setGood1(): err=\n\t%v\n", err)
-	}
+	sf.ph.Set(8)
 }
 
 // Отрицательное значение часа
 func (sf *tester) setBad1() {
 	sf.t.Logf("=setBad1=\n")
-	if err := sf.ph.Set(-1); err == nil {
-		sf.t.Errorf("setBad1(): err==nil\n")
-	}
+	sf.ph.Set(-1)
 }
 
 // Устанавливает значение часов
@@ -63,12 +59,10 @@ func (sf *tester) parse() {
 	sf.parseGood2()
 }
 
-// Установка правильных большихчасов
+// Установка правильных больших часов
 func (sf *tester) parseGood2() {
 	sf.t.Logf("=parseGood2=\n")
-	if err := sf.ph.Parse("867"); err != nil {
-		sf.t.Errorf("parseGood2(): err=\n\t%v\n", err)
-	}
+	sf.ph.Parse("867")
 	if strHour := sf.ph.String(); strHour != "867" {
 		sf.t.Errorf("parseGood2(): strHour(%q)!='867'\n", strHour)
 	}
@@ -77,9 +71,7 @@ func (sf *tester) parseGood2() {
 // Установка правильных часов
 func (sf *tester) parseGood1() {
 	sf.t.Logf("=parseGood1=\n")
-	if err := sf.ph.Parse("8"); err != nil {
-		sf.t.Errorf("parseGood1(): err=\n\t%v\n", err)
-	}
+	sf.ph.Parse("8")
 	if strHour := sf.ph.String(); strHour != "08" {
 		sf.t.Errorf("parseGood1(): strHour(%q)!='08'\n", strHour)
 	}
@@ -88,17 +80,13 @@ func (sf *tester) parseGood1() {
 // Установка отрицательных часов
 func (sf *tester) parseBad2() {
 	sf.t.Logf("=parseBad2=\n")
-	if err := sf.ph.Parse("-1"); err == nil {
-		sf.t.Errorf("parseBad2(): err==nil\n")
-	}
+	sf.ph.Parse("-1")
 }
 
 // Установка не часов
 func (sf *tester) parseBad1() {
 	sf.t.Logf("=parseBad1=\n")
-	if err := sf.ph.Parse("abc"); err == nil {
-		sf.t.Errorf("parseBad1(): err==nil\n")
-	}
+	sf.ph.Parse("abc")
 }
 
 // Создание парсера часов

+ 9 - 18
pkg/components/parsetime/parsemin/parsemin.go

@@ -4,6 +4,8 @@ import (
 	"fmt"
 	"strconv"
 	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 )
 
 /*
@@ -44,34 +46,23 @@ func (sf *ParseMin) Reset() {
 }
 
 // Parse -- устанавливает значение минут
-func (sf *ParseMin) Parse(strMin string) error {
+func (sf *ParseMin) Parse(strMin string) {
 	sf.block.Lock()
 	defer sf.block.Unlock()
 	iMin, err := strconv.Atoi(strMin)
-	if err != nil {
-		return fmt.Errorf("ParseMin.Parse(): минуты(%v) не число, err=%w", strMin, err)
-	}
-	if err := sf.set(iMin); err != nil {
-		return fmt.Errorf("ParseMin.Parse(): in internal set, err=\n\t%w", err)
-	}
-	return nil
+	Hassert(err == nil, "ParseMin.Parse(): минуты(%v) не число, err=%w", strMin, err)
+	sf.set(iMin)
 }
 
 // Set -- устанавливает целочисленное значение минут
-func (sf *ParseMin) Set(iMin int) error {
+func (sf *ParseMin) Set(iMin int) {
 	sf.block.Lock()
 	defer sf.block.Unlock()
-	if err := sf.set(iMin); err != nil {
-		return fmt.Errorf("ParseMin.Set(): in internal set, err=\n\t%w", err)
-	}
-	return nil
+	sf.set(iMin)
 }
 
 // Внтренняя установка минут
-func (sf *ParseMin) set(iMin int) error {
-	if !(0 <= iMin && iMin < 60) {
-		return fmt.Errorf("ParseMin.set(): минуты не в диапазоне(%v) 0..60", iMin)
-	}
+func (sf *ParseMin) set(iMin int) {
+	Hassert(0 <= iMin && iMin < 60, "ParseMin.set(): минуты не в диапазоне(%v) 0..60", iMin)
 	sf.val = iMin
-	return nil
 }

+ 5 - 15
pkg/components/parsetime/parsemin/parsemin_test.go

@@ -34,9 +34,7 @@ func (sf *tester) set() {
 // Кривое число минут
 func (sf *tester) setBad1() {
 	sf.t.Logf("=setBad1=\n")
-	if err := sf.ph.Set(60); err == nil {
-		sf.t.Errorf("setBad1(): err==nil\n")
-	}
+	sf.ph.Set(60)
 	if strHour := sf.ph.String(); strHour != "08" {
 		sf.t.Errorf("setBad1(): strHour(%q)!='08'\n", strHour)
 	}
@@ -44,9 +42,7 @@ func (sf *tester) setBad1() {
 
 func (sf *tester) setGood1() {
 	sf.t.Logf("=setGood1=\n")
-	if err := sf.ph.Set(8); err != nil {
-		sf.t.Errorf("setGood1(): err=\n\t%v\n", err)
-	}
+	sf.ph.Set(8)
 	if strHour := sf.ph.String(); strHour != "08" {
 		sf.t.Errorf("setGood1(): strHour(%q)!='08'\n", strHour)
 	}
@@ -72,9 +68,7 @@ func (sf *tester) parse() {
 // Установка правильных минут
 func (sf *tester) parseGood1() {
 	sf.t.Logf("=parseGood1=\n")
-	if err := sf.ph.Parse("8"); err != nil {
-		sf.t.Errorf("parseGood1(): err=\n\t%v\n", err)
-	}
+	sf.ph.Parse("8")
 	if strHour := sf.ph.String(); strHour != "08" {
 		sf.t.Errorf("parseGood1(): strHour(%q)!='08'\n", strHour)
 	}
@@ -83,17 +77,13 @@ func (sf *tester) parseGood1() {
 // Установка отрицательных минут
 func (sf *tester) parseBad2() {
 	sf.t.Logf("=parseBad2=\n")
-	if err := sf.ph.Parse("-1"); err == nil {
-		sf.t.Errorf("parseBad2(): err==nil\n")
-	}
+	sf.ph.Parse("-1")
 }
 
 // Установка не минут
 func (sf *tester) parseBad1() {
 	sf.t.Logf("=parseBad1=\n")
-	if err := sf.ph.Parse("abc"); err == nil {
-		sf.t.Errorf("parseBad1(): err==nil\n")
-	}
+	sf.ph.Parse("abc")
 }
 
 // Создание парсера минут

+ 9 - 18
pkg/components/parsetime/parsesec/parsesec.go

@@ -4,6 +4,8 @@ import (
 	"fmt"
 	"strconv"
 	"sync"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
 )
 
 /*
@@ -44,34 +46,23 @@ func (sf *ParseSec) Reset() {
 }
 
 // Parse -- устанавливает значение секунд
-func (sf *ParseSec) Parse(strSec string) error {
+func (sf *ParseSec) Parse(strSec string) {
 	sf.block.Lock()
 	defer sf.block.Unlock()
 	iSec, err := strconv.Atoi(strSec)
-	if err != nil {
-		return fmt.Errorf("ParseSec.Parse(): секунды(%v) не число, err=%w", strSec, err)
-	}
-	if err := sf.set(iSec); err != nil {
-		return fmt.Errorf("ParseSec.Parse(): in internal setting, err=\n\t%w", err)
-	}
-	return nil
+	Hassert(err == nil, "ParseSec.Parse(): секунды(%v) не число, err=%w", strSec, err)
+	sf.set(iSec)
 }
 
 // Set -- устанавливает целочисленное значение
-func (sf *ParseSec) Set(iSec int) error {
+func (sf *ParseSec) Set(iSec int) {
 	sf.block.Lock()
 	defer sf.block.Unlock()
-	if err := sf.set(iSec); err != nil {
-		return fmt.Errorf("ParseSec.Set(): in internal setting int, err=\n\t%w", err)
-	}
-	return nil
+	sf.set(iSec)
 }
 
 // Внутренняя установка значения секунд
-func (sf *ParseSec) set(iSec int) error {
-	if !(0 <= iSec && iSec < 60) {
-		return fmt.Errorf("ParseSec.set(): секунды(%v) не в диапазоне 0..60", iSec)
-	}
+func (sf *ParseSec) set(iSec int) {
+	Hassert(0 <= iSec && iSec < 60, "ParseSec.set(): секунды(%v) не в диапазоне 0..60", iSec)
 	sf.val = iSec
-	return nil
 }

+ 6 - 16
pkg/components/parsetime/parsesec/parsesec_test.go

@@ -33,9 +33,7 @@ func (sf *tester) set() {
 
 func (sf *tester) setGood1() {
 	sf.t.Logf("=setGood1=\n")
-	if err := sf.ph.Set(26); err != nil {
-		sf.t.Errorf("setGood1(): err=\n\t%v\n", err)
-	}
+	sf.ph.Set(26)
 	if strHour := sf.ph.String(); strHour != "26" {
 		sf.t.Errorf("setGood1(): strHour(%q)!='26'\n", strHour)
 	}
@@ -44,9 +42,7 @@ func (sf *tester) setGood1() {
 // Отрицательные секунды
 func (sf *tester) setBad1() {
 	sf.t.Logf("=setBad1=\n")
-	if err := sf.ph.Set(-1); err == nil {
-		sf.t.Errorf("setBad1(): err==nil\n")
-	}
+	sf.ph.Set(-1)
 	if strHour := sf.ph.String(); strHour != "59" {
 		sf.t.Errorf("setBad1(): strHour(%q)!='59'\n", strHour)
 	}
@@ -79,7 +75,7 @@ func (sf *tester) parseGood2() {
 			sf.t.Errorf("parseGood2(): panic=\n\t%v\n", _panic)
 		}
 	}()
-	_ = sf.ph.Parse("59")
+	sf.ph.Parse("59")
 	if strHour := sf.ph.String(); strHour != "59" {
 		sf.t.Errorf("parseGood2(): strHour(%q)!='867'\n", strHour)
 	}
@@ -102,25 +98,19 @@ func (sf *tester) parseGood1() {
 // Установка больших часов
 func (sf *tester) parseBad3() {
 	sf.t.Logf("=parseBad3=\n")
-	if err := sf.ph.Parse("61"); err == nil {
-		sf.t.Errorf("parseBad3(): err==nil\n")
-	}
+	sf.ph.Parse("61")
 }
 
 // Установка отрицательных часов
 func (sf *tester) parseBad2() {
 	sf.t.Logf("=parseBad2=\n")
-	if err := sf.ph.Parse("-1"); err == nil {
-		sf.t.Errorf("parseBad2(): err==nil\n")
-	}
+	sf.ph.Parse("-1")
 }
 
 // Установка не часов
 func (sf *tester) parseBad1() {
 	sf.t.Logf("=parseBad1=\n")
-	if err := sf.ph.Parse("abc"); err == nil {
-		sf.t.Errorf("parseBad1(): err==nil\n")
-	}
+	sf.ph.Parse("abc")
 }
 
 // Создание парсера часов

+ 10 - 24
pkg/components/parsetime/parsetime.go

@@ -1,10 +1,11 @@
 package parsetime
 
 import (
-	"fmt"
 	"strings"
 	"sync"
 
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+
 	"wartank/pkg/components/parsetime/parsehour"
 	"wartank/pkg/components/parsetime/parsemin"
 	"wartank/pkg/components/parsetime/parsesec"
@@ -41,46 +42,31 @@ func (sf *ParseTime) Get() int {
 }
 
 // Parse -- разбирает строковое представление на части
-func (sf *ParseTime) Parse(strTime string) error {
+func (sf *ParseTime) Parse(strTime string) {
 	sf.block.Lock()
 	defer sf.block.Unlock()
-	if strTime == "" {
-		return fmt.Errorf("CountTime.Set(): val is empty")
-	}
+	Hassert(strTime != "", "CountTime.Set(): val is empty")
 	// Разбить время, перевести в секунды
 	lstTime := strings.Split(strTime, ":")
 	if len(lstTime) == 1 { // Только секунды
 		sf.hour.Reset()
 		sf.min.Reset()
-		if err := sf.sec.Parse(lstTime[0]); err != nil {
-			return fmt.Errorf("ParseTime(): in parse second only, err=\n\t%w", err)
-		}
+		sf.sec.Parse(lstTime[0])
 	}
 	if len(lstTime) == 2 { // Минуты, секунды
 		sf.hour.Reset()
-		if err := sf.min.Parse(lstTime[0]); err != nil {
-			return fmt.Errorf("ParseTime(): in parse [min]/sec, err=\n\t%w", err)
-		}
-		if err := sf.sec.Parse(lstTime[1]); err != nil {
-			return fmt.Errorf("ParseTime(): in parse min/[sec], err=\n\t%w", err)
-		}
+		sf.min.Parse(lstTime[0])
+		sf.sec.Parse(lstTime[1])
 	}
 	if len(lstTime) >= 3 { // Есть всё, возможно с левыми полями в конце
 		strHour := lstTime[0]
 		strMin := lstTime[1]
 		strSec := lstTime[2]
-		if err := sf.sec.Parse(strSec); err != nil {
-			return fmt.Errorf("ParseTime(): in parse hour/min/[sec], err=\n\t%w", err)
-		}
-		if err := sf.min.Parse(strMin); err != nil {
-			return fmt.Errorf("ParseTime(): in parse hour/[min]/sec, err=\n\t%w", err)
-		}
-		if err := sf.hour.Parse(strHour); err != nil {
-			return fmt.Errorf("ParseTime(): in parse [hour]/min/sec, err=\n\t%w", err)
-		}
+		sf.sec.Parse(strSec)
+		sf.min.Parse(strMin)
+		sf.hour.Parse(strHour)
 	}
 	sf.intVal = sf.hour.Get()*3600 + sf.min.Get()*60 + sf.sec.Get()
-	return nil
 }
 
 // Hour -- возвращает хранимые часы

+ 10 - 30
pkg/components/parsetime/parsetime_test.go

@@ -57,9 +57,7 @@ func (sf *tester) parse() {
 
 func (sf *tester) parseHourHourBad1() {
 	sf.t.Logf("=parseHourHourBad1=\n")
-	if err := sf.pars.Parse("-11:14:54"); err == nil {
-		sf.t.Errorf("parseHourHourBad1(): err==nil\n")
-	}
+	sf.pars.Parse("-11:14:54")
 	if val := sf.pars.Get(); val != 5820 {
 		sf.t.Errorf("parseHourHourBad1(): valInt(%d)!=5820\n", val)
 	}
@@ -76,9 +74,7 @@ func (sf *tester) parseHourHourBad1() {
 
 func (sf *tester) parseHourMinBad1() {
 	sf.t.Logf("=parseHourMinBad1=\n")
-	if err := sf.pars.Parse("01:-4:01"); err == nil {
-		sf.t.Errorf("parseHourMinBad1(): err==nil\n")
-	}
+	sf.pars.Parse("01:-4:01")
 	if val := sf.pars.Get(); val != 5820 {
 		sf.t.Errorf("parseHourMinBad1(): valInt(%d)!=5820\n", val)
 	}
@@ -86,9 +82,7 @@ func (sf *tester) parseHourMinBad1() {
 
 func (sf *tester) parseHourSecBad1() {
 	sf.t.Logf("=parseHourSecBad1=\n")
-	if err := sf.pars.Parse("01:37:a"); err == nil {
-		sf.t.Errorf("parseHourSecBad1(): err==nil\n")
-	}
+	sf.pars.Parse("01:37:a")
 	if val := sf.pars.Get(); val != 5820 {
 		sf.t.Errorf("parseHourSecBad1(): valInt(%d)!=5820\n", val)
 	}
@@ -96,9 +90,7 @@ func (sf *tester) parseHourSecBad1() {
 
 func (sf *tester) parseHour() {
 	sf.t.Logf("=parseHour=\n")
-	if err := sf.pars.Parse("01:37:00"); err != nil {
-		sf.t.Errorf("parseHour(): err=\n\t%v\n", err)
-	}
+	sf.pars.Parse("01:37:00")
 	if val := sf.pars.Get(); val != 5820 {
 		sf.t.Errorf("parseHour(): valInt(%d)!=5820\n", val)
 	}
@@ -106,9 +98,7 @@ func (sf *tester) parseHour() {
 
 func (sf *tester) parseMinMinBad1() {
 	sf.t.Logf("=parseMinMinBad1=\n")
-	if err := sf.pars.Parse("60:25"); err == nil {
-		sf.t.Errorf("parseMinMinBad1(): err==nil\n")
-	}
+	sf.pars.Parse("60:25")
 	if val := sf.pars.Get(); val != 444 {
 		sf.t.Errorf("parseMinMinBad1(): valInt(%d)!=444\n", val)
 	}
@@ -116,9 +106,7 @@ func (sf *tester) parseMinMinBad1() {
 
 func (sf *tester) parseMinSecBad1() {
 	sf.t.Logf("=parseMinSecBad1=\n")
-	if err := sf.pars.Parse("07:-1"); err == nil {
-		sf.t.Errorf("parseMinSecBad1(): err==nil\n")
-	}
+	sf.pars.Parse("07:-1")
 	if val := sf.pars.Get(); val != 7*60+24 {
 		sf.t.Errorf("parseMinSecBad1(): valInt(%d)!=7*60+24\n", val)
 	}
@@ -126,9 +114,7 @@ func (sf *tester) parseMinSecBad1() {
 
 func (sf *tester) parseMin() {
 	sf.t.Logf("=parseMin=\n")
-	if err := sf.pars.Parse("07:24"); err != nil {
-		sf.t.Errorf("parseMin(): err=\n\t%v\n", err)
-	}
+	sf.pars.Parse("07:24")
 	if val := sf.pars.Get(); val != 7*60+24 {
 		sf.t.Errorf("parseMin(): valInt(%d)!=7*60+24\n", val)
 	}
@@ -137,9 +123,7 @@ func (sf *tester) parseMin() {
 // Слишком большие секунды
 func (sf *tester) parseSecBad1() {
 	sf.t.Logf("=parseSecBad1=\n")
-	if err := sf.pars.Parse("60"); err == nil {
-		sf.t.Errorf("parseSecBad1(): err==nil\n")
-	}
+	sf.pars.Parse("60")
 	if val := sf.pars.Get(); val != 28 {
 		sf.t.Errorf("parseSecBad1(): valInt(%d)!=28\n", val)
 	}
@@ -147,9 +131,7 @@ func (sf *tester) parseSecBad1() {
 
 func (sf *tester) parseSec() {
 	sf.t.Logf("=parseSec=\n")
-	if err := sf.pars.Parse("28"); err != nil {
-		sf.t.Errorf("parseSec(): err=\n\t%v\n", err)
-	}
+	sf.pars.Parse("28")
 	if val := sf.pars.Get(); val != 28 {
 		sf.t.Errorf("parseSec(): valInt(%d)!=28\n", val)
 	}
@@ -158,7 +140,5 @@ func (sf *tester) parseSec() {
 // Нет строки для парсинга
 func (sf *tester) parseBad1() {
 	sf.t.Logf("=parseBad1=\n")
-	if err := sf.pars.Parse(""); err == nil {
-		sf.t.Errorf("parseBad1(): err==nil\n")
-	}
+	sf.pars.Parse("")
 }

+ 1 - 1
vendor/gitp78su.ipnodns.ru/svi/kern/Makefile

@@ -6,7 +6,7 @@ demo:
 mod:
 	clear
 	go get -u ./...
-	go mod tidy -compat=1.24.0
+	go mod tidy -compat=1.22.0
 	go mod vendor
 	go fmt ./...
 

+ 2 - 2
vendor/gitp78su.ipnodns.ru/svi/kern/kc/helpers/helpers.go

@@ -17,7 +17,7 @@ var (
 )
 
 // Assert -- проверка на правильность утверждения с падением в панику на локальном стенде (soft assert)
-func Assert(isCond bool, msgFormat string, args ...interface{}) {
+func Assert(isCond bool, msgFormat string, args ...any) {
 	if isCond {
 		return
 	}
@@ -29,7 +29,7 @@ func Assert(isCond bool, msgFormat string, args ...interface{}) {
 }
 
 // Hassert -- проверка на правильность утверждения с безусловным падением в панику (hard assert)
-func Hassert(isCond bool, msgFormat string, args ...interface{}) {
+func Hassert(isCond bool, msgFormat string, args ...any) {
 	if isCond {
 		return
 	}

+ 0 - 74
vendor/gitp78su.ipnodns.ru/svi/kern/kc/helpers/result.txt

@@ -1,74 +0,0 @@
-package helpers
-
-// Result — аналог Result<T, E> из Rust
-//
-// Может быть либотолько полезное значение, либо только ошибка
-type Result[T any] struct {
-	value T     // Полезное значение
-	err   error // Ошибка
-}
-
-// NewResult -- возвращает успешный Result с значением
-func NewResult[T *any](result T) *Result[T] {
-	Hassert(result != nil, "NewResult(): result==nil")
-	return &Result[T]{
-		value: result,
-	}
-}
-
-// NewResultErr -- возвращает Result с ошибкой
-func NewResultErr[T any](err error) *Result[T] {
-	Hassert(err != nil, "NewError(): err==nil")
-	return &Result[T]{
-		err: err,
-	}
-}
-
-// IsOk -- возвращает true, если Result содержит значение
-func (sf *Result[T]) IsOk() bool {
-	return sf.err == nil
-}
-
-// IsErr -- возвращает true, если Result содержит ошибку
-func (sf *Result[T]) IsErr() bool {
-	return sf.err != nil
-}
-
-// Unwrap -- возвращает значение, если оно есть, иначе паникует
-func (sf *Result[T]) Unwrap() T {
-	if sf.err != nil {
-		panic(sf.err)
-	}
-	return sf.value
-}
-
-// UnwrapOr -- возвращает значение, если оно есть, или значение по умолчанию
-func (sf *Result[T]) UnwrapOr(defaultValue T) T {
-	if sf.IsErr() {
-		return defaultValue
-	}
-	return sf.value
-}
-
-// UnwrapOrElse -- возвращает значение, если оно есть, или результат выполнения функции
-func (sf *Result[T]) UnwrapOrElse(f func() T) T {
-	if sf.IsErr() {
-		return f()
-	}
-	return sf.value
-}
-
-// Error -- возвращает ошибку, если она есть
-func (sf *Result[T]) Error() error {
-	return sf.err
-}
-
-// HAssert -- проверяет, что нет ошибки (с паникой)
-func (sf *Result[T]) Hassert(msg string) {
-	Hassert(sf.err != nil, msg+", err=\n\t%v\n", sf.err)
-}
-
-// Assert -- проверяет, что нет ошибки (с паникой только на локальном стенде)
-func (sf *Result[T]) Assert(msg string) {
-	Assert(sf.err != nil, msg+", err=\n\t%v\n", sf.err)
-}

+ 20 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/kern.go

@@ -167,3 +167,23 @@ func NewSafeString() ISafeString {
 	str := safe_string.NewSafeString()
 	return str
 }
+
+// MakeOk -- возвращает новый положительный результат операции
+func MakeOk[T any](res T) Result[T] {
+	return NewOk(res)
+}
+
+// MakeErr -- возвращает новую ошибку результат операции
+func MakeErr[T any](err error) Result[T] {
+	return NewErr[T](err)
+}
+
+// MakeSome -- возвращает новый не пустой результат операции
+func MakeSome[T any](some T) Option[T] {
+	return NewSome(some)
+}
+
+// MakeNone -- возвращает новый пустой результат операции
+func MakeNone[T any]() Option[T] {
+	return NewNone[T]()
+}

+ 11 - 16
vendor/gitp78su.ipnodns.ru/svi/kern/krn/kbus/dict_topic_serve/dict_topic_serve.go

@@ -51,37 +51,32 @@ func (sf *dictServe) Unregister(handler IBusHandlerServe) {
 }
 
 // SendRequest -- вызывает обработчик при поступлении запроса
-func (sf *dictServe) SendRequest(topic ATopic, binReq []byte) ([]byte, error) {
+func (sf *dictServe) SendRequest(topic ATopic, binReq []byte) Result[[]byte] {
 	sf.RLock()
 	defer sf.RUnlock()
 	handler, isOk := sf.dictServe[topic]
 	if !isOk {
-		return nil, fmt.Errorf("dictServe.SendRequest(): handler for topic (%v) not exists", topic)
+		err := fmt.Errorf("dictServe.SendRequest(): handler for topic (%v) not exists", topic)
+		return NewErr[[]byte](err)
 	}
 	var (
-		chErr  = make(chan error, 2)
-		binRes []byte
+		chRes = make(chan Result[[]byte], 2)
 	)
 	ctx, fnCancel := context.WithTimeout(sf.ctx.Ctx(), time.Millisecond*time.Duration(TimeoutDefault))
 	defer fnCancel()
 	fnCall := func() {
-		defer close(chErr)
-		var err error
-		binRes, err = handler.FnBack(binReq)
-		if err != nil {
-			chErr <- err
-		}
+		defer close(chRes)
+		res := handler.FnBack(binReq)
+		chRes <- res
 	}
 	go fnCall()
 	select {
 	case <-ctx.Done():
-		return nil, fmt.Errorf("dictServe.SendRequest(): in call for topic (%v), err=\n\t%w", topic, ctx.Err())
-	case err := <-chErr:
-		if err != nil {
-			return nil, fmt.Errorf("dictServe.SendRequest(): error in call for topic (%v), err=\n\t%w", topic, err)
-		}
+		err := fmt.Errorf("dictServe.SendRequest(): in call for topic (%v), err=\n\t%w", topic, ctx.Err())
+		return NewErr[[]byte](err)
+	case res := <-chRes:
+		return res
 	}
-	return binRes, nil
 }
 
 var TimeoutDefault = 15000

+ 15 - 15
vendor/gitp78su.ipnodns.ru/svi/kern/krn/kbus/kbus_base/kbus_base.go

@@ -53,8 +53,8 @@ func GetKernelBusBase() *KBusBase {
 	go Bus_.close()
 	go Bus_.run()
 	Bus_.IsWork_.Set()
-	err := Bus_.Ctx_.Wg().Add(strBusBaseStream)
-	Hassert(err == nil, "GetKernelBusBase(): in add name stream(%v), err=\n\t%v", strBusBaseStream, err)
+	res := Bus_.Ctx_.Wg().Add(strBusBaseStream)
+	Hassert(res.IsOk(), "GetKernelBusBase(): in add name stream(%v), err=\n\t%v", strBusBaseStream, res.Error())
 	ctx.Set("kernBusBase", Bus_, "base of data bus")
 	_ = IKernelBus(Bus_)
 	return Bus_
@@ -79,32 +79,32 @@ func (sf *KBusBase) Unsubscribe(handler IBusHandlerSubscribe) {
 }
 
 // Subscribe -- подписывает обработчик на топик
-func (sf *KBusBase) Subscribe(handler IBusHandlerSubscribe) error {
+func (sf *KBusBase) Subscribe(handler IBusHandlerSubscribe) Result[bool] {
 	sf.log.Debug("KBusBase.Subscribe(): handler='%v'", handler.Name())
 	if !sf.IsWork_.Get() {
 		err := fmt.Errorf("KBusBase.Subscribe():  handler='%v', bus already closed", handler.Name())
 		sf.log.Err(err.Error())
-		return err
+		return NewErr[bool](err)
 	}
 	sf.dictSub.Subscribe(handler)
-	return nil
+	return NewOk(true)
 }
 
 // SendRequest -- отправляет запрос в шину данных
-func (sf *KBusBase) SendRequest(topic ATopic, binReq []byte) ([]byte, error) {
+func (sf *KBusBase) SendRequest(topic ATopic, binReq []byte) Result[[]byte] {
 	sf.log.Debug("KBusBase.SendRequest(): topic='%v'", topic)
 	if !sf.IsWork_.Get() {
 		err := fmt.Errorf("KBusBase.SendRequest():  topic='%v', bus already closed", topic)
 		sf.log.Err(err.Error())
-		return nil, err
+		return NewErr[[]byte](err)
 	}
-	binResp, err := sf.dictServe.SendRequest(topic, binReq)
-	if err != nil {
-		err := fmt.Errorf("KBusBase.SendRequest(): topic='%v', err=\n\t%w", topic, err)
+	res := sf.dictServe.SendRequest(topic, binReq)
+	if res.IsErr() {
+		err := fmt.Errorf("KBusBase.SendRequest(): topic='%v', err=\n\t%w", topic, res.Error())
 		sf.log.Err(err.Error())
-		return nil, err
+		return NewErr[[]byte](err)
 	}
-	return binResp, nil
+	return res
 }
 
 // RegisterServe -- регистрирует обработчики входящих запросов
@@ -115,16 +115,16 @@ func (sf *KBusBase) RegisterServe(handler IBusHandlerServe) {
 }
 
 // Publish -- публикует сообщение в шину
-func (sf *KBusBase) Publish(topic ATopic, binMsg []byte) (err error) {
+func (sf *KBusBase) Publish(topic ATopic, binMsg []byte) Result[bool] {
 	sf.log.Debug("KBusBase.Publish(): topic='%v'", topic)
 	if !sf.IsWork_.Get() {
 		err := fmt.Errorf("KBusBase.Publish(): topic='%v',bus already closed", topic)
 		sf.log.Err(err.Error())
-		return err
+		return NewErr[bool](err)
 	}
 	// Асинхронный запуск чтения
 	go sf.dictSub.Read(topic, binMsg)
-	return nil
+	return NewOk(true)
 }
 
 // IsWork -- возвращает признак работы шины

+ 13 - 17
vendor/gitp78su.ipnodns.ru/svi/kern/krn/kbus/kbus_http/client_bus_http/client_bus_http.go

@@ -22,7 +22,6 @@ import (
 	"gitp78su.ipnodns.ru/svi/kern/krn/kbus/kbus_msg/msg_unsub"
 	"gitp78su.ipnodns.ru/svi/kern/krn/kctx"
 	. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
-	"gitp78su.ipnodns.ru/svi/kern/mock/mock_hand_sub_http"
 )
 
 // ClientBusHttp -- клиент HTTP-шины
@@ -83,7 +82,7 @@ func (sf *ClientBusHttp) Unsubscribe(handler IBusHandlerSubscribe) {
 }
 
 // Subscribe -- подписывается на топик в дистанционной шине
-func (sf *ClientBusHttp) Subscribe(handler IBusHandlerSubscribe) error {
+func (sf *ClientBusHttp) Subscribe(handler IBusHandlerSubscribe) Result[bool] {
 	_uuid, err := uuid.NewV6()
 	Hassert(err == nil, "ClientBusHttp.Subscribe(): in generate UUID v6, err=\n\t%v", err)
 	req := &msg_sub.SubscribeReq{
@@ -102,7 +101,7 @@ func (sf *ClientBusHttp) Subscribe(handler IBusHandlerSubscribe) error {
 	if err != nil {
 		err := fmt.Errorf("ClientBusHttp.Subscribe(): in make request, err=\n\t%w", err)
 		sf.log.Err(err.Error())
-		return err
+		return NewErr[bool](err)
 	}
 	resp := &msg_sub.SubscribeResp{}
 	err = json.Unmarshal(binBody, resp)
@@ -110,18 +109,15 @@ func (sf *ClientBusHttp) Subscribe(handler IBusHandlerSubscribe) error {
 	if string(resp.Status_) != "ok" {
 		err := fmt.Errorf("ClientBusHttp.Subscribe(): resp!='ok', err=\n\t%v", resp.Status_)
 		sf.log.Err(err.Error())
-		return err
+		return NewErr[bool](err)
 	}
 	Hassert(resp.Uuid_ == req.Uuid_, "ClientBusHttp.Subscribe(): resp uuid(%v) bad", resp.Uuid_)
-	// FIXME: вот тут похоже дичь
-	_handler := handler.(*mock_hand_sub_http.MockHandSubHttp)
-	_handler.SetName(resp.Name_)
-	err = sf.bus.Subscribe(_handler)
-	return err
+	res := sf.bus.Subscribe(handler)
+	return res
 }
 
 // SendRequest -- отправляет в дистанционную шину запрос
-func (sf *ClientBusHttp) SendRequest(topic ATopic, binReq []byte) ([]byte, error) {
+func (sf *ClientBusHttp) SendRequest(topic ATopic, binReq []byte) Result[[]byte] {
 	_uuid, err := uuid.NewV6()
 	Hassert(err == nil, "ClientBusHttp.SendRequest(): in generate UUID v6, err=\n\t%v", err)
 	req := &msg_serve.ServeReq{
@@ -140,7 +136,7 @@ func (sf *ClientBusHttp) SendRequest(topic ATopic, binReq []byte) ([]byte, error
 	if err != nil {
 		err := fmt.Errorf("ClientBusHttp.SendRequest(): in make request, err=\n\t%w", err)
 		sf.log.Err(err.Error())
-		return nil, err
+		return NewErr[[]byte](err)
 	}
 	resp := &msg_serve.ServeResp{}
 	err = json.Unmarshal(binBody, resp)
@@ -148,10 +144,10 @@ func (sf *ClientBusHttp) SendRequest(topic ATopic, binReq []byte) ([]byte, error
 	if string(resp.Status_) != "ok" {
 		err := fmt.Errorf("ClientBusHttp.SendRequest(): resp!='ok', err=\n\t%v", resp.Status_)
 		sf.log.Err(err.Error())
-		return nil, err
+		return NewErr[[]byte](err)
 	}
 	Hassert(resp.Uuid_ == req.Uuid_, "ClientBusHttp.SendRequest(): resp uuid(%v) bad", resp.Uuid_)
-	return resp.BinResp_, nil
+	return NewOk(resp.BinResp_)
 }
 
 // RegisterServe -- регистрирует в локальной шине обработчик
@@ -161,7 +157,7 @@ func (sf *ClientBusHttp) RegisterServe(handler IBusHandlerServe) {
 }
 
 // Publish -- публикует сообщение в дистанционной шину
-func (sf *ClientBusHttp) Publish(topic ATopic, binMsg []byte) error {
+func (sf *ClientBusHttp) Publish(topic ATopic, binMsg []byte) Result[bool] {
 	_uuid, err := uuid.NewV6()
 	Hassert(err == nil, "ClientBusHttp.Publish(): in generate UUID v6, err=\n\t%v", err)
 	req := &msg_pub.PublishReq{
@@ -180,7 +176,7 @@ func (sf *ClientBusHttp) Publish(topic ATopic, binMsg []byte) error {
 	if err != nil {
 		err := fmt.Errorf("ClientBusHttp.Publish(): in make request, err=\n\t%w", err)
 		sf.log.Err(err.Error())
-		return err
+		return NewErr[bool](err)
 	}
 	resp := &msg_pub.PublishResp{}
 	err = json.Unmarshal(binBody, resp)
@@ -188,10 +184,10 @@ func (sf *ClientBusHttp) Publish(topic ATopic, binMsg []byte) error {
 	if string(resp.Status_) != "ok" {
 		err := fmt.Errorf("ClientBusHttp.Publish(): resp!='ok', err=\n\t%v", resp.Status_)
 		sf.log.Err(err.Error())
-		return err
+		return NewErr[bool](err)
 	}
 	Hassert(resp.Uuid_ == req.Uuid_, "ClientBusHttp.Publish(): resp uuid(%v) bad", resp.Uuid_)
-	return nil
+	return NewOk(true)
 }
 
 // Единый обработчик запросов

+ 14 - 13
vendor/gitp78su.ipnodns.ru/svi/kern/krn/kbus/kbus_http/kbus_http.go

@@ -79,9 +79,9 @@ func (sf *kBusHttp) processSubscribe(req *msg_sub.SubscribeReq) *msg_sub.Subscri
 		Uuid_:   req.Uuid_,
 		Name_:   handler.Name(),
 	}
-	err := sf.Subscribe(handler)
-	if err != nil {
-		resp.Status_ = fmt.Sprintf("kernelBusHttp.processSubscribe(): err=\n\t%v", err)
+	res := sf.Subscribe(handler)
+	if res.IsErr() {
+		resp.Status_ = fmt.Sprintf("kernelBusHttp.processSubscribe(): err=\n\t%v", res.Error())
 		return resp
 	}
 	return resp
@@ -113,13 +113,14 @@ func (sf *kBusHttp) postPublish(ctx *fiber.Ctx) error {
 // Выполняет процесс публикации
 func (sf *kBusHttp) processPublish(req *msg_pub.PublishReq) *msg_pub.PublishResp {
 	req.SelfCheck()
-	err := sf.Publish(req.Topic_, req.BinMsg_)
+	res := sf.Publish(req.Topic_, req.BinMsg_)
 	resp := &msg_pub.PublishResp{
 		Status_: "ok",
 		Uuid_:   req.Uuid_,
 	}
-	if err != nil {
-		resp.Status_ = fmt.Sprintf("kernelBusHttp.processPublish(): err=\n\t%v", err)
+	if res.IsErr() {
+		resp.Status_ = fmt.Sprintf("kernelBusHttp.processPublish(): err=\n\t%v", res.Error())
+		return resp
 	}
 	return resp
 }
@@ -150,16 +151,16 @@ func (sf *kBusHttp) postSendRequest(ctx *fiber.Ctx) error {
 // Обрабатывает входящий запрос
 func (sf *kBusHttp) processSendRequest(req *msg_serve.ServeReq) *msg_serve.ServeResp {
 	req.SelfCheck()
-	binResp, err := sf.SendRequest(req.Topic_, req.BinReq_)
+	res := sf.SendRequest(req.Topic_, req.BinReq_)
 	resp := &msg_serve.ServeResp{
-		Status_:  "ok",
-		Uuid_:    req.Uuid_,
-		BinResp_: binResp,
+		Status_: "ok",
+		Uuid_:   req.Uuid_,
 	}
-	if err != nil {
-		resp.Status_ = fmt.Sprintf("kernelBusHttp.processSendRequest(): err=\n\t%v", err)
+	if res.IsErr() {
+		resp.Status_ = fmt.Sprintf("kernelBusHttp.processSendRequest(): err=\n\t%v", res.Error())
+		return resp
 	}
-
+	resp.BinResp_ = res.Unwrap()
 	return resp
 }
 

+ 2 - 2
vendor/gitp78su.ipnodns.ru/svi/kern/krn/kctx/kernel_keeper/kernel_keeper.go

@@ -46,8 +46,8 @@ func GetKernelKeeper(ctx context.Context, fnCancel func(), wg IKernelWg) *kernel
 		chSys_:   make(chan os.Signal, 2),
 	}
 	sf.log.Debug("GetKernelKeeper(): first run")
-	err := sf.wg.Add("kernel_keeper")
-	Hassert(err == nil, "NewKernelCtx(): in add stream kernel keeper in IKernelWg, err=\n\t%v,err")
+	res := sf.wg.Add("kernel_keeper")
+	Hassert(res.IsOk(), "NewKernelCtx(): in add stream kernel keeper in IKernelWg, err=\n\t%v", res.Error())
 
 	go sf.run(sf.chSys_)
 	kernKeep = sf

+ 4 - 3
vendor/gitp78su.ipnodns.ru/svi/kern/krn/kctx/kwg/kwg.go

@@ -99,18 +99,19 @@ func (sf *kernelWg) Wait() {
 }
 
 // Add -- добавляет поток в ожидание
-func (sf *kernelWg) Add(name AStreamName) error {
+func (sf *kernelWg) Add(name AStreamName) Result[bool] {
 	sf.Lock()
 	defer sf.Unlock()
 	sf.log.Debug("kernelWg.Add(): stream='%v'", name)
 	if !sf.isWork.Get() {
-		return fmt.Errorf("kernelWg.Add(): stream=%v, work end", name)
+		err := fmt.Errorf("kernelWg.Add(): stream=%v, work end", name)
+		return NewErr[bool](err)
 	}
 	Hassert(name != "", "kernelWg.Add(): name stream is empty")
 	_, isOk := sf.dictStream[name]
 	Hassert(!isOk, "kernelWg.Add(): stream '%v' already exists", name)
 	sf.dictStream[name] = true
-	return nil
+	return NewOk(true)
 }
 
 // Ожидает окончания работы ожидателя групп

+ 6 - 6
vendor/gitp78su.ipnodns.ru/svi/kern/krn/kmodule/kmodule.go

@@ -85,25 +85,25 @@ func (sf *kModule) sigLive() {
 	var (
 		topic  = sf.name + "_live"
 		iPhase = 0
-		err    error
+		res    Result[bool]
 	)
 	fnPhase := func() {
 		switch iPhase {
 		case 0:
 			sf.strLive.Set("|")
-			err = sf.bus.Publish(ATopic(topic), sf.strLive.Byte())
+			res = sf.bus.Publish(ATopic(topic), sf.strLive.Byte())
 		case 1:
 			sf.strLive.Set("/")
-			err = sf.bus.Publish(ATopic(topic), sf.strLive.Byte())
+			res = sf.bus.Publish(ATopic(topic), sf.strLive.Byte())
 		case 2:
 			sf.strLive.Set("-")
-			err = sf.bus.Publish(ATopic(topic), sf.strLive.Byte())
+			res = sf.bus.Publish(ATopic(topic), sf.strLive.Byte())
 		case 3:
 			sf.strLive.Set("\\")
-			err = sf.bus.Publish(ATopic(topic), sf.strLive.Byte())
+			res = sf.bus.Publish(ATopic(topic), sf.strLive.Byte())
 			iPhase = -1
 		}
-		sf.recErr(err)
+		sf.recErr(res.Error())
 		iPhase++
 		sf.stat.Add(1)
 		time.Sleep(time.Millisecond * time.Duration(sf.timePhase.Get()))

+ 2 - 2
vendor/gitp78su.ipnodns.ru/svi/kern/krn/kserv_http/kserv_http.go

@@ -86,8 +86,8 @@ func GetKernelServHttp() IKernelServerHttp {
 		MaxAge:     3600 * 24,
 	}))
 	sf.fiberApp.Get("/monitor", monitor.New(monitor.Config{Title: ctx.Get("monolitName").Val().(string)}))
-	err := sf.kCtx.Wg().Add(streamName)
-	Hassert(err == nil, "NewKernelServHttp(): in add stream %v, err=\n\t%v", streamName, err)
+	res := sf.kCtx.Wg().Add(streamName)
+	Hassert(res.IsOk(), "NewKernelServHttp(): in add stream %v, err=\n\t%v", streamName, res.Error())
 	ctx.Set("fiberApp", sf.fiberApp, "kServHttp: internal fiber app")
 	kernServHttp = sf
 	ctx.Set("kServHttp", kernServHttp, "kServHttp")

+ 17 - 17
vendor/gitp78su.ipnodns.ru/svi/kern/krn/kstore_kv/kstore_kv.go

@@ -66,7 +66,7 @@ func (sf *kStoreKv) Log() ILogBuf {
 }
 
 // Set -- устанавливает значение по ключу
-func (sf *kStoreKv) Set(key string, val []byte) error {
+func (sf *kStoreKv) Set(key string, val []byte) Result[bool] {
 	sf.Lock()
 	defer sf.Unlock()
 	sf.log.Debug("kStoreKv.Set(): key='%v'", key)
@@ -76,15 +76,15 @@ func (sf *kStoreKv) Set(key string, val []byte) error {
 	}
 	err := sf.db.Update(fnSet)
 	if err != nil {
-		strOut := fmt.Sprintf("kStoreKv.Set(): key=%v, err=\n\t%v", key, err)
-		sf.log.Err(strOut)
-		return fmt.Errorf(strOut, "")
+		err := fmt.Errorf("kStoreKv.Set(): key=%v, err=\n\t%w", key, err)
+		sf.log.Err(err.Error())
+		return NewErr[bool](err)
 	}
-	return nil
+	return NewOk(true)
 }
 
 // Get -- возвращает значение по ключу
-func (sf *kStoreKv) Get(key string) ([]byte, error) {
+func (sf *kStoreKv) Get(key string) Result[[]byte] {
 	sf.RLock()
 	defer sf.RUnlock()
 	sf.log.Debug("kStoreKv.Get(): key='%v'", key)
@@ -99,15 +99,15 @@ func (sf *kStoreKv) Get(key string) ([]byte, error) {
 	}
 	err := sf.db.View(fnGet)
 	if err != nil {
-		strOut := fmt.Sprintf("kStoreKv.Get(): key=%v, err=\n\t%v", key, err)
-		sf.log.Err(strOut)
-		return nil, fmt.Errorf(strOut, "")
+		err := fmt.Errorf("kStoreKv.Get(): key=%v, err=\n\t%v", key, err)
+		sf.log.Err(err.Error())
+		return NewErr[[]byte](err)
 	}
-	return binVal, nil
+	return NewOk(binVal)
 }
 
 // Delete -- удалить ключ из хранилища
-func (sf *kStoreKv) Delete(key string) error {
+func (sf *kStoreKv) Delete(key string) Result[bool] {
 	sf.Lock()
 	defer sf.Unlock()
 	sf.log.Debug("kStoreKv.Delete(): key='%v'", key)
@@ -117,11 +117,11 @@ func (sf *kStoreKv) Delete(key string) error {
 	}
 	err := sf.db.Update(fnDelete)
 	if err != nil {
-		strOut := fmt.Sprintf("kStoreKv.Delete(): key=%v, err=\n\t%v", key, err)
-		sf.log.Err(strOut)
-		return fmt.Errorf(strOut, "")
+		err := fmt.Errorf("kStoreKv.Delete(): key=%v, err=\n\t%w", key, err)
+		sf.log.Err(err.Error())
+		return NewErr[bool](err)
 	}
-	return nil
+	return NewOk(true)
 }
 
 // Открывает базу при создании
@@ -138,8 +138,8 @@ func (sf *kStoreKv) open() {
 	Hassert(err == nil, "kStoreKv.open(): in make dir %v, err=\n\t%v", sf.storePath, err)
 	sf.db, err = badger.Open(badger.DefaultOptions(sf.storePath))
 	Hassert(err == nil, "kStoreKv.open(): in open DB %v, err=\n\t%v", sf.storePath, err)
-	err = sf.wg.Add(storeStreamName)
-	Hassert(err == nil, "kStoreKv.open(): in add name stream to IKernelWg, err=\n\t%v", err)
+	res := sf.wg.Add(storeStreamName)
+	Hassert(res.IsOk(), "kStoreKv.open(): in add name stream to IKernelWg, err=\n\t%v", res.Error())
 	sf.isWork.Set()
 	go sf.close()
 	go sf.clean()

+ 5 - 5
vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/ikernel_bus.go

@@ -23,7 +23,7 @@ type IBusHandlerSubscribe interface {
 type IBusHandlerServe interface {
 	IBusBaseHandler
 	// FnBack -- функция обратного вызова
-	FnBack(binReq []byte) (binResp []byte, err error)
+	FnBack(binReq []byte) Result[[]byte]
 }
 
 // IDictSubHook -- словарь обработчиков по единственному топик
@@ -56,7 +56,7 @@ type IDictTopicServe interface {
 	// Register -- регистрирует единственный обработчик на единственный топик
 	Register(IBusHandlerServe)
 	// SendRequest -- выполняет запрос по указанному топику
-	SendRequest(topic ATopic, binReq []byte) (binResp []byte, errResp error)
+	SendRequest(topic ATopic, binReq []byte) Result[[]byte]
 	// Unregister -- удаляет единственный обработчик с единственного топика
 	Unregister(IBusHandlerServe)
 }
@@ -67,12 +67,12 @@ type IDictTopicServe interface {
 //	Подписка и обслуживание входящих запросов требует _обработчиков_.
 type IKernelBus interface {
 	// Publish -- публикует сообщение в шину
-	Publish(topic ATopic, binMsg []byte) error
+	Publish(topic ATopic, binMsg []byte) Result[bool]
 	// SendRequest -- выполняет запрос по указанному топику
-	SendRequest(topic ATopic, binReq []byte) (binResp []byte, errResp error)
+	SendRequest(topic ATopic, binReq []byte) Result[[]byte]
 
 	// Subscribe -- подписывает обработчик на топик
-	Subscribe(IBusHandlerSubscribe) error
+	Subscribe(IBusHandlerSubscribe) Result[bool]
 	// Unsubscribe -- отписывается от топика
 	Unsubscribe(IBusHandlerSubscribe)
 	// RegisterServe -- Регистрирует обработчик на обслуживание входящих запросов

+ 3 - 3
vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/ikernel_store.go

@@ -3,11 +3,11 @@ package ktypes
 // IKernelStoreKv -- интерфейс к локальному быстрому key-value хранилищу ядра
 type IKernelStoreKv interface {
 	// Get -- возвращает значение по ключу
-	Get(key string) ([]byte, error)
+	Get(key string) Result[[]byte]
 	// Set -- устанавливает значение по ключу
-	Set(key string, val []byte) error
+	Set(key string, val []byte) Result[bool]
 	// Delete -- удаляет значение по ключу
-	Delete(key string) error
+	Delete(key string) Result[bool]
 	// Log -- возвращает локальный лог
 	Log() ILogBuf
 }

+ 1 - 1
vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/ikernel_wg.go

@@ -7,7 +7,7 @@ import (
 // IKernelWg -- интерфейс к именованному ожидателю потоков
 type IKernelWg interface {
 	// Add -- добавляет имя потока в ожидатель потоков
-	Add(AStreamName) error
+	Add(AStreamName) Result[bool]
 	// Done -- удаляет имя потока из ожидания
 	Done(AStreamName)
 	// Wait -- ожидает завершения работы всех потоков

+ 74 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/koption.go

@@ -0,0 +1,74 @@
+package ktypes
+
+import (
+	"reflect"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+)
+
+// Option -- результат возможно содержащий nil
+type Option[T any] struct {
+	val *T
+}
+
+// NewSome - полезный результат
+func NewSome[T any](value T) Option[T] {
+	// Для некоторых типов нужна дополнительная проверка через reflect
+	v := reflect.ValueOf(value)
+	switch v.Kind() {
+	case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Chan, reflect.Func, reflect.Interface:
+		Hassert(!v.IsNil(), "NewSome[T any](): value==nil")
+	}
+	sf := Option[T]{val: &value}
+	return sf
+}
+
+// NewNone - нет результата в ответе
+func NewNone[T any]() Option[T] {
+	return Option[T]{
+		val: nil,
+	}
+}
+
+// IsSome - проверяет, есть ли значение
+func (sf *Option[T]) IsSome() bool {
+	return sf.val != nil
+}
+
+// IsSome - проверяет, есть ли значение
+func (sf *Option[T]) IsNone() bool {
+	return sf.val == nil
+}
+
+// Unwrap - извлекает значение (паника, если None)
+func (sf *Option[T]) Unwrap() T {
+	Hassert(sf.val != nil, "Option[T].Unwrap(): val==nil!")
+	return *sf.val
+}
+
+// UnwrapOr - возвращает значение или дефолтное
+func (sf Option[T]) UnwrapOr(defaultValue T) T {
+	if sf.val == nil {
+		return defaultValue
+	}
+	return *sf.val
+}
+
+// UnwrapOrFn -- возвращает значение, если оно есть, или результат выполнения функции
+func (sf *Option[T]) UnwrapOrFn(fn func() T) T {
+	Hassert(fn != nil, "Result[T].UnwrapOrFn(): fn==nil")
+	if sf.val == nil {
+		return fn()
+	}
+	return *sf.val
+}
+
+// Hassert -- проверяет, что нет ошибки (с паникой)
+func (sf *Option[T]) Hassert(msgFormat string, args ...any) {
+	Hassert(sf.val != nil, msgFormat, args...)
+}
+
+// Assert -- проверяет, что нет ошибки (с паникой только на локальном стенде)
+func (sf *Option[T]) Assert(msgFormat string, args ...any) {
+	Assert(sf.val != nil, msgFormat, args...)
+}

+ 88 - 0
vendor/gitp78su.ipnodns.ru/svi/kern/krn/ktypes/kresult.go

@@ -0,0 +1,88 @@
+package ktypes
+
+import (
+	"fmt"
+	"reflect"
+
+	. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
+)
+
+// Result — обёртка вокруг результата с возможной ошибкой
+//
+// Может быть либо только полезное значение, либо только ошибка
+type Result[T any] struct {
+	val T     // Полезное значение
+	err error // Ошибка
+}
+
+// NewOk -- возвращает успешный Result с значением
+func NewOk[T any](result T) Result[T] {
+	// Для некоторых типов нужна дополнительная проверка через reflect
+	v := reflect.ValueOf(result)
+	switch v.Kind() {
+	case reflect.Ptr, reflect.Slice, reflect.Map, reflect.Chan, reflect.Func, reflect.Interface:
+		Hassert(!v.IsNil(), "NewOk(): result==nil")
+	}
+	sf := Result[T]{
+		val: result,
+	}
+	return sf
+}
+
+// NewErr -- возвращает Result с ошибкой
+func NewErr[T any](err error) Result[T] {
+	Hassert(err != nil, "NewError(): err==nil")
+	return Result[T]{
+		err: err,
+	}
+}
+
+// IsOk -- возвращает true, если Result содержит значение
+func (sf *Result[T]) IsOk() bool {
+	return sf.err == nil
+}
+
+// IsErr -- возвращает true, если Result содержит ошибку
+func (sf *Result[T]) IsErr() bool {
+	return sf.err != nil
+}
+
+// Unwrap -- возвращает значение, если оно есть, иначе паникует
+func (sf *Result[T]) Unwrap() T {
+	Hassert(sf.err == nil, "Result[T].Unwrap(): err(%v)!=nil", sf.err)
+	return sf.val
+}
+
+// UnwrapOr -- возвращает значение, если оно есть, или значение по умолчанию
+func (sf *Result[T]) UnwrapOr(defaultValue T) T {
+	if sf.err != nil {
+		return defaultValue
+	}
+	return sf.val
+}
+
+// UnwrapOrFn -- возвращает значение, если оно есть, или результат выполнения функции
+func (sf *Result[T]) UnwrapOrFn(fn func() T) T {
+	Hassert(fn != nil, "Result[T].UnwrapOrFn(): fn==nil")
+	if sf.err != nil {
+		return fn()
+	}
+	return sf.val
+}
+
+// Error -- возвращает ошибку, если она есть
+func (sf *Result[T]) Error() error {
+	return sf.err
+}
+
+// Hassert -- проверяет, что нет ошибки (с паникой)
+func (sf *Result[T]) Hassert(msgFormat string, args ...any) {
+	msg := fmt.Sprintf(msgFormat, args...)
+	Hassert(sf.err == nil, msg+", err=\n\t%v\n", sf.err)
+}
+
+// Assert -- проверяет, что нет ошибки (с паникой только на локальном стенде)
+func (sf *Result[T]) Assert(msgFormat string, args ...any) {
+	msg := fmt.Sprintf(msgFormat, args...)
+	Assert(sf.err == nil, msg+", err=\n\t%v\n", sf.err)
+}

二進制
vendor/google.golang.org/protobuf/internal/editiondefaults/editions_defaults.binpb


+ 3 - 0
vendor/google.golang.org/protobuf/internal/filedesc/editions.go

@@ -69,6 +69,9 @@ func unmarshalFeatureSet(b []byte, parent EditionFeatures) EditionFeatures {
 				parent.IsDelimitedEncoded = v == genid.FeatureSet_DELIMITED_enum_value
 			case genid.FeatureSet_JsonFormat_field_number:
 				parent.IsJSONCompliant = v == genid.FeatureSet_ALLOW_enum_value
+			case genid.FeatureSet_EnforceNamingStyle_field_number:
+				// EnforceNamingStyle is enforced in protoc, languages other than C++
+				// are not supposed to do anything with this feature.
 			default:
 				panic(fmt.Sprintf("unkown field number %d while unmarshalling FeatureSet", num))
 			}

+ 16 - 0
vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go

@@ -1014,6 +1014,7 @@ const (
 	FeatureSet_Utf8Validation_field_name        protoreflect.Name = "utf8_validation"
 	FeatureSet_MessageEncoding_field_name       protoreflect.Name = "message_encoding"
 	FeatureSet_JsonFormat_field_name            protoreflect.Name = "json_format"
+	FeatureSet_EnforceNamingStyle_field_name    protoreflect.Name = "enforce_naming_style"
 
 	FeatureSet_FieldPresence_field_fullname         protoreflect.FullName = "google.protobuf.FeatureSet.field_presence"
 	FeatureSet_EnumType_field_fullname              protoreflect.FullName = "google.protobuf.FeatureSet.enum_type"
@@ -1021,6 +1022,7 @@ const (
 	FeatureSet_Utf8Validation_field_fullname        protoreflect.FullName = "google.protobuf.FeatureSet.utf8_validation"
 	FeatureSet_MessageEncoding_field_fullname       protoreflect.FullName = "google.protobuf.FeatureSet.message_encoding"
 	FeatureSet_JsonFormat_field_fullname            protoreflect.FullName = "google.protobuf.FeatureSet.json_format"
+	FeatureSet_EnforceNamingStyle_field_fullname    protoreflect.FullName = "google.protobuf.FeatureSet.enforce_naming_style"
 )
 
 // Field numbers for google.protobuf.FeatureSet.
@@ -1031,6 +1033,7 @@ const (
 	FeatureSet_Utf8Validation_field_number        protoreflect.FieldNumber = 4
 	FeatureSet_MessageEncoding_field_number       protoreflect.FieldNumber = 5
 	FeatureSet_JsonFormat_field_number            protoreflect.FieldNumber = 6
+	FeatureSet_EnforceNamingStyle_field_number    protoreflect.FieldNumber = 7
 )
 
 // Full and short names for google.protobuf.FeatureSet.FieldPresence.
@@ -1112,6 +1115,19 @@ const (
 	FeatureSet_LEGACY_BEST_EFFORT_enum_value  = 2
 )
 
+// Full and short names for google.protobuf.FeatureSet.EnforceNamingStyle.
+const (
+	FeatureSet_EnforceNamingStyle_enum_fullname = "google.protobuf.FeatureSet.EnforceNamingStyle"
+	FeatureSet_EnforceNamingStyle_enum_name     = "EnforceNamingStyle"
+)
+
+// Enum values for google.protobuf.FeatureSet.EnforceNamingStyle.
+const (
+	FeatureSet_ENFORCE_NAMING_STYLE_UNKNOWN_enum_value = 0
+	FeatureSet_STYLE2024_enum_value                    = 1
+	FeatureSet_STYLE_LEGACY_enum_value                 = 2
+)
+
 // Names for google.protobuf.FeatureSetDefaults.
 const (
 	FeatureSetDefaults_message_name     protoreflect.Name     = "FeatureSetDefaults"

+ 0 - 2
vendor/google.golang.org/protobuf/internal/strs/strings_unsafe_go121.go → vendor/google.golang.org/protobuf/internal/strs/strings_unsafe.go

@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build go1.21
-
 package strs
 
 import (

+ 0 - 94
vendor/google.golang.org/protobuf/internal/strs/strings_unsafe_go120.go

@@ -1,94 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !go1.21
-
-package strs
-
-import (
-	"unsafe"
-
-	"google.golang.org/protobuf/reflect/protoreflect"
-)
-
-type (
-	stringHeader struct {
-		Data unsafe.Pointer
-		Len  int
-	}
-	sliceHeader struct {
-		Data unsafe.Pointer
-		Len  int
-		Cap  int
-	}
-)
-
-// UnsafeString returns an unsafe string reference of b.
-// The caller must treat the input slice as immutable.
-//
-// WARNING: Use carefully. The returned result must not leak to the end user
-// unless the input slice is provably immutable.
-func UnsafeString(b []byte) (s string) {
-	src := (*sliceHeader)(unsafe.Pointer(&b))
-	dst := (*stringHeader)(unsafe.Pointer(&s))
-	dst.Data = src.Data
-	dst.Len = src.Len
-	return s
-}
-
-// UnsafeBytes returns an unsafe bytes slice reference of s.
-// The caller must treat returned slice as immutable.
-//
-// WARNING: Use carefully. The returned result must not leak to the end user.
-func UnsafeBytes(s string) (b []byte) {
-	src := (*stringHeader)(unsafe.Pointer(&s))
-	dst := (*sliceHeader)(unsafe.Pointer(&b))
-	dst.Data = src.Data
-	dst.Len = src.Len
-	dst.Cap = src.Len
-	return b
-}
-
-// Builder builds a set of strings with shared lifetime.
-// This differs from strings.Builder, which is for building a single string.
-type Builder struct {
-	buf []byte
-}
-
-// AppendFullName is equivalent to protoreflect.FullName.Append,
-// but optimized for large batches where each name has a shared lifetime.
-func (sb *Builder) AppendFullName(prefix protoreflect.FullName, name protoreflect.Name) protoreflect.FullName {
-	n := len(prefix) + len(".") + len(name)
-	if len(prefix) == 0 {
-		n -= len(".")
-	}
-	sb.grow(n)
-	sb.buf = append(sb.buf, prefix...)
-	sb.buf = append(sb.buf, '.')
-	sb.buf = append(sb.buf, name...)
-	return protoreflect.FullName(sb.last(n))
-}
-
-// MakeString is equivalent to string(b), but optimized for large batches
-// with a shared lifetime.
-func (sb *Builder) MakeString(b []byte) string {
-	sb.grow(len(b))
-	sb.buf = append(sb.buf, b...)
-	return sb.last(len(b))
-}
-
-func (sb *Builder) grow(n int) {
-	if cap(sb.buf)-len(sb.buf) >= n {
-		return
-	}
-
-	// Unlike strings.Builder, we do not need to copy over the contents
-	// of the old buffer since our builder provides no API for
-	// retrieving previously created strings.
-	sb.buf = make([]byte, 0, 2*(cap(sb.buf)+n))
-}
-
-func (sb *Builder) last(n int) string {
-	return UnsafeString(sb.buf[len(sb.buf)-n:])
-}

+ 1 - 1
vendor/google.golang.org/protobuf/internal/version/version.go

@@ -52,7 +52,7 @@ import (
 const (
 	Major      = 1
 	Minor      = 36
-	Patch      = 5
+	Patch      = 6
 	PreRelease = ""
 )
 

+ 6 - 0
vendor/google.golang.org/protobuf/proto/merge.go

@@ -59,6 +59,12 @@ func Clone(m Message) Message {
 	return dst.Interface()
 }
 
+// CloneOf returns a deep copy of m. If the top-level message is invalid,
+// it returns an invalid message as well.
+func CloneOf[M Message](m M) M {
+	return Clone(m).(M)
+}
+
 // mergeOptions provides a namespace for merge functions, and can be
 // exported in the future if we add user-visible merge options.
 type mergeOptions struct{}

+ 2 - 0
vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go

@@ -398,6 +398,8 @@ func (p *SourcePath) appendFeatureSet(b []byte) []byte {
 		b = p.appendSingularField(b, "message_encoding", nil)
 	case 6:
 		b = p.appendSingularField(b, "json_format", nil)
+	case 7:
+		b = p.appendSingularField(b, "enforce_naming_style", nil)
 	}
 	return b
 }

+ 0 - 2
vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go121.go → vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe.go

@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build go1.21
-
 package protoreflect
 
 import (

+ 0 - 98
vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go120.go

@@ -1,98 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !go1.21
-
-package protoreflect
-
-import (
-	"unsafe"
-
-	"google.golang.org/protobuf/internal/pragma"
-)
-
-type (
-	stringHeader struct {
-		Data unsafe.Pointer
-		Len  int
-	}
-	sliceHeader struct {
-		Data unsafe.Pointer
-		Len  int
-		Cap  int
-	}
-	ifaceHeader struct {
-		Type unsafe.Pointer
-		Data unsafe.Pointer
-	}
-)
-
-var (
-	nilType     = typeOf(nil)
-	boolType    = typeOf(*new(bool))
-	int32Type   = typeOf(*new(int32))
-	int64Type   = typeOf(*new(int64))
-	uint32Type  = typeOf(*new(uint32))
-	uint64Type  = typeOf(*new(uint64))
-	float32Type = typeOf(*new(float32))
-	float64Type = typeOf(*new(float64))
-	stringType  = typeOf(*new(string))
-	bytesType   = typeOf(*new([]byte))
-	enumType    = typeOf(*new(EnumNumber))
-)
-
-// typeOf returns a pointer to the Go type information.
-// The pointer is comparable and equal if and only if the types are identical.
-func typeOf(t any) unsafe.Pointer {
-	return (*ifaceHeader)(unsafe.Pointer(&t)).Type
-}
-
-// value is a union where only one type can be represented at a time.
-// The struct is 24B large on 64-bit systems and requires the minimum storage
-// necessary to represent each possible type.
-//
-// The Go GC needs to be able to scan variables containing pointers.
-// As such, pointers and non-pointers cannot be intermixed.
-type value struct {
-	pragma.DoNotCompare // 0B
-
-	// typ stores the type of the value as a pointer to the Go type.
-	typ unsafe.Pointer // 8B
-
-	// ptr stores the data pointer for a String, Bytes, or interface value.
-	ptr unsafe.Pointer // 8B
-
-	// num stores a Bool, Int32, Int64, Uint32, Uint64, Float32, Float64, or
-	// Enum value as a raw uint64.
-	//
-	// It is also used to store the length of a String or Bytes value;
-	// the capacity is ignored.
-	num uint64 // 8B
-}
-
-func valueOfString(v string) Value {
-	p := (*stringHeader)(unsafe.Pointer(&v))
-	return Value{typ: stringType, ptr: p.Data, num: uint64(len(v))}
-}
-func valueOfBytes(v []byte) Value {
-	p := (*sliceHeader)(unsafe.Pointer(&v))
-	return Value{typ: bytesType, ptr: p.Data, num: uint64(len(v))}
-}
-func valueOfIface(v any) Value {
-	p := (*ifaceHeader)(unsafe.Pointer(&v))
-	return Value{typ: p.Type, ptr: p.Data}
-}
-
-func (v Value) getString() (x string) {
-	*(*stringHeader)(unsafe.Pointer(&x)) = stringHeader{Data: v.ptr, Len: int(v.num)}
-	return x
-}
-func (v Value) getBytes() (x []byte) {
-	*(*sliceHeader)(unsafe.Pointer(&x)) = sliceHeader{Data: v.ptr, Len: int(v.num), Cap: int(v.num)}
-	return x
-}
-func (v Value) getIface() (x any) {
-	*(*ifaceHeader)(unsafe.Pointer(&x)) = ifaceHeader{Type: v.typ, Data: v.ptr}
-	return x
-}

+ 5 - 5
vendor/modules.txt

@@ -104,8 +104,8 @@ github.com/valyala/fasthttp/fasthttputil
 github.com/valyala/fasthttp/reuseport
 github.com/valyala/fasthttp/stackless
 github.com/valyala/fasthttp/tcplisten
-# gitp78su.ipnodns.ru/svi/kern v1.11.0
-## explicit; go 1.24.0
+# gitp78su.ipnodns.ru/svi/kern v1.15.0
+## explicit; go 1.23.0
 gitp78su.ipnodns.ru/svi/kern
 gitp78su.ipnodns.ru/svi/kern/kc/helpers
 gitp78su.ipnodns.ru/svi/kern/kc/local_ctx
@@ -192,7 +192,7 @@ go.opentelemetry.io/otel/trace
 go.opentelemetry.io/otel/trace/embedded
 go.opentelemetry.io/otel/trace/internal/telemetry
 go.opentelemetry.io/otel/trace/noop
-# golang.org/x/net v0.37.0
+# golang.org/x/net v0.38.0
 ## explicit; go 1.23.0
 golang.org/x/net/internal/timeseries
 golang.org/x/net/trace
@@ -200,8 +200,8 @@ golang.org/x/net/trace
 ## explicit; go 1.23.0
 golang.org/x/sys/unix
 golang.org/x/sys/windows
-# google.golang.org/protobuf v1.36.5
-## explicit; go 1.21
+# google.golang.org/protobuf v1.36.6
+## explicit; go 1.22
 google.golang.org/protobuf/encoding/prototext
 google.golang.org/protobuf/encoding/protowire
 google.golang.org/protobuf/internal/descfmt