diff --git a/apps/api/urls.py b/apps/api/urls.py index 218db49d93..7b950c3af9 100644 --- a/apps/api/urls.py +++ b/apps/api/urls.py @@ -16,6 +16,7 @@ path("change/theme/", views.change_theme, name="change_theme"), path("checkin/", views.UserCheckInView.as_view(), name="checkin"), path("rest_sub_uid/", views.reset_sub_uid, name="rest_sub_uid"), + path("delay/", views.DelayView.as_view(), name="delay"), # web api 接口 path( "proxy_configs//", diff --git a/apps/api/views.py b/apps/api/views.py index caae47e0dd..9e940819a0 100644 --- a/apps/api/views.py +++ b/apps/api/views.py @@ -1,3 +1,4 @@ +import time import pendulum from django.conf import settings from django.contrib.auth.decorators import login_required, permission_required @@ -220,6 +221,17 @@ def post(self, request): ) +class DelayView(View): + def get(self, request): + ip = get_client_ip(request) + node = m.ProxyNode.get_by_ip(ip) + delay_ms_map = m.ProxyNode.get_additional_delay_ms() + for node_id, delay_ms in delay_ms_map.items(): + if node_id == node.id: + time.sleep(delay_ms / 1000) + return JsonResponse({"msg": "ok"}) + + @login_required @require_http_methods(["POST"]) def purchase(request): diff --git a/apps/proxy/models.py b/apps/proxy/models.py index 4d261d7d52..0b3ac4015c 100644 --- a/apps/proxy/models.py +++ b/apps/proxy/models.py @@ -239,6 +239,31 @@ def get_active_nodes(cls, level=None): .order_by("sequence") ) + @classmethod + def get_by_ip(cls, ip): + nodes = cls.get_active_nodes() + for node in nodes: + node_ips = node.server.split(",") + if ip in node_ips: + return node + return None + + @classmethod + def get_additional_delay_ms(cls): + ms_max = 100 + add_delay_ms = {} + + nodes = cls.get_active_nodes() + all_bandwidth = list(node.download_bandwidth_bytes for node in nodes) + bw_min = min(all_bandwidth) # delay 0 + bw_max = max(all_bandwidth) # delay ms_max + if bw_min >= bw_max: + return {} + + for node in nodes: + add_delay_ms[node.id] = int(node.download_bandwidth_bytes - bw_min) / int(bw_max - bw_min) * ms_max + return add_delay_ms + @classmethod def calc_total_traffic(cls): aggs = cls.objects.all().aggregate(used_traffic=models.Sum("used_traffic")) diff --git a/apps/sspanel/tasks.py b/apps/sspanel/tasks.py index bbf2ffb47f..94cef501aa 100644 --- a/apps/sspanel/tasks.py +++ b/apps/sspanel/tasks.py @@ -34,7 +34,7 @@ def sync_user_traffic_task(node_id, data): trafficlog_model_list = [] # TODO to support old version, will delete in future - if type(data) == list: + if type(data) is list: data = {"data": data} # END TODO diff --git a/apps/sub.py b/apps/sub.py index 16be0c0d95..a7a5af3eeb 100644 --- a/apps/sub.py +++ b/apps/sub.py @@ -26,6 +26,11 @@ def __init__(self, user, sub_client, node_list): self.sub_client = sub_client self.node_list = node_list + def _get_delay_url(self): + return ( + settings.HOST + f"/api/delay" + ) + def _get_clash_sub_yaml(self): return render_to_string( "clash/main.yaml", @@ -33,6 +38,7 @@ def _get_clash_sub_yaml(self): "sub_client": self.sub_client, "provider_name": settings.TITLE, "proxy_provider_url": self.user.clash_proxy_provider_endpoint, + "check_delay_url": self._get_delay_url(), }, ) diff --git a/templates/clash/main.yaml b/templates/clash/main.yaml index b8e9b61c3b..67bc29179e 100644 --- a/templates/clash/main.yaml +++ b/templates/clash/main.yaml @@ -25,7 +25,7 @@ proxy-groups: type: url-test use: - {{ provider_name }} - url: 'http://www.gstatic.com/generate_204' + url: {{ check_delay_url }} interval: 300 proxy-providers: @@ -37,7 +37,7 @@ proxy-providers: health-check: enable: true interval: 600 - url: http://www.gstatic.com/generate_204 + url: {{ check_delay_url }} {% if sub_client == "clash" %} {% include "clash/rules.yaml" %}