diff --git a/core/src/main/java/ru/kirillius/pf/sdn/core/Config.java b/core/src/main/java/ru/kirillius/pf/sdn/core/Config.java index e475006..c4af32a 100644 --- a/core/src/main/java/ru/kirillius/pf/sdn/core/Config.java +++ b/core/src/main/java/ru/kirillius/pf/sdn/core/Config.java @@ -66,7 +66,7 @@ public class Config { @Setter @Getter @JSONProperty - private volatile File cacheDirectory = new File("./.cache"); + private volatile File cacheDirectory = new File("/var/cache/pf-sdn"); /** * List of subscription sources @@ -74,7 +74,7 @@ public class Config { @Setter @Getter @JSONArrayProperty(type = RepositoryConfig.class) - private volatile List subscriptions = new ArrayList<>(); + private volatile List subscriptions = new ArrayList<>(); /** * List of subscribed resources @@ -189,7 +189,7 @@ public class Config { try (var fileInputStream = new FileOutputStream(file)) { try (var writer = new BufferedWriter(new OutputStreamWriter(fileInputStream))) { var json = serialize(config); - writer.write(json.toString()); + writer.write(json.toString(4)); writer.flush(); config.initialJSON = json; } diff --git a/launcher.sh b/launcher.sh index 4074cc5..dbb3e41 100644 --- a/launcher.sh +++ b/launcher.sh @@ -148,7 +148,7 @@ while true; do # Функция для запуска Java run_java() { - java -jar "$LIBRARY/$VER.pfapp" -c="$CFGPATH" -l="$LIBRARY" -r="$REPO_URL" & + java -Xmx256m -jar "$LIBRARY/$VER.pfapp" -c="$CFGPATH" -l="$LIBRARY" -r="$REPO_URL" & CPID=$! wait $CPID } diff --git a/webui/src/pages/Logs.js b/webui/src/pages/Logs.js index 026eae7..a6a706d 100644 --- a/webui/src/pages/Logs.js +++ b/webui/src/pages/Logs.js @@ -4,6 +4,7 @@ import { JSONRPC } from '@/json-rpc.js'; const MAX_PREVIEW_LENGTH = "[06.10.2025 01:14:00][SEVERE] ShellExecutor> Failed to execute local shell command \"rc-service openvpn restart\"\r\nIOException:Cannot run program \"rc-service openvpn restart\": Exec failed, error: 2 (Нет такого файла или каталога) \nStack trace:\njava.base/".length; let logs = []; +let hasRendered = false; let isLoading = false; let refreshIntervalId = null; @@ -106,8 +107,45 @@ function createLogEntryHtml(entry, index) { `; } +function serializeLogEntry(entry) { + if (Array.isArray(entry)) { + return `[${entry.map(serializeLogEntry).join(',')}]`; + } + + if (entry && typeof entry === 'object') { + const keys = Object.keys(entry).sort(); + const serialized = keys.map((key) => `${JSON.stringify(key)}:${serializeLogEntry(entry[key])}`); + return `{${serialized.join(',')}}`; + } + + return JSON.stringify(entry); +} + +function haveLogsChanged(previousLogs, nextLogs) { + if (previousLogs === nextLogs) { + return false; + } + + if (!Array.isArray(previousLogs) || !Array.isArray(nextLogs)) { + return true; + } + + if (previousLogs.length !== nextLogs.length) { + return true; + } + + for (let index = 0; index < previousLogs.length; index += 1) { + if (serializeLogEntry(previousLogs[index]) !== serializeLogEntry(nextLogs[index])) { + return true; + } + } + + return false; +} + function renderLogs() { const $list = $(`#${FIELD_IDS.list}`); + hasRendered = true; if (!logs.length) { $list.html('

Записей в журнале нет.

'); return; @@ -128,7 +166,14 @@ async function loadLogs() { try { const entries = await JSONRPC.System.getLogs(); - logs = Array.isArray(entries) ? entries : []; + const nextLogs = Array.isArray(entries) ? entries : []; + const shouldRender = !hasRendered || haveLogsChanged(logs, nextLogs); + + if (!shouldRender) { + return; + } + + logs = nextLogs.slice(); renderLogs(); } catch (error) { console.error('Ошибка загрузки логов:', error); @@ -206,6 +251,7 @@ export const LogsPage = { unmount: () => { detachEventHandlers(); logs = []; + hasRendered = false; isLoading = false; if (refreshIntervalId) { clearInterval(refreshIntervalId);