fix(mtproto): harden panel + deploy visibility

- Rename snapshot to snap; bust app.js cache (?v).\n- /health returns version from package.json; startup log prints v.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Андрей Бобырев
2026-05-15 03:41:49 +03:00
parent 6c2698c106
commit eaee4d78f7
4 changed files with 30 additions and 17 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "amnezia-admin", "name": "amnezia-admin",
"version": "1.2.17", "version": "1.2.18",
"private": true, "private": true,
"description": "amnezia_web — базовая панель AmneziaWG (FREE: просмотр и удаление клиентов; полная версия — PRO).", "description": "amnezia_web — базовая панель AmneziaWG (FREE: просмотр и удаление клиентов; полная версия — PRO).",
"license": "MIT", "license": "MIT",

View File

@@ -366,39 +366,42 @@ async function refreshMtprotoPanel() {
mtprotoBanner.textContent = ""; mtprotoBanner.textContent = "";
} }
try { try {
const s = await api("/api/mtproto/status"); const snap = await api("/api/mtproto/status");
if (mtprotoLogsTailEl) mtprotoLogsTailEl.textContent = typeof s.logsTail === "string" ? s.logsTail : ""; if (mtprotoLogsTailEl) {
mtprotoLogsTailEl.textContent =
typeof snap.logsTail === "string" ? snap.logsTail : "";
}
const parts = []; const parts = [];
if (s.exists) parts.push("контейнер есть"); if (snap.exists) parts.push("контейнер есть");
if (s.running) parts.push("запущен"); if (snap.running) parts.push("запущен");
mtprotoStatusLine.textContent = mtprotoStatusLine.textContent =
parts.length > 0 parts.length > 0
? parts.join(" · ") + ? parts.join(" · ") +
(s.hostPort ? ` · порт хоста :${String(s.hostPort)}` : "") + (snap.hostPort ? ` · порт хоста :${String(snap.hostPort)}` : "") +
(s.secretMasked ? ` · секрет ${s.secretMasked}` : "") (snap.secretMasked ? ` · секрет ${snap.secretMasked}` : "")
: "не установлен"; : "не установлен";
if (typeof s.hint === "string" && s.hint.trim()) { if (typeof snap.hint === "string" && snap.hint.trim()) {
const hintEl = document.createElement("p"); const hintEl = document.createElement("p");
hintEl.className = "muted warp-muted"; hintEl.className = "muted warp-muted";
hintEl.textContent = s.hint.trim(); hintEl.textContent = snap.hint.trim();
mtprotoActionsEl.appendChild(hintEl); mtprotoActionsEl.appendChild(hintEl);
} else if (s.exists && !s.running && typeof s.image === "string" && s.image.trim()) { } else if (snap.exists && !snap.running && typeof snap.image === "string" && snap.image.trim()) {
const imgHint = document.createElement("p"); const imgHint = document.createElement("p");
imgHint.className = "muted warp-muted"; imgHint.className = "muted warp-muted";
imgHint.textContent = `После установки образ будет доступен здесь (${s.image.trim()} при актуальной конфигурации).`; imgHint.textContent = `После установки образ будет доступен здесь (${snap.image.trim()} при актуальной конфигурации).`;
mtprotoActionsEl.appendChild(imgHint); mtprotoActionsEl.appendChild(imgHint);
} }
if (s.tgLink) { if (snap.tgLink) {
const link = document.createElement("div"); const link = document.createElement("div");
link.className = "mtproto-deep-link muted warp-muted"; link.className = "mtproto-deep-link muted warp-muted";
const lab = document.createElement("strong"); const lab = document.createElement("strong");
lab.textContent = "Ссылка в Telegram: "; lab.textContent = "Ссылка в Telegram: ";
const a = document.createElement("a"); const a = document.createElement("a");
a.href = s.tgLink; a.href = snap.tgLink;
a.textContent = s.tgLink; a.textContent = snap.tgLink;
a.target = "_blank"; a.target = "_blank";
a.rel = "noopener noreferrer"; a.rel = "noopener noreferrer";
link.append(lab, a); link.append(lab, a);

View File

@@ -261,6 +261,6 @@
</div> </div>
</dialog> </dialog>
<script src="/app.js" type="module"></script> <script src="/app.js?v=1.2.18" type="module"></script>
</body> </body>
</html> </html>

View File

@@ -7,6 +7,16 @@ import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
/** Из package.json — для мониторинга и проверки, что VPS подняли свежий образ. */
let PANEL_VERSION = "0.0.0";
try {
const raw = fs.readFileSync(path.join(__dirname, "package.json"), "utf8");
const v = JSON.parse(raw)?.version;
if (typeof v === "string" && v.trim()) PANEL_VERSION = v.trim();
} catch {
/* оставить PANEL_VERSION по умолчанию */
}
const PORT = Number(process.env.PORT || 3980); const PORT = Number(process.env.PORT || 3980);
const PROFILE_COOKIE = "amnezia_prof"; const PROFILE_COOKIE = "amnezia_prof";
const SCHEDULER_MS = Number(process.env.SCHEDULE_DISCONNECT_MS || 60_000); const SCHEDULER_MS = Number(process.env.SCHEDULE_DISCONNECT_MS || 60_000);
@@ -2102,7 +2112,7 @@ app.get("/api/community/install-log", requireAuth, (req, res) => {
}); });
app.get("/health", (_req, res) => { app.get("/health", (_req, res) => {
res.json({ ok: true }); res.json({ ok: true, version: PANEL_VERSION });
}); });
app.get("/api/session", (req, res) => { app.get("/api/session", (req, res) => {
@@ -2983,7 +2993,7 @@ app.use((_req, res) => {
app.listen(PORT, "0.0.0.0", () => { app.listen(PORT, "0.0.0.0", () => {
const summary = PROFILES.map((p) => `${p.label}${p.container}`).join("; "); const summary = PROFILES.map((p) => `${p.label}${p.container}`).join("; ");
console.log(`amnezia-admin on :${PORT} · ${summary} · data:${DATA_DIR}`); console.log(`amnezia-admin v${PANEL_VERSION} on :${PORT} · ${summary} · data:${DATA_DIR}`);
}); });
setInterval(() => { setInterval(() => {