feat: добавлена возможность поиска и отображения rule-sets из каталога SagerNet
All checks were successful
Build and Deploy Gateway / build-and-deploy (push) Successful in 19s

Refs: None
This commit is contained in:
2026-05-08 20:38:27 +03:00
parent 4f1a2f8bf6
commit bb7250e4ac
3 changed files with 187 additions and 0 deletions

View File

@@ -572,6 +572,54 @@ async function handleApi(req, res) {
}
}
if (req.method === "GET" && req.url === "/api/rule-sets/sagernet-catalog") {
const cacheFile = path.join(
settings.dataDir,
"sagernet-catalog-cache.json",
);
const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 часа
if (fs.existsSync(cacheFile)) {
try {
const cached = JSON.parse(fs.readFileSync(cacheFile, "utf8"));
if (Date.now() - new Date(cached.cachedAt).getTime() < CACHE_TTL_MS) {
return sendJson(res, 200, { success: true, ...cached });
}
} catch {}
}
try {
const headers = { "User-Agent": "vpn-proxy-app" };
const [gsRes, giRes] = await Promise.all([
fetch(
"https://api.github.com/repos/SagerNet/sing-geosite/git/trees/rule-set?recursive=1",
{ headers },
),
fetch(
"https://api.github.com/repos/SagerNet/sing-geoip/git/trees/rule-set?recursive=1",
{ headers },
),
]);
const gsData = await gsRes.json();
const giData = await giRes.json();
const geosite = (gsData.tree || [])
.filter((f) => f.path.endsWith(".srs"))
.map((f) => f.path.replace(".srs", ""))
.sort();
const geoip = (giData.tree || [])
.filter((f) => f.path.endsWith(".srs"))
.map((f) => f.path.replace(".srs", ""))
.sort();
const result = { geosite, geoip, cachedAt: new Date().toISOString() };
writeJson(cacheFile, result);
return sendJson(res, 200, { success: true, ...result });
} catch (err) {
return sendJson(res, 500, { success: false, error: err.message });
}
}
if (req.method === "POST" && req.url === "/api/route/check") {
const body = await readBody(req);
const host = String(body.host || "").trim();