v1.54
https://github.com/StressOzz/Zapret-Manager/issues/1062#issuecomment-5842272411
This commit is contained in:
1 parent
714d18f5eb
commit
95e4fc5d3d
1 file changed
+42
-18
+42
-18
@@ -3442,9 +3442,11 @@ health() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
printf '{"zapret":%s,"zapret2":%s,"bytetube":%s,"tg":%s,"mixomo":%s,"doh":%s,"hosts":%s,"steer":%s,"steer_off":%s,"awg":%s}\n' \
|
local sx=""
|
||||||
|
if _st_installed; then sx="$(_st_exit)"; [ "$sx" = warp ] && _st_warp_own && sx=own; fi
|
||||||
|
printf '{"zapret":%s,"zapret2":%s,"bytetube":%s,"tg":%s,"mixomo":%s,"doh":%s,"hosts":%s,"steer":%s,"steer_off":%s,"steer_exit":"%s","awg":%s}\n' \
|
||||||
"$zr" "$zr2" "$bt" "$tg" "$mx" "$doh" "$hs" "$sr" \
|
"$zr" "$zr2" "$bt" "$tg" "$mx" "$doh" "$hs" "$sr" \
|
||||||
"$([ -f /etc/zm-steer/stopped ] && echo true || echo false)" "$(_awg_health)"
|
"$([ -f /etc/zm-steer/stopped ] && echo true || echo false)" "$sx" "$(_awg_health)"
|
||||||
}
|
}
|
||||||
|
|
||||||
VERSIONS_CACHE="$ZM_STATE_DIR/versions.json"
|
VERSIONS_CACHE="$ZM_STATE_DIR/versions.json"
|
||||||
@@ -7331,11 +7333,11 @@ awg_status() {
|
|||||||
ep="$(sed -n 's/^[[:space:]]*Endpoint[[:space:]]*=[[:space:]]*//p' "$MIXOMO_WARP_CONF" | head -n1)"
|
ep="$(sed -n 's/^[[:space:]]*Endpoint[[:space:]]*=[[:space:]]*//p' "$MIXOMO_WARP_CONF" | head -n1)"
|
||||||
fi
|
fi
|
||||||
[ -x /etc/init.d/mihomo ] && mih=true
|
[ -x /etc/init.d/mihomo ] && mih=true
|
||||||
printf '{"running":%s,"phase":"%s","installed":%s,"kmod":"%s","tools":"%s","luci":"%s","luci_pkg":"%s","module":%s,"proto":%s,"steer":%s,"warp_conf":%s,"warp_path":"%s","warp_endpoint":"%s","mihomo":%s,"endpoints":"%s","ifaces":[%s]}\n' \
|
printf '{"running":%s,"phase":"%s","installed":%s,"kmod":"%s","tools":"%s","luci":"%s","luci_pkg":"%s","module":%s,"proto":%s,"steer":%s,"warp_conf":%s,"warp_path":"%s","warp_endpoint":"%s","mihomo":%s,"endpoints":"%s","steer_own":%s,"ifaces":[%s]}\n' \
|
||||||
"$running" "$(cat "$AWG_RUN/phase" 2>/dev/null)" "$(_awg_installed && echo true || echo false)" \
|
"$running" "$(cat "$AWG_RUN/phase" 2>/dev/null)" "$(_awg_installed && echo true || echo false)" \
|
||||||
"$(esc "$(_awg_pkg_ver kmod-amneziawg)")" "$(esc "$(_awg_pkg_ver amneziawg-tools)")" "$(esc "$lv")" "$lp" \
|
"$(esc "$(_awg_pkg_ver kmod-amneziawg)")" "$(esc "$(_awg_pkg_ver amneziawg-tools)")" "$(esc "$lv")" "$lp" \
|
||||||
"$(_st_awg_loaded && echo true || echo false)" "$(_awg_proto_ok && echo true || echo false)" \
|
"$(_st_awg_loaded && echo true || echo false)" "$(_awg_proto_ok && echo true || echo false)" \
|
||||||
"$(_st_warp_on && echo true || echo false)" "$conf" "$MIXOMO_WARP_CONF" "$(esc "$ep")" "$mih" "$AWG_ENDPOINTS" "$list"
|
"$(_st_warp_on && echo true || echo false)" "$conf" "$MIXOMO_WARP_CONF" "$(esc "$ep")" "$mih" "$AWG_ENDPOINTS" "$(_st_warp_own && echo true || echo false)" "$list"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -8697,6 +8699,8 @@ function pollJob(job, logEl, onDone, onTick) {
|
|||||||
finished = true;
|
finished = true;
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
delete _activePolls[job];
|
delete _activePolls[job];
|
||||||
|
// Операция закончилась — пусть остальное (точки в меню Web UI и т. п.) обновится сразу
|
||||||
|
try { window.dispatchEvent(new CustomEvent('zm:changed', { detail: { job: job } })); } catch (e) {}
|
||||||
onDone(st.rc === '0');
|
onDone(st.rc === '0');
|
||||||
}
|
}
|
||||||
}).catch(function() {
|
}).catch(function() {
|
||||||
@@ -8936,9 +8940,10 @@ return view.extend({
|
|||||||
var offBadge = function(text) { return E('span', { 'class': 'zm-badge zm-off' }, [ E('span', { 'class': 'zm-dot' }), text ]); };
|
var offBadge = function(text) { return E('span', { 'class': 'zm-badge zm-off' }, [ E('span', { 'class': 'zm-dot' }), text ]); };
|
||||||
// Steer: 2 — должен работать, но не работает; 5 — выключен или сервисы не выбраны.
|
// Steer: 2 — должен работать, но не работает; 5 — выключен или сервисы не выбраны.
|
||||||
var stSt = st(h, 'steer', 0);
|
var stSt = st(h, 'steer', 0);
|
||||||
items.push(row('Steer', stSt === 1 ? zm.badge(true, 'работает', '')
|
var stVia = { warp: 'через WARP', own: 'через свой WARP', vpn: 'через VPN' }[h.steer_exit] || '';
|
||||||
: stSt === 2 ? zm.badge(false, '', 'не работает')
|
items.push(row('Steer', stSt === 1 ? zm.badge(true, 'работает' + (stVia ? ' · ' + stVia : ''), '')
|
||||||
: stSt === 5 ? offBadge(h.steer_off ? 'выключен' : 'сервисы не выбраны')
|
: stSt === 2 ? zm.badge(false, '', 'не работает' + (stVia ? ' · ' + stVia : ''))
|
||||||
|
: stSt === 5 ? offBadge(h.steer_off ? 'выключен' : h.steer_exit === 'none' ? 'подключите WARP или VPN' : 'сервисы не выбраны')
|
||||||
: zm.badge(false, '', 'не установлен')));
|
: zm.badge(false, '', 'не установлен')));
|
||||||
items.push(row('ByeTube', zm.stateBadge(st(h, 'bytetube', 0))));
|
items.push(row('ByeTube', zm.stateBadge(st(h, 'bytetube', 0))));
|
||||||
items.push(row('TG WS Proxy', zm.stateBadge(st(h, 'tg', 0))));
|
items.push(row('TG WS Proxy', zm.stateBadge(st(h, 'tg', 0))));
|
||||||
@@ -9493,7 +9498,7 @@ return view.extend({
|
|||||||
: E('button', { 'class': 'cbi-button cbi-button-positive', 'click': function() { quick('up', f.name, f.name + ' включён'); } }, 'Включить'));
|
: E('button', { 'class': 'cbi-button cbi-button-positive', 'click': function() { quick('up', f.name, f.name + ' включён'); } }, 'Включить'));
|
||||||
acts.push(E('button', { 'class': 'cbi-button', 'click': function() { open[f.name] = open[f.name] === 'ep' ? null : 'ep'; renderIfaces(); } }, 'Точка входа'));
|
acts.push(E('button', { 'class': 'cbi-button', 'click': function() { open[f.name] = open[f.name] === 'ep' ? null : 'ep'; renderIfaces(); } }, 'Точка входа'));
|
||||||
}
|
}
|
||||||
acts.push(E('button', { 'class': 'cbi-button cbi-button-action', 'click': function() {
|
if (!(steer && data.steer_own)) acts.push(E('button', { 'class': 'cbi-button cbi-button-action', 'click': function() {
|
||||||
if (!confirm('Сгенерировать новый WARP для ' + f.name + '?\n\nНовые ключи Cloudflare WARP получит только этот интерфейс' + (f.warp ? ', точка входа и маскировка сохранятся.' : ' — вместо текущего сервера.'))) return;
|
if (!confirm('Сгенерировать новый WARP для ' + f.name + '?\n\nНовые ключи Cloudflare WARP получит только этот интерфейс' + (f.warp ? ', точка входа и маскировка сохранятся.' : ' — вместо текущего сервера.'))) return;
|
||||||
job('regen', f.name, 'Генерируем новый WARP для ' + f.name);
|
job('regen', f.name, 'Генерируем новый WARP для ' + f.name);
|
||||||
} }, 'Новый WARP'));
|
} }, 'Новый WARP'));
|
||||||
@@ -9509,7 +9514,9 @@ return view.extend({
|
|||||||
quick('delete', f.name, f.name + ' удалён');
|
quick('delete', f.name, f.name + ' удалён');
|
||||||
} }, 'Удалить'));
|
} }, 'Удалить'));
|
||||||
box.appendChild(E('div', { 'class': 'zm-actions' }, acts));
|
box.appendChild(E('div', { 'class': 'zm-actions' }, acts));
|
||||||
if (steer) box.appendChild(E('p', { 'class': 'zm-hint' }, 'Туннель Steer: конфиг и ключи можно менять здесь, остальным управляет страница Steer.'));
|
if (steer) box.appendChild(E('p', { 'class': 'zm-hint' }, data.steer_own
|
||||||
|
? 'Свой WARP для Steer: новый конфиг можно вставить здесь («Изменить конфиг») или на странице Steer.'
|
||||||
|
: 'Туннель Steer: конфиг и ключи можно менять здесь, остальным управляет страница Steer.'));
|
||||||
if (open[f.name] === 'ep') box.appendChild(epEditor(f));
|
if (open[f.name] === 'ep') box.appendChild(epEditor(f));
|
||||||
if (open[f.name] === 'conf') {
|
if (open[f.name] === 'conf') {
|
||||||
var ta = E('textarea', { 'class': 'zm-config-editor', 'spellcheck': 'false', 'style': 'min-height:220px' });
|
var ta = E('textarea', { 'class': 'zm-config-editor', 'spellcheck': 'false', 'style': 'min-height:220px' });
|
||||||
@@ -9910,6 +9917,9 @@ return view.extend({
|
|||||||
|
|
||||||
// ── главная карточка ──
|
// ── главная карточка ──
|
||||||
|
|
||||||
|
// Как называть туннель WARP: в режиме «Свой конфиг» — «Свой WARP».
|
||||||
|
function warpName() { return data.warp_mode === 'own' ? 'Свой WARP' : 'WARP'; }
|
||||||
|
|
||||||
function selectedCount() {
|
function selectedCount() {
|
||||||
var n = (data.services || []).filter(function(s) { return s.on; }).length;
|
var n = (data.services || []).filter(function(s) { return s.on; }).length;
|
||||||
if (!n && (parseInt(data.channels, 10) || 0) > 0) n = 1;
|
if (!n && (parseInt(data.channels, 10) || 0) > 0) n = 1;
|
||||||
@@ -9973,13 +9983,13 @@ return view.extend({
|
|||||||
mainCard.appendChild(E('div', { 'class': 'zm-row' }, [
|
mainCard.appendChild(E('div', { 'class': 'zm-row' }, [
|
||||||
E('span', { 'class': 'zm-label' }, 'Сервисы идут через'),
|
E('span', { 'class': 'zm-label' }, 'Сервисы идут через'),
|
||||||
E('div', { 'class': 'zm-seg' }, [
|
E('div', { 'class': 'zm-seg' }, [
|
||||||
E('div', { 'class': 'zm-seg-item' + (!isVpn ? ' zm-active' : ''), 'click': function() { if (isVpn && !busy) act('sub_exit', 'warp', 'Переключаем на WARP'); } }, 'WARP'),
|
E('div', { 'class': 'zm-seg-item' + (!isVpn ? ' zm-active' : ''), 'click': function() { if (isVpn && !busy) act('sub_exit', 'warp', 'Переключаем на ' + warpName()); } }, warpName()),
|
||||||
E('div', { 'class': 'zm-seg-item' + (isVpn ? ' zm-active' : ''), 'click': function() { if (!isVpn && !busy) act('sub_exit', 'vpn', 'Переключаем на VPN'); } }, data.sub_label || 'VPN')
|
E('div', { 'class': 'zm-seg-item' + (isVpn ? ' zm-active' : ''), 'click': function() { if (!isVpn && !busy) act('sub_exit', 'vpn', 'Переключаем на VPN'); } }, data.sub_label || 'VPN')
|
||||||
]),
|
]),
|
||||||
isVpn ? vpnBadge() : badge(ts[1], ts[0])
|
isVpn ? vpnBadge() : badge(ts[1], ts[0])
|
||||||
]));
|
]));
|
||||||
} else if (data.exit === 'vpn') mainCard.appendChild(row('Сервисы идут через', E('span', {}, [ 'VPN' + (data.sub_label ? ' · ' + data.sub_label : '') + ' ', vpnBadge() ])));
|
} else if (data.exit === 'vpn') mainCard.appendChild(row('Сервисы идут через', E('span', {}, [ 'VPN' + (data.sub_label ? ' · ' + data.sub_label : '') + ' ', vpnBadge() ])));
|
||||||
else if (data.exit === 'warp') mainCard.appendChild(row('Сервисы идут через', badge(ts[1], 'WARP · ' + ts[0])));
|
else if (data.exit === 'warp') mainCard.appendChild(row('Сервисы идут через', badge(ts[1], warpName() + ' · ' + ts[0])));
|
||||||
else mainCard.appendChild(row('Сервисы идут через', badge('zm-warn', 'туннель не подключён — выберите вкладку WARP или VPN')));
|
else mainCard.appendChild(row('Сервисы идут через', badge('zm-warn', 'туннель не подключён — выберите вкладку WARP или VPN')));
|
||||||
mainCard.appendChild(row('Через туннель', E('span', {}, n ? n + ' ' + plural(n, 'сервис', 'сервиса', 'сервисов') : 'ничего не выбрано')));
|
mainCard.appendChild(row('Через туннель', E('span', {}, n ? n + ' ' + plural(n, 'сервис', 'сервиса', 'сервисов') : 'ничего не выбрано')));
|
||||||
var newer = data.latest && data.version && verLt(data.version, data.latest);
|
var newer = data.latest && data.version && verLt(data.version, data.latest);
|
||||||
@@ -10121,9 +10131,11 @@ return view.extend({
|
|||||||
var n = customData ? (parseInt(customData.count, 10) || 0) : 0;
|
var n = customData ? (parseInt(customData.count, 10) || 0) : 0;
|
||||||
customCard.appendChild(row('Состояние', !n ? badge('zm-off', 'список пуст')
|
customCard.appendChild(row('Состояние', !n ? badge('zm-off', 'список пуст')
|
||||||
: !svc.on ? badge('zm-warn', 'не выбран')
|
: !svc.on ? badge('zm-warn', 'не выбран')
|
||||||
: !data.installed ? badge('zm-warn', 'пойдёт через WARP после установки')
|
: !data.installed ? badge('zm-warn', 'пойдёт через Steer после установки')
|
||||||
: data.stopped ? badge('zm-off', 'Steer выключен')
|
: data.stopped ? badge('zm-off', 'Steer выключен')
|
||||||
: badge('zm-ok', 'идёт через WARP')));
|
: data.exit === 'vpn' ? badge('zm-ok', 'идёт через VPN')
|
||||||
|
: data.exit === 'warp' ? badge('zm-ok', 'идёт через ' + warpName())
|
||||||
|
: badge('zm-warn', 'подключите WARP или VPN')));
|
||||||
customCard.appendChild(row('Доменов', E('span', {}, String(n))));
|
customCard.appendChild(row('Доменов', E('span', {}, String(n))));
|
||||||
customEditor = E('textarea', {
|
customEditor = E('textarea', {
|
||||||
'class': 'zm-config-editor', 'spellcheck': 'false', 'style': 'min-height:200px', 'placeholder': 'example.com\nsite.org',
|
'class': 'zm-config-editor', 'spellcheck': 'false', 'style': 'min-height:200px', 'placeholder': 'example.com\nsite.org',
|
||||||
@@ -10174,9 +10186,11 @@ return view.extend({
|
|||||||
else if (diagRes.vpn === 'off') items.push([ 'fail', 'Трафик через подписку не идёт', 'проверьте задержку узлов на вкладке «Подписка» или выберите другой узел' ]);
|
else if (diagRes.vpn === 'off') items.push([ 'fail', 'Трафик через подписку не идёт', 'проверьте задержку узлов на вкладке «Подписка» или выберите другой узел' ]);
|
||||||
else if (tn.length) tn.forEach(function(t) {
|
else if (tn.length) tn.forEach(function(t) {
|
||||||
var who = tn.length > 1 ? 'Туннель ' + t.n + ': ' : '';
|
var who = tn.length > 1 ? 'Туннель ' + t.n + ': ' : '';
|
||||||
if (t.warp === 'on') items.push([ 'ok', who + 'трафик идёт через WARP' + (t.colo ? ' (сервер ' + t.colo + ')' : ''), '' ]);
|
var ownW = data.warp_mode === 'own';
|
||||||
else if (t.warp === 'notls') items.push([ 'warn', who + 'соединение есть, но HTTPS через туннель не проходит', 'нажмите «Сменить точки входа»' ]);
|
if (t.warp === 'on') items.push([ 'ok', who + 'трафик идёт через ' + warpName() + (t.colo ? ' (сервер ' + t.colo + ')' : ''), '' ]);
|
||||||
else items.push([ tn.length > 1 && diagRes.warp === 'on' ? 'warn' : 'fail', who + 'трафик через WARP не идёт', 'нажмите «Перезапустить туннели» или «Сменить точки входа»' ]);
|
else if (t.warp === 'notls') items.push([ 'warn', who + 'соединение есть, но HTTPS через туннель не проходит', ownW ? 'замените конфиг на вкладке WARP' : 'нажмите «Сменить точки входа»' ]);
|
||||||
|
else items.push([ tn.length > 1 && diagRes.warp === 'on' ? 'warn' : 'fail', who + 'трафик через ' + warpName() + ' не идёт',
|
||||||
|
ownW ? 'нажмите «Перезапустить туннель» или замените конфиг на вкладке WARP' : 'нажмите «Перезапустить туннели» или «Сменить точки входа»' ]);
|
||||||
});
|
});
|
||||||
else if (diagRes.warp === 'on') items.push([ 'ok', 'Трафик идёт через WARP' + (diagRes.colo ? ' (сервер ' + diagRes.colo + ')' : ''), '' ]);
|
else if (diagRes.warp === 'on') items.push([ 'ok', 'Трафик идёт через WARP' + (diagRes.colo ? ' (сервер ' + diagRes.colo + ')' : ''), '' ]);
|
||||||
else if (diagRes.warp === 'off') items.push([ 'fail', 'Трафик через WARP не идёт', 'нажмите «Перезапустить туннели» или «Сменить точки входа»' ]);
|
else if (diagRes.warp === 'off') items.push([ 'fail', 'Трафик через WARP не идёт', 'нажмите «Перезапустить туннели» или «Сменить точки входа»' ]);
|
||||||
@@ -10508,7 +10522,7 @@ return view.extend({
|
|||||||
E('div', { 'class': 'zm-sub-facts' }, facts)
|
E('div', { 'class': 'zm-sub-facts' }, facts)
|
||||||
]));
|
]));
|
||||||
|
|
||||||
var vpn = subData.exit === 'vpn';
|
var vpn = (data.exit || subData.exit) === 'vpn';
|
||||||
if (vpn) {
|
if (vpn) {
|
||||||
var v = subData.vpn || {}, pr = v.probe || {}, st;
|
var v = subData.vpn || {}, pr = v.probe || {}, st;
|
||||||
if (v.up) st = badge('zm-ok', 'подключено');
|
if (v.up) st = badge('zm-ok', 'подключено');
|
||||||
@@ -10551,7 +10565,7 @@ return view.extend({
|
|||||||
var sk = subData.list && subData.list.skipped_reasons || [];
|
var sk = subData.list && subData.list.skipped_reasons || [];
|
||||||
if (subData.list && subData.list.skipped > 0) subCard.appendChild(E('p', { 'class': 'zm-hint' },
|
if (subData.list && subData.list.skipped > 0) subCard.appendChild(E('p', { 'class': 'zm-hint' },
|
||||||
'Пропущено узлов: ' + subData.list.skipped + (sk.length ? ' — ' + sk.map(function(r) { return r.reason; }).slice(0, 2).join('; ') : '') + '. Steer умеет VLESS Reality (tcp, grpc, xhttp).'));
|
'Пропущено узлов: ' + subData.list.skipped + (sk.length ? ' — ' + sk.map(function(r) { return r.reason; }).slice(0, 2).join('; ') : '') + '. Steer умеет VLESS Reality (tcp, grpc, xhttp).'));
|
||||||
if (!vpn) subCard.appendChild(E('p', { 'class': 'zm-hint' }, 'Сейчас сервисы идут через WARP — переключить можно в карточке Steer вверху. Выбор узла сохранится.'));
|
if (!vpn && data.exit === 'warp') subCard.appendChild(E('p', { 'class': 'zm-hint' }, 'Сейчас сервисы идут через ' + warpName() + ' — переключить можно в карточке Steer вверху. Выбор узла сохранится.'));
|
||||||
if (subData.kind === 'url') {
|
if (subData.kind === 'url') {
|
||||||
var AUTO = [ { id: 'off', name: 'Не обновлять' }, { id: '3', name: 'Каждые 3 часа' }, { id: '6', name: 'Каждые 6 часов' }, { id: '12', name: 'Каждые 12 часов' }, { id: '24', name: 'Раз в сутки' } ];
|
var AUTO = [ { id: 'off', name: 'Не обновлять' }, { id: '3', name: 'Каждые 3 часа' }, { id: '6', name: 'Каждые 6 часов' }, { id: '12', name: 'Каждые 12 часов' }, { id: '24', name: 'Раз в сутки' } ];
|
||||||
var curAuto = subData.auto || 'off';
|
var curAuto = subData.auto || 'off';
|
||||||
@@ -15724,6 +15738,9 @@ function ubus(object, method, params, useSid) {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
if (!msg || !Array.isArray(msg.result)) throw new Error('Некорректный ответ ubus');
|
if (!msg || !Array.isArray(msg.result)) throw new Error('Некорректный ответ ubus');
|
||||||
|
// Любое действие в панели (не опрос состояния) — через секунду обновляем точки в меню,
|
||||||
|
// чтобы меню, дашборд и страницы показывали одно и то же, а не ждали 15 секунд.
|
||||||
|
if (object === 'zapret-manager' && !/(status|info|health|list|tail|log|latest|version|export|get)/.test(method)) scheduleShellRefresh();
|
||||||
return msg.result;
|
return msg.result;
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
clearTimeout(tm);
|
clearTimeout(tm);
|
||||||
@@ -16471,6 +16488,13 @@ function loadShellInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var shellTimer = null;
|
var shellTimer = null;
|
||||||
|
var shellRefreshTimer = null;
|
||||||
|
function scheduleShellRefresh() {
|
||||||
|
clearTimeout(shellRefreshTimer);
|
||||||
|
shellRefreshTimer = setTimeout(function () { refreshShellStatus(); }, 1200);
|
||||||
|
}
|
||||||
|
window.addEventListener('zm:changed', scheduleShellRefresh);
|
||||||
|
|
||||||
function startShellPolling() {
|
function startShellPolling() {
|
||||||
if (shellTimer) return;
|
if (shellTimer) return;
|
||||||
shellTimer = setInterval(function () { if (!document.hidden) refreshShellStatus(); }, 15000);
|
shellTimer = setInterval(function () { if (!document.hidden) refreshShellStatus(); }, 15000);
|
||||||
|
|||||||
Reference in new issue
Block a user