version 1.4.1: per-user WARP флаг, fallback-установка PyPI
- app.py: full_warp флаг в warp_rules, _rebuild_egress читает с диска, race condition fix - bot.py: full_warp поддержка в toggle_warp - templates/index.html: чекбокс «Весь трафик через WARP» с full_warp, не авто-включается - install-panel.sh: зеркала PyPI (aliyun), таймаут 120с на pip, fallback на apt --system-site-packages - install-bot.sh: зеркала и fallback для python-telegram-bot - README: версия 1.4, обновлён roadmap
This commit is contained in:
+28
-23
@@ -773,11 +773,24 @@ async function setWarp(name,enabled){
|
||||
async function openWarpRules(name){
|
||||
// Загрузить текущие правила
|
||||
const d=await api('/api/users/warp_rules?name='+encodeURIComponent(name));
|
||||
const r=d?.rules||{domains:[],ips:[],sources:[]};
|
||||
const r=d?.rules||{domains:[],ips:[],sources:[],full_warp:false};
|
||||
|
||||
const html=`
|
||||
<div style="display:flex;align-items:center;gap:12px;margin-bottom:18px;padding:12px 16px;background:var(--surface2);border:1px solid var(--border);border-radius:8px">
|
||||
<label class="toggle" style="flex-shrink:0">
|
||||
<input type="checkbox" id="wr-full-warp" ${r.full_warp?'checked':''}
|
||||
onchange="toggleFullWarp(this.checked)">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
<div>
|
||||
<div style="font-weight:600;font-size:.9rem">Весь трафик через WARP</div>
|
||||
<div style="font-size:.75rem;color:var(--muted)">Если включено — правила ниже игнорируются, всё идёт через WARP</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="wr-rules-section">
|
||||
<p style="color:var(--muted);font-size:.85rem;margin-bottom:18px;line-height:1.6">
|
||||
Трафик этого пользователя через <strong style="color:var(--accent)">WARP</strong> только для указанных доменов, IP и источников.<br>
|
||||
Если «Весь трафик» выключен — через <strong style="color:var(--accent)">WARP</strong> пойдут только указанные домены и IP.<br>
|
||||
Всё остальное идёт напрямую с IP вашего сервера.
|
||||
</p>
|
||||
|
||||
@@ -799,23 +812,9 @@ async function openWarpRules(name){
|
||||
color:var(--text);padding:10px 12px;border-radius:8px;font-family:var(--mono);font-size:.82rem;
|
||||
resize:vertical;outline:none;line-height:1.6" placeholder="104.16.0.0/12 172.64.0.0/13">${escH(r.ips.join('\n'))}</textarea>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom:20px">
|
||||
<label style="font-size:.8rem;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.6px;display:block;margin-bottom:8px">
|
||||
Источники — geosite / geoip / URL (по одному на строку)
|
||||
</label>
|
||||
<textarea id="wr-sources" rows="4" style="width:100%;background:var(--bg);border:1px solid var(--border);
|
||||
color:var(--text);padding:10px 12px;border-radius:8px;font-family:var(--mono);font-size:.82rem;
|
||||
resize:vertical;outline:none;line-height:1.6"
|
||||
placeholder="geosite:openai geosite:netflix geoip:us https://example.com/domains.txt">${escH(r.sources.join('\n'))}</textarea>
|
||||
<div style="font-size:.75rem;color:var(--muted);margin-top:6px;line-height:1.7">
|
||||
<strong style="color:var(--text)">geosite:категория</strong> — из базы v2fly (openai, google, netflix, category-ru…)<br>
|
||||
<strong style="color:var(--text)">geoip:страна</strong> — IP-диапазоны страны (us, gb, de…)<br>
|
||||
<strong style="color:var(--text)">https://…</strong> — прямая ссылка на текстовый файл с доменами или CIDR
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;gap:10px">
|
||||
<div style="display:flex;gap:10px;margin-top:16px">
|
||||
<button class="btn btn-primary" onclick="saveWarpRules('${escH(name)}')">
|
||||
Сохранить и применить
|
||||
</button>
|
||||
@@ -826,23 +825,29 @@ async function openWarpRules(name){
|
||||
openModal('WARP-правила: '+name, html);
|
||||
}
|
||||
|
||||
function toggleFullWarp(checked){
|
||||
const el=document.getElementById('wr-rules-section');
|
||||
if(el)el.style.display=checked?'none':'';
|
||||
}
|
||||
|
||||
async function saveWarpRules(name){
|
||||
const btn=document.querySelector('#modal-body .btn-primary');
|
||||
btn.disabled=true;
|
||||
btn.innerHTML='<span class="spinner"></span> Применяю…';
|
||||
|
||||
const domains=document.getElementById('wr-domains').value.split('\n').map(s=>s.trim()).filter(Boolean);
|
||||
const ips=document.getElementById('wr-ips').value.split('\n').map(s=>s.trim()).filter(Boolean);
|
||||
const sources=document.getElementById('wr-sources').value.split('\n').map(s=>s.trim()).filter(Boolean);
|
||||
const fullWarp=document.getElementById('wr-full-warp')?.checked||false;
|
||||
const domains=fullWarp?[]:document.getElementById('wr-domains').value.split('\n').map(s=>s.trim()).filter(Boolean);
|
||||
const ips=fullWarp?[]:document.getElementById('wr-ips').value.split('\n').map(s=>s.trim()).filter(Boolean);
|
||||
|
||||
const d=await api('/api/users/warp_rules','POST',{name,domains,ips,sources});
|
||||
const d=await api('/api/users/warp_rules','POST',{name,domains,ips,sources:[],full_warp:fullWarp});
|
||||
btn.disabled=false;
|
||||
btn.textContent='Сохранить и применить';
|
||||
|
||||
const el=document.getElementById('wr-result');
|
||||
if(d?.ok){
|
||||
el.innerHTML='<div class="alert alert-ok">✓ Правила сохранены и применены в mita</div>';
|
||||
showToast('Правила WARP обновлены');
|
||||
el.innerHTML=`<div class="alert alert-ok">✓ ${fullWarp?'Весь трафик через WARP':'Правила сохранены'} и применены в mita</div>`;
|
||||
showToast(fullWarp?'WARP: весь трафик для '+name:'Правила WARP обновлены');
|
||||
loadUsers();
|
||||
}else{
|
||||
el.innerHTML=`<div class="alert alert-err">Ошибка: ${escH(d?.error||'')}</div>`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user