Skip to content

Commit

Permalink
fix: improve the speed of xray.config.include_db_users
Browse files Browse the repository at this point in the history
  • Loading branch information
SaintShit committed Jul 3, 2024
1 parent c1b47d6 commit 8485fda
Showing 1 changed file with 68 additions and 41 deletions.
109 changes: 68 additions & 41 deletions app/xray/config.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from __future__ import annotations

import json
from collections import defaultdict
from copy import deepcopy
from pathlib import PosixPath
from typing import Union

import commentjson
from sqlalchemy import func

from app.db import GetDB, crud
from app.models.proxy import ProxySettings, ProxyTypes
from app.db import GetDB
from app.db import models as db_models
from app.models.proxy import ProxyTypes
from app.models.user import UserStatus
from app.utils.crypto import get_cert_SANs
from config import DEBUG, XRAY_EXCLUDE_INBOUND_TAGS, XRAY_FALLBACKS_INBOUND_TAG
Expand Down Expand Up @@ -45,7 +48,6 @@ def __init__(self,
self.inbounds_by_protocol = {}
self.inbounds_by_tag = {}
self._fallbacks_inbound = self.get_inbound(XRAY_FALLBACKS_INBOUND_TAG)
self._addr_clients_by_tag = {}
self._resolve_inbounds()

self._apply_api()
Expand Down Expand Up @@ -119,6 +121,8 @@ def _validate(self):
for inbound in self['inbounds']:
if not inbound.get("tag"):
raise ValueError("all inbounds must have a unique tag")
if ',' in inbound.get("tag"):
raise ValueError("character «,» is not allowed in inbound tag")
for outbound in self['outbounds']:
if not outbound.get("tag"):
raise ValueError("all outbounds must have a unique tag")
Expand All @@ -135,8 +139,6 @@ def _resolve_inbounds(self):
inbound['settings'] = {}
if not inbound['settings'].get('clients'):
inbound['settings']['clients'] = []
self._addr_clients_by_tag[inbound['tag']
] = inbound['settings']['clients']

settings = {
"tag": inbound["tag"],
Expand Down Expand Up @@ -298,30 +300,6 @@ def _resolve_inbounds(self):
except KeyError:
self.inbounds_by_protocol[inbound['protocol']] = [settings]

def add_inbound_client(self, inbound_tag: str, email: str, settings: dict):
inbound = self.inbounds_by_tag.get(inbound_tag, {})
client = {"email": email, **settings}

# XTLS currently only supports transmission methods of TCP and mKCP
if client.get('flow') and (
inbound.get('network', 'tcp') not in ('tcp', 'kcp')
or
(
inbound.get('network', 'tcp') in ('tcp', 'kcp')
and
inbound.get('tls') not in ('tls', 'reality')
)
or
inbound.get('header_type') == 'http'
):
del client['flow']

try:
self._addr_clients_by_tag[inbound_tag].append(client)
except KeyError:
return
return client

def get_inbound(self, tag) -> dict:
for inbound in self['inbounds']:
if inbound['tag'] == tag:
Expand All @@ -342,18 +320,67 @@ def include_db_users(self) -> XRayConfig:
config = self.copy()

with GetDB() as db:
for user in crud.get_users(db, status=[UserStatus.active,
UserStatus.on_hold]):
proxies_settings = {
p.type: ProxySettings.from_dict(
p.type, p.settings).dict(no_obj=True)
for p in user.proxies
}
for proxy_type, inbound_tags in user.inbounds.items():
for inbound_tag in inbound_tags:
config.add_inbound_client(inbound_tag,
f"{user.id}.{user.username}",
proxies_settings[proxy_type])
query = db.query(
db_models.User.id,
db_models.User.username,
func.lower(db_models.Proxy.type).label('type'),
db_models.Proxy.settings,
func.group_concat(db_models.excluded_inbounds_association.c.inbound_tag).label('excluded_inbound_tags')
).join(
db_models.Proxy, db_models.User.id == db_models.Proxy.user_id
).outerjoin(
db_models.excluded_inbounds_association, db_models.Proxy.id == db_models.excluded_inbounds_association.c.proxy_id
).filter(
db_models.User.status.in_([UserStatus.active, UserStatus.on_hold])
).group_by(
func.lower(db_models.Proxy.type),
db_models.User.id
)
result = query.all()

grouped_data = defaultdict(list)

for row in result:
grouped_data[row["type"]].append((
row["id"],
row["username"],
row["settings"],
[i for i in row['excluded_inbound_tags'].split(',') if i] if row['excluded_inbound_tags'] else None
))

for proxy_type, rows in grouped_data.items():

inbounds = self.inbounds_by_protocol[proxy_type]

for inbound in inbounds:
clients = config.get_inbound(inbound['tag'])['settings']['clients']

for row in rows:
user_id, username, settings, excluded_inbound_tags = row

if excluded_inbound_tags and inbound['tag'] in excluded_inbound_tags:
continue

client = {
"email": f"{user_id}.{username}",
**settings
}

# XTLS currently only supports transmission methods of TCP and mKCP
if client.get('flow') and (
inbound.get('network', 'tcp') not in ('tcp', 'kcp')
or
(
inbound.get('network', 'tcp') in ('tcp', 'kcp')
and
inbound.get('tls') not in ('tls', 'reality')
)
or
inbound.get('header_type') == 'http'
):
del client['flow']

clients.append(client)

if DEBUG:
with open('generated_config-debug.json', 'w') as f:
Expand Down

0 comments on commit 8485fda

Please sign in to comment.