Skip to content

Commit f874363

Browse files
committed
渠道匹配支持裸主机:不带端口的站点地址覆盖该主机所有端口 (v1.7.1)
之前匹配只做完全相等(± /api 后缀),带端口的渠道 (如 180.178.51.122:13810 / :13800)无法匹配裸 IP 的固定成本节点。 现在按打分取最优:精确匹配 > ±/api > 裸主机(无端口无路径时匹配 该主机任意端口/路径的渠道)——单独给某端口建站点时精确匹配仍然优先
1 parent 19dcbd4 commit f874363

3 files changed

Lines changed: 19 additions & 4 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "relay-monitor",
3-
"version": "1.7.0",
3+
"version": "1.7.1",
44
"private": true,
55
"description": "监控 sub2api / new-api 中转站余额的网页面板",
66
"type": "module",

public/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ <h2 id="modalTitle">添加中转站</h2>
161161
<input class="input" type="date" id="f-fixedStart" style="width:150px" />
162162
</div>
163163
<div class="hint">日均成本 = 金额 ÷ 天数,从购买日起摊销,到期后不再计成本(续费改日期即可)。
164-
不访问任何接口;站点地址可留空,填上游地址可与「我的站点」渠道自动匹配。</div>
164+
不访问任何接口;站点地址可留空。填上游地址可与「我的站点」渠道自动匹配——
165+
只填主机(如 1.2.3.4,不带端口)可匹配该主机所有端口的渠道。</div>
165166
</div>
166167
<div class="form-field" id="f-own-wrap">
167168
<label class="chk-line"><input type="checkbox" id="f-own" /> 这是我自己的中转站</label>

server.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,14 +609,28 @@ async function computeProfit(own, incomeUsd, adminUsageUsd, { startMs, now, tz,
609609
}
610610
const channels = ownChannelsCache.list;
611611
const norm = (u) => String(u || "").toLowerCase().replace(/^https?:\/\//, "").replace(/\/+$/, "");
612-
const same = (a, b) => a && b && (a === b || a === b + "/api" || b === a + "/api");
612+
const hostOf = (u) => u.split("/")[0].split(":")[0];
613+
const isBareHost = (u) => !!u && !u.includes("/") && !u.includes(":");
614+
// 匹配打分:精确 > ±/api 后缀 > 裸主机(站点地址不带端口/路径时,
615+
// 覆盖该主机所有端口——同一台机器跑多个服务的场景)
616+
const matchScore = (stUrl, chUrl) => {
617+
if (!stUrl || !chUrl) return 0;
618+
if (stUrl === chUrl) return 3;
619+
if (stUrl === chUrl + "/api" || chUrl === stUrl + "/api") return 2;
620+
if (isBareHost(stUrl) && hostOf(chUrl) === stUrl) return 1;
621+
return 0;
622+
};
613623
const upstreams = store.list().filter((s) => s.id !== own.id);
614624

615625
const matched = new Map(); // stationId -> {station, channels[]}
616626
const unmatched = new Map(); // label -> {label, names[], enabled, total}
617627
for (const ch of channels) {
618628
const cu = norm(ch.baseUrl);
619-
const st = cu ? upstreams.find((s) => same(norm(s.baseUrl), cu)) : null;
629+
let st = null, best = 0;
630+
for (const s of upstreams) {
631+
const score = matchScore(norm(s.baseUrl), cu);
632+
if (score > best) { best = score; st = s; }
633+
}
620634
if (st) {
621635
const e = matched.get(st.id) || { station: st, channels: [] };
622636
e.channels.push(ch.name);

0 commit comments

Comments
 (0)