@coopenomics/desktop 2025.11.28-alpha-2 → 2025.11.29-alpha-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coopenomics/desktop",
|
|
3
|
-
"version": "2025.11.
|
|
3
|
+
"version": "2025.11.29-alpha-1",
|
|
4
4
|
"description": "A Desktop Project",
|
|
5
5
|
"productName": "Desktop App",
|
|
6
6
|
"author": "Alex Ant <dacom.dark.sun@gmail.com>",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"start": "node -r ./alias-resolver.js dist/ssr/index.js"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@coopenomics/controller": "2025.11.
|
|
29
|
-
"@coopenomics/notifications": "2025.11.
|
|
30
|
-
"@coopenomics/sdk": "2025.11.
|
|
28
|
+
"@coopenomics/controller": "2025.11.29-alpha-1",
|
|
29
|
+
"@coopenomics/notifications": "2025.11.29-alpha-1",
|
|
30
|
+
"@coopenomics/sdk": "2025.11.29-alpha-1",
|
|
31
31
|
"@dicebear/collection": "^9.0.1",
|
|
32
32
|
"@dicebear/core": "^9.0.1",
|
|
33
33
|
"@editorjs/code": "^2.9.3",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"@wharfkit/wallet-plugin-privatekey": "^1.1.0",
|
|
60
60
|
"axios": "^1.2.1",
|
|
61
61
|
"compression": "^1.7.4",
|
|
62
|
-
"cooptypes": "2025.11.
|
|
62
|
+
"cooptypes": "2025.11.29-alpha-1",
|
|
63
63
|
"dompurify": "^3.1.7",
|
|
64
64
|
"dotenv": "^16.4.5",
|
|
65
65
|
"email-regex": "^5.0.0",
|
|
@@ -123,5 +123,5 @@
|
|
|
123
123
|
"npm": ">= 6.13.4",
|
|
124
124
|
"yarn": ">= 1.21.1"
|
|
125
125
|
},
|
|
126
|
-
"gitHead": "
|
|
126
|
+
"gitHead": "e4d0781eb86ea8e54d7b01533b689f47ea086ef7"
|
|
127
127
|
}
|
|
@@ -6,6 +6,11 @@ import { Zeus } from '@coopenomics/sdk';
|
|
|
6
6
|
|
|
7
7
|
const namespace = 'systemStore';
|
|
8
8
|
|
|
9
|
+
// Константы для экспоненциального backoff
|
|
10
|
+
const BASE_INTERVAL_MS = 30000; // Базовый интервал 30 секунд (было 10)
|
|
11
|
+
const MAX_INTERVAL_MS = 300000; // Максимальный интервал 5 минут
|
|
12
|
+
const BACKOFF_MULTIPLIER = 2; // Множитель для backoff
|
|
13
|
+
|
|
9
14
|
interface ISystemStore {
|
|
10
15
|
info: Ref<ISystemInfo>;
|
|
11
16
|
backendAvailable: Ref<boolean>;
|
|
@@ -21,44 +26,96 @@ export const useSystemStore = defineStore(namespace, (): ISystemStore => {
|
|
|
21
26
|
} as ISystemInfo);
|
|
22
27
|
const backendAvailable = ref<boolean>(true);
|
|
23
28
|
const maintenanceCounter = ref<number>(0); // Счетчик для принудительного обновления
|
|
24
|
-
|
|
29
|
+
|
|
30
|
+
let monitoringTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
31
|
+
let isLoading = false; // Защита от конкурентных запросов
|
|
32
|
+
let currentInterval = BASE_INTERVAL_MS; // Текущий интервал (для backoff)
|
|
33
|
+
let consecutiveErrors = 0; // Счетчик последовательных ошибок
|
|
25
34
|
|
|
26
35
|
const loadSystemInfo = async () => {
|
|
36
|
+
// Защита от конкурентных запросов
|
|
37
|
+
if (isLoading) {
|
|
38
|
+
console.debug('loadSystemInfo: запрос уже выполняется, пропускаем');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
isLoading = true;
|
|
27
43
|
try {
|
|
28
44
|
info.value = await api.loadSystemInfo();
|
|
29
45
|
backendAvailable.value = true;
|
|
30
46
|
triggerRef(info); // Принудительно триггерим реактивность
|
|
47
|
+
|
|
48
|
+
// При успехе сбрасываем backoff
|
|
49
|
+
consecutiveErrors = 0;
|
|
50
|
+
currentInterval = BASE_INTERVAL_MS;
|
|
31
51
|
} catch (error) {
|
|
32
52
|
console.warn('Failed to load system info, backend might be unavailable:', error);
|
|
33
53
|
backendAvailable.value = false;
|
|
34
54
|
// При недоступности бэкенда устанавливаем статус обслуживания
|
|
35
55
|
info.value.system_status = Zeus.SystemStatus.maintenance;
|
|
56
|
+
|
|
57
|
+
// Увеличиваем интервал при ошибках (экспоненциальный backoff)
|
|
58
|
+
consecutiveErrors++;
|
|
59
|
+
currentInterval = Math.min(
|
|
60
|
+
BASE_INTERVAL_MS * Math.pow(BACKOFF_MULTIPLIER, consecutiveErrors),
|
|
61
|
+
MAX_INTERVAL_MS
|
|
62
|
+
);
|
|
63
|
+
console.debug(`Backoff: следующая попытка через ${currentInterval / 1000} секунд`);
|
|
64
|
+
|
|
36
65
|
throw error; // Перебрасываем ошибку для обработки выше
|
|
66
|
+
} finally {
|
|
67
|
+
isLoading = false;
|
|
37
68
|
}
|
|
38
69
|
};
|
|
39
70
|
|
|
40
|
-
const
|
|
41
|
-
//
|
|
71
|
+
const scheduleNextCheck = () => {
|
|
72
|
+
// КРИТИЧНО: Не запускаем мониторинг на сервере (SSR)
|
|
73
|
+
// В SSR setInterval/setTimeout создают утечки памяти и накапливают запросы
|
|
74
|
+
if (typeof window === 'undefined') {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
42
78
|
stopSystemMonitoring();
|
|
43
79
|
|
|
44
|
-
|
|
45
|
-
monitoringInterval = setInterval(async () => {
|
|
80
|
+
monitoringTimeout = setTimeout(async () => {
|
|
46
81
|
try {
|
|
47
82
|
await loadSystemInfo();
|
|
48
83
|
} catch (error) {
|
|
49
84
|
console.warn('Failed to update system info during monitoring:', error);
|
|
50
85
|
// При недоступности бэкенда устанавливаем статус обслуживания
|
|
51
86
|
backendAvailable.value = false;
|
|
52
|
-
info.value.system_status = Zeus.SystemStatus.maintenance;
|
|
87
|
+
info.value.system_status = Zeus.SystemStatus.maintenance;
|
|
53
88
|
maintenanceCounter.value++; // Увеличиваем счетчик для триггера watch
|
|
54
89
|
}
|
|
55
|
-
|
|
90
|
+
|
|
91
|
+
// Планируем следующую проверку с учетом возможного backoff
|
|
92
|
+
scheduleNextCheck();
|
|
93
|
+
}, currentInterval);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const startSystemMonitoring = () => {
|
|
97
|
+
// КРИТИЧНО: Не запускаем мониторинг на сервере (SSR)
|
|
98
|
+
// Это предотвращает утечку таймеров и самоDDoS
|
|
99
|
+
if (typeof window === 'undefined') {
|
|
100
|
+
console.debug('startSystemMonitoring: пропускаем на сервере (SSR)');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Останавливаем существующий мониторинг, если он есть
|
|
105
|
+
stopSystemMonitoring();
|
|
106
|
+
|
|
107
|
+
// Сбрасываем backoff при явном старте мониторинга
|
|
108
|
+
consecutiveErrors = 0;
|
|
109
|
+
currentInterval = BASE_INTERVAL_MS;
|
|
110
|
+
|
|
111
|
+
// Используем setTimeout вместо setInterval для гибкого управления интервалом
|
|
112
|
+
scheduleNextCheck();
|
|
56
113
|
};
|
|
57
114
|
|
|
58
115
|
const stopSystemMonitoring = () => {
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
|
|
116
|
+
if (monitoringTimeout) {
|
|
117
|
+
clearTimeout(monitoringTimeout);
|
|
118
|
+
monitoringTimeout = null;
|
|
62
119
|
}
|
|
63
120
|
};
|
|
64
121
|
|
|
@@ -8,19 +8,30 @@ import { useInitExtensionsProcess } from 'src/processes/init-installed-extension
|
|
|
8
8
|
import { applyThemeFromStorage } from 'src/shared/lib/utils';
|
|
9
9
|
import { useSessionStore } from 'src/entities/Session';
|
|
10
10
|
|
|
11
|
+
// Проверка, работаем ли мы на сервере (SSR)
|
|
12
|
+
const isServer = typeof window === 'undefined';
|
|
13
|
+
|
|
11
14
|
export async function useInitAppProcess(router: Router) {
|
|
12
15
|
applyThemeFromStorage();
|
|
13
16
|
const system = useSystemStore();
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
// Загружаем системную информацию только на клиенте
|
|
19
|
+
// На сервере SSR это создает лишнюю нагрузку и задержку рендеринга
|
|
20
|
+
if (!isServer) {
|
|
21
|
+
try {
|
|
22
|
+
await system.loadSystemInfo();
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.warn('Failed to load initial system info, backend might be unavailable:', error);
|
|
25
|
+
// Продолжаем инициализацию даже при недоступности бэкенда
|
|
26
|
+
}
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
// Запускаем мониторинг системной информации для отслеживания статуса
|
|
23
|
-
|
|
30
|
+
// Метод startSystemMonitoring сам проверяет SSR, но явная проверка здесь
|
|
31
|
+
// делает код более понятным и предотвращает лишние вызовы
|
|
32
|
+
if (!isServer) {
|
|
33
|
+
system.startSystemMonitoring();
|
|
34
|
+
}
|
|
24
35
|
|
|
25
36
|
const desktops = useDesktopStore();
|
|
26
37
|
|