Browse Source

style: optimize code and log output

master
dnomd343 2 years ago
parent
commit
d1d0d43672
  1. 6
      Basis/Check.py
  2. 2
      Basis/Compile.py
  3. 12
      Basis/Functions.py
  4. 4
      Basis/Logger.py
  5. 26
      Basis/Process.py
  6. 2
      Builder/Brook.py
  7. 34
      Builder/Hysteria.py
  8. 11
      Builder/Shadowsocks.py
  9. 2
      Builder/ShadowsocksR.py
  10. 7
      Builder/Trojan.py
  11. 46
      Builder/TrojanGo.py
  12. 9
      Builder/VLESS.py
  13. 2
      Builder/VMess.py
  14. 4
      Builder/Xray.py
  15. 7
      Tester/VMess.py
  16. 1
      main.py

6
Basis/Check.py

@ -23,14 +23,14 @@ def Check(taskId: str, taskInfo: dict) -> dict:
except Exception as reason:
logging.error('[%s] Client build error -> %s' % (taskId, reason))
raise RuntimeError('Client build error')
logging.info('[%s] Client loaded successfully')
logging.info('[%s] Client loaded successfully' % taskId)
# TODO: wait port occupied (client.socksPort)
time.sleep(1)
if not client.status(): # client unexpected exit
logging.warning('[%s] Client unexpected exit')
logging.warning('[%s] Client unexpected exit' % taskId)
client.destroy() # remove file and kill sub process
logging.debug('[%s] Client output\n%s', client.output)
logging.debug('[%s] Client output\n%s', (taskId, client.output))
raise RuntimeError('Client unexpected exit')
checkResult = Checker(taskId, taskInfo['check'], {

2
Basis/Compile.py

@ -7,5 +7,5 @@ from Basis.Logger import logging
def startCompile(dirRange: str = '/') -> None:
for optimize in [-1, 1, 2]:
logging.warning('python optimize compile -> %s (level = %i)' % (dirRange, optimize))
logging.warning('Python optimize compile -> %s (level = %i)' % (dirRange, optimize))
compileall.compile_dir(dirRange, quiet = 1, maxlevels = 256, optimize = optimize)

12
Basis/Functions.py

@ -32,7 +32,7 @@ def genFlag(length: int = 12) -> str: # generate random task flag
flag += chr(tmp + 87) # a ~ f
else:
flag += str(tmp) # 0 ~ 9
logging.debug('generate new flag -> ' + flag)
logging.debug('Generate new flag -> ' + flag)
return flag
@ -44,21 +44,21 @@ def genUUID() -> str: # generate uuid v5
def getAvailablePort(rangeStart: int = 1024, rangeEnd: int = 65535, waitTime: int = 10) -> int: # get available port
if rangeStart > rangeEnd or rangeStart < 1 or rangeEnd > 65535:
raise RuntimeError('invalid port range')
raise RuntimeError('Invalid port range')
while True:
port = random.randint(rangeStart, rangeEnd) # choose randomly
if checkPortStatus(port):
logging.debug('get new port -> %i' % port)
logging.debug('Get new port -> %i' % port)
return port
time.sleep(waitTime / 1000) # ms -> s (default 10ms)
def checkPortStatus(port: int) -> bool: # check if the port is occupied
logging.debug('check status of port %i -> available' % port)
for connection in networkStatus(): # scan every connections
if connection['local']['port'] == port: # port occupied (whatever ipv4-tcp / ipv4-udp / ipv6-tcp / ipv6-udp)
logging.debug('check status of port %i -> occupied' % port)
logging.debug('Check port %i -> occupied' % port)
return False
logging.debug('Check port %i -> available' % port)
return True
@ -84,5 +84,5 @@ def networkStatus() -> list: # get all network connections
'status': connection.status,
'pid': connection.pid, # process id
})
logging.debug('get network status -> found %i connections' % len(result))
logging.debug('Network status -> found %i connections' % len(result))
return result

4
Basis/Logger.py

@ -6,8 +6,8 @@ import logging
from colorlog import ColoredFormatter
logFile = 'runtime.log'
logLevel = logging.DEBUG
# logLevel = logging.WARNING
# logLevel = logging.DEBUG
logLevel = logging.WARNING
dateFormat = '%Y-%m-%d %H:%M:%S'
logFormat = '[%(asctime)s] [%(levelname)s] %(message)s (%(module)s.%(funcName)s)'
logging.basicConfig(

26
Basis/Process.py

@ -73,13 +73,13 @@ class Process(object):
logging.error('[%s] %s already exist but not folder' % (self.id, self.workDir))
else:
logging.error('[%s] Unable to create new folder -> %s' % (self.id, self.workDir))
raise RuntimeError('working directory error') # fatal error
raise RuntimeError('Working directory error') # fatal error
def __killProcess(self, killSignal: int) -> None:
try:
pgid = os.getpgid(self.__process.pid) # progress group id
os.killpg(pgid, killSignal) # kill sub process group
logging.debug('[%s] Send kill signal to PGID %i' % (self.id, pgid))
logging.debug('[%s] Send signal %i to PGID %i' % (self.id, killSignal, pgid))
except:
logging.warning('[%s] Failed to get PGID of sub process (PID = %i)' % (self.id, self.__process.pid))
@ -129,15 +129,15 @@ class Process(object):
def start(self, isCapture: bool = True) -> None:
self.__capture = isCapture
logging.debug('[%s] Process ready to start (%s)' % (self.id, (
'with output capture' if self.__capture else 'without output capture'
)))
logging.debug('[%s] Process ready to start (%s)' % (
self.id, ('with' if self.__capture else 'without') + ' output capture'
))
if self.cmd is None: # ERROR CASE
logging.error('[%s] Process miss start command' % self.id)
raise RuntimeError('miss start command')
raise RuntimeError('Miss start command')
if self.__process is not None and self.__process.poll() is None: # ERROR CASE
logging.error('[%s] Sub process is still running' % self.id)
raise RuntimeError('sub process is still running')
logging.error('[%s] Process is still running' % self.id)
raise RuntimeError('Process is still running')
if self.env is not None and 'PATH' not in self.env and '/' not in self.cmd[0]: # WARNING CASE
logging.warning('[%s] Executable file in relative path but miss PATH in environ' % self.id)
if self.file is not None: # create and write file contents
@ -147,7 +147,7 @@ class Process(object):
logging.debug('[%s] File %s -> %s' % (self.id, file['path'], file['content']))
if self.__capture: # with output capture
self.__logfile = os.path.join(self.workDir, self.id + '.log')
logging.debug('[%s] Output capture file -> %s' % (self.id, self.__logfile))
logging.debug('[%s] Process output capture -> %s' % (self.id, self.__logfile))
stdout = open(self.__logfile, 'w', encoding = 'utf-8')
stderr = STDOUT # combine the stderr with stdout
else: # discard all the output of sub process
@ -170,20 +170,20 @@ class Process(object):
def status(self) -> bool: # check if the sub process is still running
status = self.__process.poll() is None
logging.debug('[%s] Check status -> %s' % (self.id, 'running' if status else 'exit'))
logging.debug('[%s] Process check status -> %s' % (self.id, 'running' if status else 'exit'))
return status
def wait(self, timeout: int or None = None) -> None: # blocking wait sub process
logging.info('[%s] Process wait -> timeout = %s' % (self.id, str(timeout)))
try:
self.__process.wait(timeout = timeout)
logging.info('[%s] Process wait timeout -> sub process exit' % self.id)
logging.info('[%s] Process wait timeout -> exit' % self.id)
except:
logging.info('[%s] Process wait timeout -> sub process still running' % self.id)
logging.info('[%s] Process wait timeout -> running' % self.id)
def quit(self, isForce: bool = False, waitTime: int = 50) -> None: # wait 50ms in default
killSignal = signal.SIGKILL if isForce else signal.SIGTERM # 9 -> force kill / 15 -> terminate signal
logging.debug('[%s] Kill signal = %i (%s)' % (self.id, killSignal, signal.Signals(killSignal).name))
logging.debug('[%s] Kill signal -> %i (%s)' % (self.id, killSignal, signal.Signals(killSignal).name))
self.__killProcess(killSignal)
time.sleep(waitTime / 1000) # sleep (ms -> s)
while self.__process.poll() is None: # confirm sub process exit

2
Builder/Brook.py

@ -35,4 +35,4 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str,
}[proxyInfo['stream']['type']](proxyInfo) + [
'--socks5', '%s:%i' % (hostFormat(socksInfo['addr'], v6Bracket = True), socksInfo['port'])
]
return brookCommand, 'Config file %s no need' % configFile, {}
return brookCommand, 'Config file %s no need' % configFile, {} # command, fileContent, envVar

34
Builder/Hysteria.py

@ -6,7 +6,7 @@ from Basis.Functions import hostFormat
def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, dict]:
hysteriaConfig = {**{
hysteriaConfig = {
'server': '%s:%i' % (hostFormat(proxyInfo['server'], v6Bracket = True), proxyInfo['port']),
'protocol': proxyInfo['protocol'],
'up_mbps': proxyInfo['up'],
@ -15,16 +15,22 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str,
'retry': 3,
'socks5': {
'listen': '%s:%i' % (hostFormat(socksInfo['addr'], v6Bracket = True), socksInfo['port'])
}
}, **({} if proxyInfo['obfs'] is None else {
'obfs': proxyInfo['obfs']
}), **({} if proxyInfo['passwd'] is None else {
'auth_str': proxyInfo['passwd']
}), **({} if proxyInfo['sni'] == '' else {
'server_name': proxyInfo['sni']
}), **({} if proxyInfo['alpn'] is None else {
'alpn': proxyInfo['alpn']
}), **({} if proxyInfo['verify'] else {
'insecure': True
})}
return ['hysteria', '-c', configFile, 'client'], json.dumps(hysteriaConfig), {'LOGGING_LEVEL': 'trace'}
},
**({} if proxyInfo['obfs'] is None else {
'obfs': proxyInfo['obfs']
}),
**({} if proxyInfo['passwd'] is None else {
'auth_str': proxyInfo['passwd']
}),
**({} if proxyInfo['sni'] == '' else {
'server_name': proxyInfo['sni']
}),
**({} if proxyInfo['alpn'] is None else {
'alpn': proxyInfo['alpn']
}),
**({} if proxyInfo['verify'] else {
'insecure': True
})
}
return ['hysteria', '-c', configFile, 'client'], \
json.dumps(hysteriaConfig), {'LOGGING_LEVEL': 'trace'} # command, fileContent, envVar

11
Builder/Shadowsocks.py

@ -72,12 +72,9 @@ def ssPythonLegacy(proxyInfo: dict, socksInfo: dict, isUdp: bool) -> tuple[dict,
def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, dict]:
if proxyInfo['plugin'] is None: # UDP is enabled when server without plugin
isUdp = True
else:
isUdp = not pluginUdp( # check the UDP conflict status of plugins
proxyInfo['plugin']['type'], proxyInfo['plugin']['param']
)
isUdp = True if proxyInfo['plugin'] is None else ( # UDP enabled when server without plugin
not pluginUdp(proxyInfo['plugin']['type'], proxyInfo['plugin']['param']) # UDP conflict status of plugins
)
if proxyInfo['method'] not in ssAllMethods: # unknown shadowsocks method
raise RuntimeError('Unknown shadowsocks method')
for client in ssMethods: # traverse all shadowsocks client
@ -89,4 +86,4 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str,
'ss-python': ssPython,
'ss-python-legacy': ssPythonLegacy
}[client](proxyInfo, socksInfo, isUdp) # generate config file
return ssClient + ['-c', configFile], json.dumps(ssConfig), {} # tuple[command, fileContent, envVar]
return ssClient + ['-c', configFile], json.dumps(ssConfig), {} # command, fileContent, envVar

2
Builder/ShadowsocksR.py

@ -24,4 +24,4 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str,
'obfs': proxyInfo['obfs'],
'obfs_param': proxyInfo['obfsParam']
}
return ['ssr-local', '-vv', '-c', configFile], json.dumps(ssrConfig), {} # tuple[command, fileContent, envVar]
return ['ssr-local', '-vv', '-c', configFile], json.dumps(ssrConfig), {} # command, fileContent, envVar

7
Builder/Trojan.py

@ -9,13 +9,14 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str,
outboundConfig = {
'protocol': 'trojan',
'settings': {
'servers': [{**{
'servers': [{
'address': proxyInfo['server'],
'port': proxyInfo['port'],
'password': proxyInfo['passwd'],
}, **Xray.xtlsFlow(proxyInfo['stream'])}]
**Xray.xtlsFlow(proxyInfo['stream'])
}]
},
'streamSettings': Xray.loadStream(proxyInfo['stream'])
}
trojanConfig = Xray.loadConfig(socksInfo, outboundConfig) # load config file for xray-core
return ['xray', '-c', configFile], json.dumps(trojanConfig), {}
return ['xray', '-c', configFile], json.dumps(trojanConfig), {} # command, fileContent, envVar

46
Builder/TrojanGo.py

@ -5,13 +5,15 @@ import json
def sslConfig(proxyInfo: dict) -> dict:
return {**{
'verify': proxyInfo['verify']
}, **({} if proxyInfo['sni'] == '' else {
'sni': proxyInfo['sni']
}), **({} if proxyInfo['alpn'] is None else {
'alpn': proxyInfo['alpn'].split(',')
})}
return {
'verify': proxyInfo['verify'],
**({} if proxyInfo['sni'] == '' else {
'sni': proxyInfo['sni']
}),
**({} if proxyInfo['alpn'] is None else {
'alpn': proxyInfo['alpn'].split(',')
}),
}
def wsConfig(proxyInfo: dict) -> dict:
@ -27,22 +29,24 @@ def wsConfig(proxyInfo: dict) -> dict:
def ssConfig(proxyInfo: dict) -> dict:
return {**{
'enabled': False if proxyInfo['ss'] is None else True
}, **({} if proxyInfo['ss'] is None else {
'method': proxyInfo['ss']['method'],
'password': proxyInfo['ss']['passwd'],
})}
return {
'enabled': False if proxyInfo['ss'] is None else True,
**({} if proxyInfo['ss'] is None else {
'method': proxyInfo['ss']['method'],
'password': proxyInfo['ss']['passwd'],
})
}
def pluginConfig(proxyInfo: dict) -> dict:
return {**{
'enabled': False if proxyInfo['plugin'] is None else True
}, **({} if proxyInfo['plugin'] is None else {
'type': 'shadowsocks',
'command': proxyInfo['plugin']['type'],
'option': proxyInfo['plugin']['param'],
})}
return {
'enabled': False if proxyInfo['plugin'] is None else True,
**({} if proxyInfo['plugin'] is None else {
'type': 'shadowsocks',
'command': proxyInfo['plugin']['type'],
'option': proxyInfo['plugin']['param'],
})
}
def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str, dict]:
@ -61,4 +65,4 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str,
'shadowsocks': ssConfig(proxyInfo),
'transport_plugin': pluginConfig(proxyInfo),
}
return ['trojan-go', '-config', configFile], json.dumps(trojanGoConfig), {}
return ['trojan-go', '-config', configFile], json.dumps(trojanGoConfig), {} # command, fileContent, envVar

9
Builder/VLESS.py

@ -12,13 +12,14 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str,
'vnext': [{
'address': proxyInfo['server'],
'port': proxyInfo['port'],
'users': [{**{
'users': [{
'id': proxyInfo['id'],
'encryption': proxyInfo['method']
}, **Xray.xtlsFlow(proxyInfo['stream'])}]
'encryption': proxyInfo['method'],
**Xray.xtlsFlow(proxyInfo['stream'])
}]
}]
},
'streamSettings': Xray.loadStream(proxyInfo['stream'])
}
vlessConfig = Xray.loadConfig(socksInfo, outboundConfig) # load config file for xray-core
return ['xray', '-c', configFile], json.dumps(vlessConfig), {}
return ['xray', '-c', configFile], json.dumps(vlessConfig), {} # command, fileContent, envVar

2
Builder/VMess.py

@ -25,4 +25,4 @@ def load(proxyInfo: dict, socksInfo: dict, configFile: str) -> tuple[list, str,
'streamSettings': V2ray.loadStream(proxyInfo['stream'])
}
vmessConfig = V2ray.loadConfig(socksInfo, outboundConfig) # load config file for v2ray-core
return ['v2ray', '-c', configFile], json.dumps(vmessConfig), {}
return ['v2ray', '-c', configFile], json.dumps(vmessConfig), {} # command, fileContent, envVar

4
Builder/Xray.py

@ -34,9 +34,9 @@ def wsStream(streamInfo: dict) -> dict: # WebSocket stream config (different ed
wsObject['headers']['Host'] = streamInfo['host']
if streamInfo['ed'] is not None: # ed value into uri path -> /...?ed=xxx
if wsObject['path'].find('?') == -1: # no params in raw path
wsObject['path'] += '?ed=' + str(streamInfo['ed'])
wsObject['path'] += '?ed=%i' % streamInfo['ed']
else:
wsObject['path'] += '&ed=' + str(streamInfo['ed'])
wsObject['path'] += '&ed=%i' % streamInfo['ed']
return {
'network': 'ws',
'wsSettings': wsObject

7
Tester/VMess.py

@ -6,11 +6,10 @@ import json
import itertools
from Tester import V2ray
from Builder import VMess
from Builder import pathEnv
from Basis.Logger import logging
from Basis.Process import Process
from Tester.Settings import Settings
from Basis.Constant import vmessMethods
from Basis.Constant import PathEnv, vmessMethods
from Basis.Functions import md5Sum, genUUID, getAvailablePort
@ -31,8 +30,8 @@ def loadServer(configFile: str, proxyInfo: dict, streamConfig: dict) -> Process:
return Process(Settings['workDir'], cmd = ['v2ray', '-c', serverFile], file = {
'path': serverFile,
'content': json.dumps(vmessConfig)
}, env= {
'PATH': pathEnv,
}, env = {
'PATH': PathEnv,
'v2ray.vmess.aead.forced': 'false' # enable non-aead test (aid not 0)
}, isStart = False)

1
main.py

@ -50,7 +50,6 @@ def loopCheck() -> None:
try:
taskId, taskInfo = Manager.popTask()
except:
logging.debug('no more task')
continue
logging.info('new task %s -> %s' % (taskId, taskInfo))
ret = Check(taskId, taskInfo)

Loading…
Cancel
Save