diff --git a/public/app.js b/public/app.js
index 7b3915b..a8df635 100644
--- a/public/app.js
+++ b/public/app.js
@@ -1454,12 +1454,18 @@ async function loadInstances() {
? ``
: ``;
const badge = m.badge ? `${m.badge}` : "";
+ const srcTag = i.managed
+ ? ""
+ : `приложение Amnezia`;
+ const delBtn = i.managed
+ ? ``
+ : "";
return `
-
${escapeHtmlSafe(m.title)} ${badge}
+
${escapeHtmlSafe(m.title)} ${badge} ${srcTag}
${escapeHtmlSafe(i.variantMeta?.desc || "")}
${status}
@@ -1468,7 +1474,7 @@ async function loadInstances() {
-
+ ${delBtn}
`;
}).join("");
diff --git a/public/styles.css b/public/styles.css
index e71e883..4eaefa5 100644
--- a/public/styles.css
+++ b/public/styles.css
@@ -1201,3 +1201,5 @@ tr:last-child td {
.instance-form-row label { font-size: 0.75rem; color: var(--muted); }
.instance-hint { font-size: 0.75rem; margin-top: 8px; }
.instance-empty { padding: 12px; }
+
+.inst-src { font-size: 0.6rem; color: var(--muted); border: 1px solid var(--line); border-radius: 999px; padding: 2px 7px; vertical-align: middle; }
diff --git a/server.js b/server.js
index 140ec5a..66fa2ce 100644
--- a/server.js
+++ b/server.js
@@ -2653,24 +2653,48 @@ function runInstanceScript(args) {
});
}
+function detectVariantFromHead(head, iface) {
+ if (iface === "wg0" || !/^S1\s*=/m.test(head)) return "legacy";
+ if (/^S3\s*=/m.test(head) || /^S4\s*=/m.test(head)) return "awg2";
+ return "awg";
+}
+
app.get("/api/instances", requireAuth, async (_req, res) => {
- const managed = loadManagedProfiles();
+ const managedIds = new Set(loadManagedProfiles().map((m) => m.id));
+ const profiles = getProfiles();
const running = await listRunningContainerNames();
const items = [];
- for (const m of managed) {
+ for (const prof of profiles) {
+ const isManaged = managedIds.has(prof.id) || prof.managed === true;
+ let container = prof.container;
+ let runningNow = false;
let peers = null;
- if (running.includes(m.container)) {
- try {
- const out = (await execDocker(["exec", m.container, m.wgBinary, "show", m.iface, "peers"])).stdout || "";
- peers = out.split("\n").map((x) => x.trim()).filter(Boolean).length;
- } catch { peers = null; }
+ let port = prof.port || null;
+ let variant = prof.variant || "awg2";
+ try {
+ const rt = createRuntime(prof);
+ container = await rt.resolveContainer();
+ runningNow = running.includes(container);
+ if (runningNow) {
+ const { conf } = await rt.loadState();
+ peers = conf.peers.length;
+ const m = /^ListenPort\s*=\s*(\d+)/m.exec(conf.head);
+ if (m) port = Number(m[1]);
+ if (!prof.variant) variant = detectVariantFromHead(conf.head, prof.iface || "awg0");
+ }
+ } catch {
+ runningNow = container ? running.includes(container) : false;
}
items.push({
- id: m.id, label: m.label, variant: m.variant, port: m.port,
- container: m.container,
- running: running.includes(m.container),
+ id: prof.id,
+ label: prof.label,
+ variant,
+ port,
+ container,
+ running: runningNow,
peers,
- variantMeta: INSTANCE_VARIANTS[m.variant] || null,
+ managed: isManaged,
+ variantMeta: INSTANCE_VARIANTS[variant] || null,
});
}
res.json({ instances: items, variants: INSTANCE_VARIANTS });
@@ -2720,17 +2744,26 @@ app.post("/api/instances/delete", requireAuth, requireProTier, async (req, res)
res.json({ ok: true });
});
+async function resolveProfileContainer(id) {
+ const prof = getProfiles().find((p) => p.id === id);
+ if (!prof) return null;
+ try { return await createRuntime(prof).resolveContainer(); }
+ catch { return prof.container || null; }
+}
+
app.post("/api/instances/stop", requireAuth, requireProTier, async (req, res) => {
const id = String(req.body?.id || "").trim();
- if (!loadManagedProfiles().some((p) => p.id === id)) return res.status(404).json({ error: "Инстанс не найден." });
- try { await execDocker(["stop", id]); res.json({ ok: true }); }
+ const container = await resolveProfileContainer(id);
+ if (!container) return res.status(404).json({ error: "Инстанс не найден." });
+ try { await execDocker(["stop", container]); res.json({ ok: true }); }
catch (e) { res.status(500).json({ error: String(e.message || e) }); }
});
app.post("/api/instances/start", requireAuth, requireProTier, async (req, res) => {
const id = String(req.body?.id || "").trim();
- if (!loadManagedProfiles().some((p) => p.id === id)) return res.status(404).json({ error: "Инстанс не найден." });
- try { await execDocker(["start", id]); res.json({ ok: true }); }
+ const container = await resolveProfileContainer(id);
+ if (!container) return res.status(404).json({ error: "Инстанс не найден." });
+ try { await execDocker(["start", container]); res.json({ ok: true }); }
catch (e) { res.status(500).json({ error: String(e.message || e) }); }
});