|
@@ -1,6 +1,6 @@
|
|
|
# -*- coding: utf-8 -*-
|
|
# -*- coding: utf-8 -*-
|
|
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
|
-from odoo import fields, models
|
|
|
|
|
|
|
+from odoo import fields, models, api
|
|
|
from odoo.exceptions import UserError
|
|
from odoo.exceptions import UserError
|
|
|
from urllib.parse import quote
|
|
from urllib.parse import quote
|
|
|
import httpx
|
|
import httpx
|
|
@@ -19,8 +19,6 @@ class ClashTools(models.Model):
|
|
|
|
|
|
|
|
current_node = fields.Char('Current Node')
|
|
current_node = fields.Char('Current Node')
|
|
|
|
|
|
|
|
- skip_node = fields.Char('Skip Node', help='Use semicolons to separate')
|
|
|
|
|
-
|
|
|
|
|
total_nodes = fields.Integer('Total Nodes')
|
|
total_nodes = fields.Integer('Total Nodes')
|
|
|
|
|
|
|
|
use_type = fields.Selection([
|
|
use_type = fields.Selection([
|
|
@@ -28,8 +26,12 @@ class ClashTools(models.Model):
|
|
|
('depin', 'Depin'),
|
|
('depin', 'Depin'),
|
|
|
], string='Use Type', default='')
|
|
], string='Use Type', default='')
|
|
|
|
|
|
|
|
|
|
+ current_node_state = fields.Char('Current Node State')
|
|
|
|
|
+
|
|
|
line_ids = fields.One2many('clash.tools.line', 'clash_tools_id', string='Line')
|
|
line_ids = fields.One2many('clash.tools.line', 'clash_tools_id', string='Line')
|
|
|
|
|
|
|
|
|
|
+ clash_no_skip_config_id = fields.Many2one('clash.no_skip.config', string='Clash Skip Config')
|
|
|
|
|
+
|
|
|
def btn_init_data(self):
|
|
def btn_init_data(self):
|
|
|
# 一键创建所有局域网中的 clash 连接, 因为懒
|
|
# 一键创建所有局域网中的 clash 连接, 因为懒
|
|
|
data_dict = {
|
|
data_dict = {
|
|
@@ -175,25 +177,29 @@ class ClashTools(models.Model):
|
|
|
line_delay_min = self.line_ids.search([('clash_tools_id', '=', rec.id), ('node_state', '=', 'ok')], order='delay asc')
|
|
line_delay_min = self.line_ids.search([('clash_tools_id', '=', rec.id), ('node_state', '=', 'ok')], order='delay asc')
|
|
|
|
|
|
|
|
for line in line_delay_min:
|
|
for line in line_delay_min:
|
|
|
- if rec.skip_node:
|
|
|
|
|
|
|
+ if rec.clash_no_skip_config_id:
|
|
|
try:
|
|
try:
|
|
|
- skip_node_list = rec.skip_node.split(';')
|
|
|
|
|
|
|
+ no_skip_node_list = rec.clash_no_skip_config_id.no_skip_domains.split(';')
|
|
|
except:
|
|
except:
|
|
|
raise UserError('Please enter the node name to skip, separated by semicolons.')
|
|
raise UserError('Please enter the node name to skip, separated by semicolons.')
|
|
|
|
|
|
|
|
- # 查看是否存在需要跳过的节点, 如果是, 则跳过
|
|
|
|
|
- for skip_node in skip_node_list:
|
|
|
|
|
- if skip_node in line.name:
|
|
|
|
|
- continue
|
|
|
|
|
- else:
|
|
|
|
|
- # 这里不是跳过, 然后检查一下有没使用过这个节点
|
|
|
|
|
- if line.name in selected_node_list:
|
|
|
|
|
- continue
|
|
|
|
|
- else:
|
|
|
|
|
- # 这里是既不是跳过, 有没有使用过, 就使用这个节点
|
|
|
|
|
- self._use_select_node(line)
|
|
|
|
|
- selected_node_list.append(line.name)
|
|
|
|
|
- break
|
|
|
|
|
|
|
+ # 查看是否存在不需要跳过的节点, 如果是, 查看有没有使用过这个节点, 如果使用过, 就跳过
|
|
|
|
|
+ # 如果没有使用过, 则使用这个节点, 之后将这个节点添加到已使用列表中
|
|
|
|
|
+ # 判定节点的时候, 部分节点是英文, 所以需要统一一下大小写
|
|
|
|
|
+ selected = False
|
|
|
|
|
+ for no_skip_node in no_skip_node_list:
|
|
|
|
|
+ if line.name in selected_node_list:
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ if no_skip_node.strip().lower() in line.name.lower():
|
|
|
|
|
+ self._use_select_node(line)
|
|
|
|
|
+ selected_node_list.append(line.name)
|
|
|
|
|
+ selected = True
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
|
|
+ if selected:
|
|
|
|
|
+ break
|
|
|
|
|
+
|
|
|
else:
|
|
else:
|
|
|
# 如果跳过节点的条件为空, 则判断是否使用过这个节点, 没有就使用
|
|
# 如果跳过节点的条件为空, 则判断是否使用过这个节点, 没有就使用
|
|
|
if line.name in selected_node_list:
|
|
if line.name in selected_node_list:
|
|
@@ -203,6 +209,23 @@ class ClashTools(models.Model):
|
|
|
selected_node_list.append(line.name)
|
|
selected_node_list.append(line.name)
|
|
|
break
|
|
break
|
|
|
|
|
|
|
|
|
|
+ def btn_check_current_node(self):
|
|
|
|
|
+ for rec in self:
|
|
|
|
|
+ if not rec.localhost_ip or not rec.line_ids or not rec.current_node:
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ url = rec.localhost_ip
|
|
|
|
|
+ if 'https' in url:
|
|
|
|
|
+ raise UserError('Local network services do not require HTTPS.')
|
|
|
|
|
+ if 'http' not in url:
|
|
|
|
|
+ url = 'http://' + url
|
|
|
|
|
+
|
|
|
|
|
+ result = self._check_node(quote(rec.current_node, safe=""), url)
|
|
|
|
|
+ if result != 9999:
|
|
|
|
|
+ rec.current_node_state = ';'.join([f'{k}:{v}' for k, v in result.items()])
|
|
|
|
|
+ else:
|
|
|
|
|
+ rec.current_node_state = 'error'
|
|
|
|
|
+
|
|
|
def _set_global_proxy(self, url, rec):
|
|
def _set_global_proxy(self, url, rec):
|
|
|
setting_url = url + '/api/configs'
|
|
setting_url = url + '/api/configs'
|
|
|
|
|
|
|
@@ -246,12 +269,17 @@ class ClashTools(models.Model):
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
response = httpx.get(proxies_list_url, headers=headers)
|
|
response = httpx.get(proxies_list_url, headers=headers)
|
|
|
-
|
|
|
|
|
- result = []
|
|
|
|
|
-
|
|
|
|
|
proxies_list = response.json()
|
|
proxies_list = response.json()
|
|
|
- for proxies in proxies_list.get('proxies'):
|
|
|
|
|
- result.append(proxies)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if self.clash_no_skip_config_id:
|
|
|
|
|
+ try:
|
|
|
|
|
+ skip_node_list = self.clash_no_skip_config_id.no_skip_domains.split(';')
|
|
|
|
|
+ skip_node_set = {node.lower() for node in skip_node_list}
|
|
|
|
|
+ result = [proxies for proxies in proxies_list.get('proxies') if any(skip_node in proxies.lower() for skip_node in skip_node_set)]
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ raise UserError(f'{self.name} Please enter the node name to skip, separated by semicolons.\nerror: {e}')
|
|
|
|
|
+ else:
|
|
|
|
|
+ result = proxies_list.get('proxies', [])
|
|
|
|
|
|
|
|
return result
|
|
return result
|
|
|
|
|
|
|
@@ -405,3 +433,16 @@ class ClashToolsLine(models.Model):
|
|
|
'mean_delay': res,
|
|
'mean_delay': res,
|
|
|
'node_state': 'error'
|
|
'node_state': 'error'
|
|
|
})
|
|
})
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class ClashSkipConfig(models.Model):
|
|
|
|
|
+ _name = 'clash.no_skip.config'
|
|
|
|
|
+ _description = 'Clash No Skip Config'
|
|
|
|
|
+
|
|
|
|
|
+ name = fields.Char('Name')
|
|
|
|
|
+ no_skip_domains = fields.Char('No Skip Domains')
|
|
|
|
|
+
|
|
|
|
|
+ @api.depends('name', 'no_skip_domains')
|
|
|
|
|
+ def _compute_display_name(self):
|
|
|
|
|
+ for record in self:
|
|
|
|
|
+ record.display_name = f'{record.name} - {record.no_skip_domains}'
|