Browse Source

update: enhance api logical

master^2
dnomd343 2 years ago
parent
commit
29742f2c78
  1. 30
      Basis/Api.py
  2. 18
      Basis/Check.py
  3. 26
      Basis/Constant.py
  4. 25
      Basis/Manager.py
  5. 23
      main.py

30
Basis/Api.py

@ -8,6 +8,7 @@ from Checker import formatCheck
from Basis.Logger import logging from Basis.Logger import logging
from Basis.Manager import Manager from Basis.Manager import Manager
from flask import Flask, Response, request from flask import Flask, Response, request
from Basis.Exception import managerException
from Basis.Constant import ApiPort, ApiPath, ApiToken, Version from Basis.Constant import ApiPort, ApiPath, ApiToken, Version
webApi = Flask(__name__) # init flask server webApi = Flask(__name__) # init flask server
@ -68,12 +69,17 @@ def createTask() -> Response:
if not tokenCheck(): # token check if not tokenCheck(): # token check
return genError('Invalid token') return genError('Invalid token')
# TODO: format check and proxy list try:
checkList = formatCheck(request.json.get('check')) # TODO: format check and proxy list
checkList = formatCheck(request.json.get('check'))
except:
return genError('Some error in check options')
proxyList = [] proxyList = []
for proxy in request.json.get('proxy'): for proxy in request.json.get('proxy'):
proxyList.append(formatProxy(proxy)) try:
logging.critical(proxyList) proxyList.append(formatProxy(proxy))
except Exception as exp:
return genError('Proxy error in %s -> %s' % (proxy, exp))
logging.debug('API create task -> check = %s | proxy = %s' % (checkList, proxyList)) logging.debug('API create task -> check = %s | proxy = %s' % (checkList, proxyList))
tasks = [] tasks = []
@ -105,6 +111,22 @@ def getTaskInfo(taskId: str) -> Response:
}) })
@webApi.route(os.path.join(ApiPath, 'task/<taskId>'), methods = ['DELETE'])
def deleteTask(taskId: str) -> Response:
if not tokenCheck(): # token check
return genError('Invalid token')
logging.debug('API get task -> %s' % taskId)
if not Manager.isUnion(taskId):
return genError('Task not found')
try:
Manager.delUnion(taskId)
return jsonResponse({
'success': True
})
except managerException as exp:
return genError(str(exp))
@webApi.route(os.path.join(ApiPath, 'version'), methods = ['GET']) @webApi.route(os.path.join(ApiPath, 'version'), methods = ['GET'])
def getVersion() -> Response: def getVersion() -> Response:
logging.debug('API get version -> %s' + Version) logging.debug('API get version -> %s' + Version)

18
Basis/Check.py

@ -6,6 +6,8 @@ import time
from Checker import Checker from Checker import Checker
from Basis.Logger import logging from Basis.Logger import logging
from Builder import Builder, clientEntry from Builder import Builder, clientEntry
from Basis.Exception import checkException
from Basis.Functions import checkPortStatus
def buildClient(taskId: str, taskInfo: dict) -> Builder: def buildClient(taskId: str, taskInfo: dict) -> Builder:
@ -18,24 +20,27 @@ def buildClient(taskId: str, taskInfo: dict) -> Builder:
) )
except Exception as reason: except Exception as reason:
logging.error('[%s] Client build error -> %s' % (taskId, reason)) logging.error('[%s] Client build error -> %s' % (taskId, reason))
raise RuntimeError('Client build error') raise checkException('Client build error')
def waitClient(taskId: str, client: Builder): def waitClient(taskId: str, client: Builder, times: int = 150, delay: int = 100): # wait until client port occupied
# TODO: wait port occupied (client.socksPort) for i in range(times):
time.sleep(1) # TODO: simple delay for now if not checkPortStatus(client.socksPort): # port occupied
break
time.sleep(delay / 1000) # wait in default: 100ms * 150 => 15s
time.sleep(1) # wait a short time before check process
if not client.status(): # client unexpected exit if not client.status(): # client unexpected exit
logging.warning('[%s] Client unexpected exit' % taskId) logging.warning('[%s] Client unexpected exit' % taskId)
client.destroy() # remove file and kill sub process client.destroy() # remove file and kill sub process
logging.debug('[%s] Client output\n%s', (taskId, client.output)) logging.debug('[%s] Client output\n%s', (taskId, client.output))
raise RuntimeError('Client unexpected exit') raise checkException('Client unexpected exit')
def Check(taskId: str, taskInfo: dict) -> dict: def Check(taskId: str, taskInfo: dict) -> dict:
logging.info('[%s] Start checking process -> %s' % (taskId, taskInfo)) logging.info('[%s] Start checking process -> %s' % (taskId, taskInfo))
if taskInfo['type'] not in clientEntry: # unknown proxy type if taskInfo['type'] not in clientEntry: # unknown proxy type
logging.error('[%s] Unknown proxy type %s' % (taskId, taskInfo['type'])) logging.error('[%s] Unknown proxy type %s' % (taskId, taskInfo['type']))
raise RuntimeError('Unknown proxy type') raise checkException('Unknown proxy type')
client = buildClient(taskId, taskInfo) # build proxy client client = buildClient(taskId, taskInfo) # build proxy client
logging.info('[%s] Client loaded successfully' % taskId) logging.info('[%s] Client loaded successfully' % taskId)
waitClient(taskId, client) # wait for the client to start waitClient(taskId, client) # wait for the client to start
@ -49,5 +54,6 @@ def Check(taskId: str, taskInfo: dict) -> dict:
taskInfo.pop('check') # remove check items taskInfo.pop('check') # remove check items
return { return {
**taskInfo, **taskInfo,
'success': True,
'result': checkResult, # add check result 'result': checkResult, # add check result
} }

26
Basis/Constant.py

@ -20,10 +20,15 @@ TestHost = 'proxyc.net'
TestSite = 'www.bing.com' TestSite = 'www.bing.com'
PathEnv = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin' PathEnv = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin'
# Load Env Options # Load Env Options
yamlFile = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../env.yaml') envOptions = {}
yamlContent = open(yamlFile, 'r', encoding = 'utf-8').read() try:
envOptions = yaml.load(yamlContent, Loader = yaml.FullLoader) yamlFile = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../env.yaml')
yamlContent = open(yamlFile, 'r', encoding = 'utf-8').read()
envOptions = yaml.load(yamlContent, Loader = yaml.FullLoader)
except: # something error in env.yaml
pass
if 'version' in envOptions: if 'version' in envOptions:
Version = envOptions['version'] Version = envOptions['version']
if 'loglevel' in envOptions: if 'loglevel' in envOptions:
@ -40,12 +45,14 @@ if 'api' in envOptions:
if 'token' in envOptions['api']: if 'token' in envOptions['api']:
ApiToken = envOptions['api']['token'] ApiToken = envOptions['api']['token']
# WorkDir Create # WorkDir Create
try: try:
os.makedirs(WorkDir) # just like `mkdir -p ...` os.makedirs(WorkDir) # just like `mkdir -p ...`
except: except:
pass # folder exist or target is another thing pass # folder exist or target is another thing
# Shadowsocks Info # Shadowsocks Info
mbedtlsMethods = [ mbedtlsMethods = [
'aes-128-cfb128', 'aes-128-cfb128',
@ -120,6 +127,7 @@ ssAllMethods = set()
[ssAllMethods.update(ssMethods[x]) for x in ssMethods] [ssAllMethods.update(ssMethods[x]) for x in ssMethods]
ssAllMethods = sorted(list(ssAllMethods)) # methods of Shadowsocks ssAllMethods = sorted(list(ssAllMethods)) # methods of Shadowsocks
# Plugin Info # Plugin Info
Plugins = { Plugins = {
'simple-obfs': ['obfs-local', 'obfs-server'], 'simple-obfs': ['obfs-local', 'obfs-server'],
@ -140,6 +148,7 @@ Plugins = {x: [Plugins[x][0], Plugins[x][1 if len(Plugins[x]) == 2 else 0]] for
Plugins = {x: {'client': Plugins[x][0], 'server': Plugins[x][1]} for x in Plugins} # format plugins info Plugins = {x: {'client': Plugins[x][0], 'server': Plugins[x][1]} for x in Plugins} # format plugins info
pluginClients = [Plugins[x]['client'] for x in Plugins] # plugin client list -> obfs-local / simple-tls / ... pluginClients = [Plugins[x]['client'] for x in Plugins] # plugin client list -> obfs-local / simple-tls / ...
# ShadowsocksR Info # ShadowsocksR Info
ssrMethods = [ # methods of ShadowsocksR ssrMethods = [ # methods of ShadowsocksR
'aes-128-ctr', 'aes-192-ctr', 'aes-256-ctr', 'aes-128-ctr', 'aes-192-ctr', 'aes-256-ctr',
@ -168,19 +177,20 @@ ssrObfuscations = [ # obfuscations of ShadowsocksR (obfs)
'tls_simple', 'tls1.2_ticket_auth', 'tls1.2_ticket_fastauth', 'tls_simple', 'tls1.2_ticket_auth', 'tls1.2_ticket_fastauth',
] ]
# VMess Info
# V2ray / Xray Info
vmessMethods = ['aes-128-gcm', 'chacha20-poly1305', 'auto', 'none', 'zero'] vmessMethods = ['aes-128-gcm', 'chacha20-poly1305', 'auto', 'none', 'zero']
# XTLS Info quicMethods = ['none', 'aes-128-gcm', 'chacha20-poly1305']
udpObfuscations = ['none', 'srtp', 'utp', 'wechat-video', 'dtls', 'wireguard']
xtlsFlows = ['xtls-origin', 'xtls-direct', 'xtls-splice'] xtlsFlows = ['xtls-origin', 'xtls-direct', 'xtls-splice']
xtlsFlows = {x: x.replace('-', '-rprx-') for x in xtlsFlows} xtlsFlows = {x: x.replace('-', '-rprx-') for x in xtlsFlows}
# v2ray / Xray Info
quicMethods = ['none', 'aes-128-gcm', 'chacha20-poly1305']
udpObfuscations = ['none', 'srtp', 'utp', 'wechat-video', 'dtls', 'wireguard']
# Trojan-Go Info # Trojan-Go Info
trojanGoMethods = ['aes-128-gcm', 'aes-256-gcm', 'chacha20-ietf-poly1305'] trojanGoMethods = ['aes-128-gcm', 'aes-256-gcm', 'chacha20-ietf-poly1305']
# Hysteria Info # Hysteria Info
hysteriaProtocols = ['udp', 'wechat-video', 'faketcp'] hysteriaProtocols = ['udp', 'wechat-video', 'faketcp']

25
Basis/Manager.py

@ -39,15 +39,26 @@ class Task(object):
logging.info('Manager add task [%s] -> %s' % (taskId, task)) logging.info('Manager add task [%s] -> %s' % (taskId, task))
self.__tasks.update(tasks) # load into task list self.__tasks.update(tasks) # load into task list
self.__unions[unionId] = { self.__unions[unionId] = {
'finish': False,
'items': taskIds # record task items 'items': taskIds # record task items
} }
logging.info('Manager add union [%s] -> %s' % (unionId, taskIds)) logging.info('Manager add union [%s] -> %s' % (unionId, taskIds))
return unionId return unionId
def delUnion(self, unionId) -> None: # remove union
if unionId not in self.__unions:
logging.error('Manager union [%s] not found' % unionId)
raise managerException('Union id not found')
if not self.__unions[unionId]['finish']: # some tasks are still running
raise managerException('Couldn\'t remove working union')
self.__unions.pop(unionId)
def getUnion(self, unionId: str) -> dict: # get union status (remove tasks when all completed) def getUnion(self, unionId: str) -> dict: # get union status (remove tasks when all completed)
if unionId not in self.__unions: if unionId not in self.__unions:
logging.error('Manager union [%s] not found' % unionId) logging.error('Manager union [%s] not found' % unionId)
raise managerException('Union id not found') raise managerException('Union id not found')
if self.__unions[unionId]['finish']: # all tasks are finished
return self.__unions[unionId]
tasks = self.__unions[unionId]['items'] tasks = self.__unions[unionId]['items']
finishNum = 0 finishNum = 0
for taskId in tasks: for taskId in tasks:
@ -60,17 +71,15 @@ class Task(object):
'finish': False, 'finish': False,
'percent': round(finishNum / len(tasks), 2) 'percent': round(finishNum / len(tasks), 2)
} }
self.__unions.pop(unionId) # remove from union list self.__unions[unionId]['result'] = []
unionResult = [] # temporary storage
for taskId in tasks: for taskId in tasks:
task = self.__tasks[taskId] task = self.__tasks[taskId]
self.__tasks.pop(taskId) # remove from task list self.__tasks.pop(taskId) # remove from task list
unionResult.append(task['data']) self.__unions[unionId]['result'].append(task['data'])
logging.info('Manager release union [%s] -> %s' % (unionId, unionResult)) self.__unions[unionId]['finish'] = True
return { self.__unions[unionId].pop('items')
'finish': True, logging.info('Manager release union [%s] -> %s' % (unionId, self.__unions[unionId]['result']))
'result': unionResult return self.__unions[unionId]
}
def popTask(self) -> tuple[str or None, any]: # fetch a loaded task def popTask(self) -> tuple[str or None, any]: # fetch a loaded task
for taskId, task in self.__tasks.items(): for taskId, task in self.__tasks.items():

23
main.py

@ -8,6 +8,7 @@ import _thread
import argparse import argparse
import compileall import compileall
from Basis import Constant from Basis import Constant
from Basis.Exception import checkException
def mainArgParse(rawArgs: list) -> argparse.Namespace: def mainArgParse(rawArgs: list) -> argparse.Namespace:
@ -74,9 +75,25 @@ def pythonCompile(dirRange: str = '/') -> None: # python optimize compile
def runCheck(taskId: str, taskInfo: dict) -> None: def runCheck(taskId: str, taskInfo: dict) -> None:
checkResult = Check(taskId, taskInfo) # check by task info success = True
logging.warning('[%s] Task finish' % taskId) checkResult = {}
Manager.finishTask(taskId, checkResult) # commit check result try:
checkResult = Check(taskId, taskInfo) # check by task info
logging.warning('[%s] Task finish' % taskId)
except checkException as exp:
success = False
logging.error('[%s] Task error -> %s' % (taskId, exp))
except:
success = False
logging.error('[%s] Task error -> Unknown error' % taskId)
finally:
if not success: # got some error in check process
taskInfo.pop('check')
checkResult = {
**taskInfo,
'success': False,
}
Manager.finishTask(taskId, checkResult) # commit check result
def loop(threadNum: int = 16) -> None: def loop(threadNum: int = 16) -> None:

Loading…
Cancel
Save