Browse Source

update: proxyc init process

dev
dnomd343 2 years ago
parent
commit
428d2d414d
  1. 2
      Dockerfile
  2. 97
      Main.py
  3. 65
      Test.py
  4. 24
      Utils/Api.py
  5. 6
      env.yml
  6. 141
      main.py

2
Dockerfile

@ -448,7 +448,7 @@ COPY . /asset/usr/local/share/ProxyC/
# Release docker image # Release docker image
FROM ${PYTHON_IMG} FROM ${PYTHON_IMG}
RUN apk add --no-cache boost-program_options c-ares ca-certificates libev libsodium libstdc++ mbedtls pcre && \ RUN apk add --no-cache boost-program_options c-ares ca-certificates libev libsodium libstdc++ mbedtls pcre && \
ln -s /usr/local/share/ProxyC/main.py /usr/bin/proxyc ln -s /usr/local/share/ProxyC/Main.py /usr/bin/proxyc
COPY --from=asset /asset / COPY --from=asset /asset /
EXPOSE 7839 EXPOSE 7839
ENTRYPOINT ["proxyc"] ENTRYPOINT ["proxyc"]

97
Main.py

@ -0,0 +1,97 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import time
import _thread
import argparse
import compileall
from Utils import Constant
from Utils.Exception import checkException
def parseArgs(rawArgs: list) -> argparse.Namespace:
mainParser = argparse.ArgumentParser(description = 'Start running API server')
mainParser.add_argument('--log', type = str, default = Constant.LogLevel, help = 'output log level')
mainParser.add_argument('--dns', type = str, default = Constant.DnsServer, nargs = '+', help = 'specify dns server')
mainParser.add_argument('--port', type = int, default = Constant.ApiPort, help = 'port for running')
mainParser.add_argument('--path', type = str, default = Constant.ApiPath, help = 'root path for api server')
mainParser.add_argument('--token', type = str, default = Constant.ApiToken, help = 'token for api server')
mainParser.add_argument('--thread', type = int, default = Constant.CheckThread, help = 'number of check thread')
mainParser.add_argument('-v', '--version', help = 'show version', action = 'store_true')
return mainParser.parse_args(rawArgs)
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1].lower() == 'test': # test mode
from Test import runTest
runTest(sys.argv[2:])
sys.exit(0)
mainArgs = parseArgs(sys.argv[1:])
if mainArgs.version: # output version and exit
print('ProxyC version %s' % Constant.Version)
sys.exit(0)
Constant.LogLevel = mainArgs.log # overwrite global options
Constant.DnsServer = mainArgs.dns
Constant.ApiPort = mainArgs.port
Constant.ApiPath = mainArgs.path
Constant.ApiToken = mainArgs.token
Constant.CheckThread = mainArgs.thread
if __name__ == '__main__':
from Utils.Check import Check
from Utils import Api, DnsProxy
from Utils.Logger import logger
from Utils.Manager import Manager
from concurrent.futures import ThreadPoolExecutor
def pythonCompile(dirRange: str = '/') -> None: # python optimize compile
for optimize in [-1, 1, 2]:
compileall.compile_dir(dirRange, quiet = 1, optimize = optimize)
logger.info('Python optimize compile -> %s (level = %i)' % (dirRange, optimize))
def runCheck(taskId: str, taskInfo: dict) -> None:
success = True
checkResult = {}
try:
checkResult = Check(taskId, taskInfo) # check by task info
logger.warning('[%s] Task finish' % taskId)
except checkException as exp:
success = False
logger.error('[%s] Task error -> %s' % (taskId, exp))
except:
success = False
logger.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) -> None:
logger.warning('Loop check start -> %i threads' % threadNum)
threadPool = ThreadPoolExecutor(max_workers = threadNum) # init thread pool
while True:
try:
taskId, taskInfo = Manager.popTask() # pop a task
logger.warning('[%s] Load new task' % taskId)
except: # no more task
time.sleep(2)
continue
threadPool.submit(runCheck, taskId, taskInfo) # submit into thread pool
if __name__ == '__main__':
logger.warning('ProxyC starts running (%s)' % Constant.Version)
_thread.start_new_thread(pythonCompile, ('/usr',)) # python compile (generate .pyc file)
_thread.start_new_thread(DnsProxy.start, (Constant.DnsServer, 53)) # start dns server
_thread.start_new_thread(loop, (Constant.CheckThread, )) # start check loop
Api.startServer() # start api server

65
Test.py

@ -0,0 +1,65 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import argparse
from Utils import Constant
def parseArgs(rawArgs: list) -> argparse.Namespace:
testParser = argparse.ArgumentParser(description = 'Test that each function is working properly')
testParser.add_argument('PROTOCOL', type = str, help = 'test protocol name')
testParser.add_argument('-a', '--all', help = 'test extra shadowsocks items', action = 'store_true')
testParser.add_argument('-6', '--ipv6', help = 'test on ipv6 network', action = 'store_true')
testParser.add_argument('--debug', help = 'enable debug log level', action = 'store_true')
testParser.add_argument('--url', type = str, default = 'http://google.com', help = 'http request url')
testParser.add_argument('--cert', type = str, default = '', help = 'specify the certificate id')
testParser.add_argument('--thread', type = int, default = 16, help = 'thread number in check process')
testParser.add_argument('--select', type = str, nargs = '+', help = 'select id list for test')
return testParser.parse_args(rawArgs)
def initTest(args: list) -> argparse.Namespace:
if len(args) == 0 or args[0].startswith('-'): # no protocol is specified
args = ['all'] + args # test all items
testArgs = parseArgs(args)
Constant.LogLevel = 'debug' if testArgs.debug else 'warning'
from Tester import testEntry
from Utils.Logger import logger # load logger after setting up LogLevel
from Utils.Tester import loadBind, loadCert
if testArgs.PROTOCOL != 'all' and testArgs.PROTOCOL not in testEntry:
logger.error('Unknown protocol -> %s' % testArgs.PROTOCOL)
sys.exit(1)
loadBind(serverV6 = testArgs.ipv6, clientV6 = testArgs.ipv6) # ipv4 / ipv6 (127.0.0.1 / ::1)
loadCert(certId = testArgs.cert) # certificate config
logger.critical('TEST ITEM: %s' % testArgs.PROTOCOL)
logger.critical('SELECT: ' + str(testArgs.select))
logger.critical('URL: %s' % testArgs.url)
logger.critical('THREAD NUMBER: %i' % testArgs.thread)
return testArgs
def runTest(args: list) -> None: # run test process
testArgs = initTest(args)
from Tester import testEntry
from Utils.Tester import Test
from Utils.Logger import logger
logger.critical('-' * 32 + ' TEST START ' + '-' * 32) # test start
if testArgs.PROTOCOL == 'all': # run all test items
for item in testEntry:
if item == ('ss' if testArgs.all else 'ss-all'): # skip ss / ss-all
continue
logger.critical('TEST ITEM -> ' + item)
Test(testEntry[item], testArgs.thread, testArgs.url, testArgs.select)
else: # run single item
if testArgs.PROTOCOL == 'ss' and testArgs.all: # test shadowsocks extra items
testArgs.PROTOCOL = 'ss-all'
Test(testEntry[testArgs.PROTOCOL], testArgs.thread, testArgs.url, testArgs.select)
logger.critical('-' * 32 + ' TEST COMPLETE ' + '-' * 32) # test complete
if __name__ == '__main__':
runTest(sys.argv[1:])

24
Basis/Api.py → Utils/Api.py

@ -5,11 +5,11 @@ import os
import json import json
from gevent import pywsgi from gevent import pywsgi
from Checker import formatCheck from Checker import formatCheck
from Basis.Logger import logging from Utils.Logger import logger
from Basis.Manager import Manager from Utils.Manager import Manager
from flask import Flask, Response, request from flask import Flask, Response, request
from Basis.Exception import managerException from Utils.Exception import managerException
from Basis.Constant import ApiPort, ApiPath, ApiToken, Version from Utils.Constant import ApiPort, ApiPath, ApiToken, Version
webApi = Flask(__name__) # init flask server webApi = Flask(__name__) # init flask server
@ -57,7 +57,7 @@ def getTaskList() -> Response:
if not tokenCheck(): # token check if not tokenCheck(): # token check
return genError('Invalid token') return genError('Invalid token')
taskList = Manager.listUnion() taskList = Manager.listUnion()
logging.debug('API get task list -> %s' % taskList) logger.debug('API get task list -> %s' % taskList)
return jsonResponse({ return jsonResponse({
'success': True, 'success': True,
'task': taskList, 'task': taskList,
@ -81,7 +81,7 @@ def createTask() -> Response:
except Exception as exp: except Exception as exp:
return genError('Proxy error in %s -> %s' % (proxy, exp)) return genError('Proxy error in %s -> %s' % (proxy, exp))
logging.debug('API create task -> check = %s | proxy = %s' % (checkList, proxyList)) logger.debug('API create task -> check = %s | proxy = %s' % (checkList, proxyList))
tasks = [] tasks = []
for proxy in proxyList: for proxy in proxyList:
tasks.append({ tasks.append({
@ -89,7 +89,7 @@ def createTask() -> Response:
'check': checkList # load check items 'check': checkList # load check items
}) })
checkId = Manager.addUnion(tasks) # add into manager -> get id checkId = Manager.addUnion(tasks) # add into manager -> get id
logging.debug('API return task id -> %s' % checkId) logger.debug('API return task id -> %s' % checkId)
return jsonResponse({ return jsonResponse({
'success': True, 'success': True,
'id': checkId, 'id': checkId,
@ -102,7 +102,7 @@ def createTask() -> Response:
def getTaskInfo(taskId: str) -> Response: def getTaskInfo(taskId: str) -> Response:
if not tokenCheck(): # token check if not tokenCheck(): # token check
return genError('Invalid token') return genError('Invalid token')
logging.debug('API get task -> %s' % taskId) logger.debug('API get task -> %s' % taskId)
if not Manager.isUnion(taskId): if not Manager.isUnion(taskId):
return genError('Task not found') return genError('Task not found')
return jsonResponse({ return jsonResponse({
@ -115,7 +115,7 @@ def getTaskInfo(taskId: str) -> Response:
def deleteTask(taskId: str) -> Response: def deleteTask(taskId: str) -> Response:
if not tokenCheck(): # token check if not tokenCheck(): # token check
return genError('Invalid token') return genError('Invalid token')
logging.debug('API get task -> %s' % taskId) logger.debug('API get task -> %s' % taskId)
if not Manager.isUnion(taskId): if not Manager.isUnion(taskId):
return genError('Task not found') return genError('Task not found')
try: try:
@ -129,7 +129,7 @@ def deleteTask(taskId: str) -> Response:
@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) logger.debug('API get version -> %s' + Version)
return jsonResponse({ return jsonResponse({
'success': True, 'success': True,
'version': Version, 'version': Version,
@ -137,6 +137,6 @@ def getVersion() -> Response:
def startServer() -> None: def startServer() -> None:
logging.warning('API server at http://:%i%s' % (ApiPort, ApiPath)) logger.warning('API server at http://:%i%s' % (ApiPort, ApiPath))
logging.warning('API ' + ('without token' if ApiToken == '' else 'token -> %s' % ApiToken)) logger.warning('API ' + ('without token' if ApiToken == '' else 'token -> %s' % ApiToken))
pywsgi.WSGIServer(('0.0.0.0', ApiPort), webApi).serve_forever() # powered by gevent pywsgi.WSGIServer(('0.0.0.0', ApiPort), webApi).serve_forever() # powered by gevent

6
env.yml

@ -1,8 +1,8 @@
version: '0.1' version: '0.9.0'
loglevel: 'INFO' loglevel: 'INFO'
dir: '/tmp/ProxyC-test' dir: '/tmp/ProxyC'
dns: null dns: null
api: api:
port: 7839 port: 7839
# path: '/' path: '/'
token: '' token: ''

141
main.py

@ -1,141 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import copy
import time
import _thread
import argparse
import compileall
from Utils import Constant
from Utils.Exception import checkException
def mainArgParse(rawArgs: list) -> argparse.Namespace:
mainParser = argparse.ArgumentParser(description = 'Start running API server')
mainParser.add_argument('--log', type = str, default = Constant.LogLevel, help = 'output log level')
mainParser.add_argument('--dns', type = str, default = Constant.DnsServer, nargs = '+', help = 'specify dns server')
mainParser.add_argument('--port', type = int, default = Constant.ApiPort, help = 'port for running')
mainParser.add_argument('--path', type = str, default = Constant.ApiPath, help = 'root path for api server')
mainParser.add_argument('--token', type = str, default = Constant.ApiToken, help = 'token for api server')
mainParser.add_argument('--thread', type = int, default = Constant.CheckThread, help = 'number of check thread')
mainParser.add_argument('-v', '--version', help = 'show version', action = 'store_true')
return mainParser.parse_args(rawArgs)
def testArgParse(rawArgs: list) -> argparse.Namespace:
testParser = argparse.ArgumentParser(description = 'Test that each function is working properly')
testParser.add_argument('PROTOCOL', type = str, help = 'test protocol name')
testParser.add_argument('-a', '--all', help = 'test extra shadowsocks items', action = 'store_true')
testParser.add_argument('-6', '--ipv6', help = 'test on ipv6 network', action = 'store_true')
testParser.add_argument('--debug', help = 'enable debug log level', action = 'store_true')
testParser.add_argument('--url', type = str, default = 'http://baidu.com', help = 'http request url')
testParser.add_argument('--cert', type = str, default = '', help = 'specify the certificate id')
testParser.add_argument('--thread', type = int, default = 16, help = 'thread number in check process')
testParser.add_argument('--select', type = str, nargs = '+', help = 'select id list for test')
return testParser.parse_args(rawArgs)
testArgs = None
testMode = False
inputArgs = copy.copy(sys.argv)
if len(inputArgs) >= 0: # remove first arg (normally file name)
inputArgs.pop(0)
if len(inputArgs) != 0 and inputArgs[0].lower() == 'test': # test mode
inputArgs.pop(0) # remove `test`
if len(inputArgs) == 0 or inputArgs[0].startswith('-'): # no protocol is specified
inputArgs = ['all'] + inputArgs
testArgs = testArgParse(inputArgs)
Constant.LogLevel = 'debug' if testArgs.debug else 'warning'
testMode = True
else:
mainArgs = mainArgParse(inputArgs)
if mainArgs.version: # output version and exit
print('ProxyC version %s' % Constant.Version)
sys.exit(0)
Constant.LogLevel = mainArgs.log # overwrite global options
Constant.DnsServer = mainArgs.dns
Constant.ApiPort = mainArgs.port
Constant.ApiPath = mainArgs.path
Constant.ApiToken = mainArgs.token
Constant.CheckThread = mainArgs.thread
from Tester import testEntry
from Utils.Check import Check
# from Utils import Api, DnsProxy
from Utils import DnsProxy
from Utils.Logger import logger
from Utils.Manager import Manager
from Utils.Tester import Test, loadBind, loadCert
from concurrent.futures import ThreadPoolExecutor
def pythonCompile(dirRange: str = '/') -> None: # python optimize compile
for optimize in [-1, 1, 2]:
compileall.compile_dir(dirRange, quiet = 1, optimize = optimize)
logger.warning('Python optimize compile -> %s (level = %i)' % (dirRange, optimize))
def runCheck(taskId: str, taskInfo: dict) -> None:
success = True
checkResult = {}
try:
checkResult = Check(taskId, taskInfo) # check by task info
logger.warning('[%s] Task finish' % taskId)
except checkException as exp:
success = False
logger.error('[%s] Task error -> %s' % (taskId, exp))
except:
success = False
logger.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) -> None:
logger.warning('Loop check start -> %i threads' % threadNum)
threadPool = ThreadPoolExecutor(max_workers = threadNum) # init thread pool
while True:
try:
taskId, taskInfo = Manager.popTask() # pop a task
logger.warning('[%s] Load new task' % taskId)
except: # no more task
time.sleep(2)
continue
threadPool.submit(runCheck, taskId, taskInfo) # submit into thread pool
if testMode: # test mode
loadBind(serverV6 = testArgs.ipv6, clientV6 = testArgs.ipv6) # ipv4 / ipv6 (127.0.0.1 / ::1)
loadCert(certId = testArgs.cert) # cert config
logger.critical('TEST ITEM: %s' % testArgs.PROTOCOL)
logger.critical('SELECT: ' + str(testArgs.select))
logger.critical('URL: %s' % testArgs.url)
logger.critical('THREAD NUMBER: %i' % testArgs.thread)
logger.critical('-' * 32 + ' TEST START ' + '-' * 32)
if testArgs.PROTOCOL == 'all': # run all test items
for item in testEntry:
if item == ('ss' if testArgs.all else 'ss-all'): # skip ss / ss-all
continue
logger.critical('TEST ITEM -> ' + item)
Test(testEntry[item], testArgs.thread, testArgs.url, testArgs.select)
else: # run single item
if testArgs.PROTOCOL == 'ss' and testArgs.all: # test shadowsocks extra items
testItem = 'ss-all'
Test(testEntry[testArgs.PROTOCOL], testArgs.thread, testArgs.url, testArgs.select)
logger.critical('-' * 32 + ' TEST COMPLETE ' + '-' * 32)
sys.exit(0) # test complete
logger.warning('ProxyC starts running (%s)' % Constant.Version)
_thread.start_new_thread(pythonCompile, ('/usr',)) # python compile (generate .pyc file)
_thread.start_new_thread(DnsProxy.start, (Constant.DnsServer, 53)) # start dns server
_thread.start_new_thread(loop, (Constant.CheckThread, )) # start check loop
# Api.startServer() # start api server
Loading…
Cancel
Save