diff --git a/Check.py b/Check.py deleted file mode 100644 index d2e2ea3..0000000 --- a/Check.py +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/python -# -*- coding:utf-8 -*- - -import os -import time - -import ProxyBuilder as Builder -import ProxyChecker as Checker -import ProxyFilter as Filter - -def __loadDir(folderPath: str) -> bool: # 创建文件夹 - try: - if os.path.exists(folderPath): # 文件 / 文件夹 存在 - if not os.path.isdir(folderPath): # 文件 - return False # 无法创建 - else: # 不存在 - os.makedirs(folderPath) # 递归创建文件夹 - return True # 文件夹正常 - except: - return False - -def __proxyHttpCheck(socksPort: int, httpCheckUrl: str, httpCheckTimeout: float) -> dict or None: # Http检测 - try: - health, httpDelay = Checker.httpCheck( - socksPort, - url = httpCheckUrl, - timeout = httpCheckTimeout - ) - if health is None: # 连接失败 - return None - return { - 'delay': httpDelay, - 'health': health - } - except: # 未知错误 - return None - -def proxyTest( - rawInfo: dict, - startDelay: float = 1, - workDir: str = '/tmp/ProxyC', - httpCheckUrl: str = 'http://gstatic.com/generate_204', - httpCheckTimeout: float = 20) -> dict or None: - """ - 代理检测入口 - - 程序异常: - return None - - 启动失败: - return { - 'success': False, - 'info': proxyInfo - } - - 测试完成: - return { - 'success': True, - 'check': checkResult, - 'info': proxyInfo - } - - """ - if not __loadDir(workDir): # 工作文件夹无效 - return None - if 'info' not in rawInfo: # 缺少代理服务器信息 - return None - - client = None - status, proxyInfo = Filter.filte(rawInfo['info'], isExtra = True) - if not status: # 输入节点错误 - return { - 'success': False, - 'info': None - } - try: - status, client = Builder.build(proxyInfo, workDir) - except Exception as reason: # 构建发生错误 - print(str(reason)) - Builder.destroy(client) - return None - if not status: # 节点信息有误 - return { - 'success': False, - 'info': proxyInfo - } - - time.sleep(startDelay) # 延迟等待客户端启动 - try: - status = Builder.check(client) # 检查客户端状态 - except: # 检测失败 - Builder.destroy(client) - return None - if not status: # 客户端异常退出 - Builder.destroy(client) - return { - 'success': False, - 'info': proxyInfo - } - - if 'check' not in rawInfo: # 缺少检测项目 - return None - checkItem = rawInfo['check'] - checkResult = {} - for item in checkItem: - if item == 'http': # http检测 - result = __proxyHttpCheck(client['port'], httpCheckUrl, httpCheckTimeout) - else: # 未知检测项目 - result = None - if result is None: # 检测出错 - Builder.destroy(client) - return None - checkResult[item] = result - - Builder.destroy(client) # 销毁客户端 - return { - 'success': True, - 'check': checkResult, - 'info': proxyInfo - } diff --git a/Loop.py b/Loop.py deleted file mode 100644 index 9adc724..0000000 --- a/Loop.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/python -# -*- coding:utf-8 -*- - -import time -import redis -import subprocess - -maxThread = 32 - -redisPort = 6379 -redisHost = 'localhost' -redisPrefix = 'proxyc-' - -redisObject = redis.StrictRedis( - db = 0, - host = redisHost, - port = redisPort -) - -processList = [] -runScript = '/root/ProxyC/Run.py' -# runScript = '/usr/local/share/ProxyC/Run.py' - -while True: - spareNum = min( - maxThread - len(processList), # 空余进程数 - len(redisObject.keys(redisPrefix + 'check-*')) # 待检测个数 - ) - if spareNum < 0: # 待运行进程数 > 0 - spareNum = 0 - for i in range(spareNum): # 运行检测进程 - processList.append( - subprocess.Popen(['python', runScript]) - ) - time.sleep(0.2) - - for process in processList: # 遍历子进程 - if process.poll() is not None: # 进程已退出 - processList.remove(process) - - time.sleep(0.5) diff --git a/Run.py b/Run.py deleted file mode 100644 index dbfc892..0000000 --- a/Run.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/python -# -*- coding:utf-8 -*- - -import json -import redis -import Check as Checker - -redisPort = 6379 -redisHost = 'localhost' -redisPrefix = 'proxyc-' - -def __getCheckInfo() -> tuple[str or None, dict or None]: - """ - 获取检测任务 - - 无任务或发生异常: - return None, None - - 任务格式有误: - return tag, None - - 任务获取成功: - return tag, {...} - """ - try: - checkList = redisObject.keys(redisPrefix + 'check-a-*') # 优先级排序 - if len(checkList) == 0: - checkList = redisObject.keys(redisPrefix + 'check-b-*') - if len(checkList) == 0: - checkList = redisObject.keys(redisPrefix + 'check-c-*') - if len(checkList) == 0: - checkList = redisObject.keys(redisPrefix + 'check-d-*') - if len(checkList) == 0: - checkList = redisObject.keys(redisPrefix + 'check-e-*') - if len(checkList) == 0: # 无任务 - return None, None - key = checkList[0] # 选取首个任务 - taskContent = redisObject.get(key) # 获取任务信息 - redisObject.delete(key) # 删除任务记录 - tag = str(key[len(redisPrefix) + 8:], encoding = 'utf-8') # {prefix}check-x-{tag} - except: - return None, None - try: - return tag, json.loads(taskContent) # JSON解码 - except: # JSON解码失败 - return tag, None - -def __setCheckResult(checkTag: str, checkResult: dict) -> bool: # 写入检测结果 - try: - key = redisPrefix + 'result-' + checkTag - redisObject.set(key, json.dumps(checkResult)) - return True - except: - return False - -def main(startDelay: float, httpCheckUrl: str, httpCheckTimeout: int) -> None: - checkTag, checkInfo = __getCheckInfo() # 获取检测任务 - if checkTag is None: - print("no task found") - return - print(checkInfo) - checkResult = Checker.proxyTest( - checkInfo, - startDelay = startDelay, - httpCheckUrl = httpCheckUrl, - httpCheckTimeout = httpCheckTimeout - ) - if checkResult is None: - print("some bad things happen") - return - elif not checkResult['success']: - print("error proxy info") - return - print(checkTag + ' -> ', end = '') - print(checkResult) - if not __setCheckResult(checkTag, checkResult): - print("redis write error") - return - -defaultStartDelay = 1.5 -defaultHttpCheckTimeout = 20 -defaultHttpCheckUrl = 'http://gstatic.com/generate_204' - -redisObject = redis.StrictRedis(host = redisHost, port = redisPort, db = 0) # 连接Redis数据库 - -main(defaultStartDelay, defaultHttpCheckUrl, defaultHttpCheckTimeout) diff --git a/Web.py b/Web.py deleted file mode 100644 index 574ef97..0000000 --- a/Web.py +++ /dev/null @@ -1,455 +0,0 @@ -#!/usr/bin/python -# -*- coding:utf-8 -*- - -import json -import redis -import random -from flask import Flask, request - -apiPath = '/' -api = Flask(__name__) - -redisPort = 6379 -redisHost = 'localhost' -redisPrefix = 'proxyc-' - -accessToken = 'dnomd343' - -def httpPostArg(field: str) -> dict or str or None: # 获取HTTP POST参数 - try: - if request.values.get(field) is not None: # application/x-www-form-urlencoded - return request.values.get(field) - elif request.json.get(field) is not None: # application/json - return request.json.get(field) - elif request.form.get(field) is not None: # multipart/form-data - return request.form.get(field) - except: - pass - return None - -def genRandomId(length: int = 24) -> str: # 生成随机ID - tag = '' - for i in range(0, length): - tmp = random.randint(0, 15) - if tmp >= 10: - tag += chr(tmp + 87) # a ~ f - else: - tag += str(tmp) # 0 ~ 9 - return tag - -def genError(message: str) -> dict: # 生成错误回复 - return { - 'success': False, - 'message': message - } - -def genSuccess(data: dict) -> dict: # 生成成功返回 - data['success'] = True - return data - -def getCheckList(userId: str) -> list or None: # 获取检测任务列表 - try: - taskList = [] - rawTaskList = redisObject.keys(redisPrefix + 'task-' + userId + '*') - for task in rawTaskList: # 获取任务ID - taskList.append(str(task[len(redisPrefix) + 5:], encoding = 'utf-8')) - return taskList - except: - return None - -def addCheckTask(checkList: dict, proxyList: dict, priority: str, userId: str) -> dict: # 新增检测任务 - try: - import ProxyDecoder as Decoder - import ProxyFilter as Filter - - checkList = list(set(checkList)) # 检测方式去重 - for checkMethod in checkList: - if checkMethod not in ['http']: - return genError('unknown check method `' + checkMethod + '`') - - for i in range(0, len(proxyList)): - proxyList[i] = Decoder.decode(proxyList[i]) # 解码分享链接 - if proxyList[i] is None: - return genError('could not decode index ' + str(i)) - status, proxyList[i] = Filter.filte(proxyList[i], isExtra = True) # 节点信息检查 - if not status: # 节点不合法 - return genError('index ' + str(i) + ': ' + proxyList[i]) - - tagList = [] - for proxyInfo in proxyList: - tag = genRandomId(32) # 32位检测ID - tagList.append(tag) - redisObject.set( # 写入数据库 - redisPrefix + 'check-' + priority + '-' + tag, - json.dumps({ - 'tag': tag, - 'check': checkList, - 'info': proxyInfo - }) - ) - - checkId = userId + genRandomId(8) # 24位userId + 8位随机 -> 32位任务ID - redisObject.set( # 记录任务 - redisPrefix + 'task-' + checkId, - json.dumps({ - 'checkId': checkId, - 'priority': priority, - 'check': checkList, - 'proxy': tagList, - 'complete': False - }) - ) - return genSuccess({ - 'checkId': checkId - }) - except: - return genError('server error') - -def getTaskInfo(checkId: str) -> dict: # 获取任务详情 - try: - taskKey = redisObject.keys(redisPrefix + 'task-' + checkId) - if not taskKey: # 任务ID不存在 - return genError('invalid check id') - taskKey = str(taskKey[0], encoding = 'utf-8') - taskInfo = json.loads( - redisObject.get(taskKey) - ) - if taskInfo['complete']: # 任务已完成 - return { - 'success': True, - 'complete': True, - 'checkId': checkId, - 'number': len(taskInfo['proxy']), - 'result': taskInfo['result'] - } - - completeNum = 0 # 测试完成数目 - for tag in taskInfo['proxy']: - if redisObject.keys(redisPrefix + 'result-' + tag): # 暂未测试 - completeNum += 1 - if completeNum < len(taskInfo['proxy']): # 测试未完成 - return { - 'success': True, - 'complete': False, - 'checkId': checkId, - 'number': len(taskInfo['proxy']), - 'schedule': round(completeNum / len(taskInfo['proxy']), 2) - } - - checkResult = [] - for tag in taskInfo['proxy']: # 遍历检测结果 - checkResult.append( - json.loads( - redisObject.get(redisPrefix + 'result-' + tag) - ) - ) - redisObject.delete(redisPrefix + 'result-' + tag) # 删除测试结果 - taskInfo['complete'] = True - taskInfo['result'] = checkResult - redisObject.set(taskKey, json.dumps(taskInfo)) # 记入数据库 - return { - 'success': True, - 'complete': True, - 'checkId': checkId, - 'number': len(taskInfo['proxy']), - 'result': taskInfo['result'] - } - except: - return genError('server error') - -def deleteTask(checkId: str) -> dict: # 删除任务 - try: - taskKey = redisObject.keys(redisPrefix + 'task-' + checkId) - if not taskKey: # 任务ID不存在 - return genError('invalid check id') - taskKey = str(taskKey[0], encoding = 'utf-8') - taskInfo = json.loads( - redisObject.get(taskKey) - ) - if not taskInfo['complete']: # 任务未完成 - return genError('task not complete') - redisObject.delete(taskKey) - return { - 'success': True, - 'checkId': checkId - } - except: - return genError('server error') - -def isAdminToken(token: str) -> bool: - """ - 是否为管理员token - - 验证成功: - return True - - 验证失败: - return False - """ - adminToken = accessToken - return token == adminToken - -def isUserToken(token: str) -> bool: - """ - 是否为有效token - - token有效: - return True - - token无效: - return False - """ - try: - if token.encode('utf-8') in redisObject.smembers(redisPrefix + 'users'): - return True - except: - pass - return False - -def addUser(priority: str, remain: int or str) -> tuple[bool, str]: - """ - 添加账号 - - 添加成功: - return True, userId - - 添加异常: - return False, {reason} - """ - try: - userId = genRandomId(length = 24) - if priority not in ['a', 'b', 'c', 'd', 'e']: # 优先级无效 - return False, 'invalid priority' - remain = int(remain) - if remain < 0: - remain = -1 # 不限次数 - userInfo = { - 'token': userId, - 'priority': priority, - 'remain': remain - } - redisObject.sadd( # 添加账号token - redisPrefix + 'users', userId - ) - redisObject.set( # 记录账号信息 - redisPrefix + 'user-' + userId, - json.dumps(userInfo) - ) - return True, userId # 返回userId - except: - return False, 'server error' - -def delUser(userId: str) -> tuple[bool, str]: - """ - 删除账号 - - 删除成功: - return True, userId - - 删除失败: - return False, {reason} - """ - try: - if not isUserToken(userId): - return False, 'invalid user id' - - taskList = redisObject.keys(redisPrefix + 'task-' + userId + '*') - if taskList: - return False, 'task list not empty' - - redisObject.srem(redisPrefix + 'users', userId) - redisObject.delete(redisPrefix + 'user-' + userId) - return True, userId - except: - return False, 'server error' - -def getUserInfo(userId: str, minus: bool = False) -> dict or None: - """ - 获取账号信息 (minus = True: 剩余次数 - 1) - - 获取异常: - return None - - 获取成功: - return { - 'token': '...' - 'priority': '...', - 'remain': ... - } - """ - try: - if not isUserToken(userId): # userId不存在 - return None - userInfo = json.loads( - redisObject.get(redisPrefix + 'user-' + userId) # 账号信息 - ) - if minus and userInfo['remain'] > 0: - userInfo['remain'] -= 1 # 剩余次数 - 1 - redisObject.set( - redisPrefix + 'user-' + userId, # 记入数据库 - json.dumps(userInfo) - ) - return userInfo - except: - return None # 异常 - -def getUserList() -> dict or None: - """ - 获取所有账号信息 - - 获取异常: - return None - - 获取成功: - return { - 'token_1': { - 'priority': '...', - 'working': ..., - 'remain': ..., - }, - 'token_2': { - ... - } - ... - } - """ - try: - userList = {} - for userId in redisObject.smembers(redisPrefix + 'users'): # 遍历全部账号 - userId = str(userId, encoding = 'utf-8') - userInfo = getUserInfo(userId) - userInfo.pop('token') - userList[userId] = userInfo # 记录账号信息 - return userList - except: - return None - -def modifyUserInfo(userId: str, priority: str = None, remain = None) -> bool: - """ - 修改账号信息 - - 修改成功: - return True - - 修改失败: - return False - """ - - try: - userInfo = getUserInfo(userId) - if userInfo is None: # 账号不存在 - return False - if priority is not None: # 优先级变动 - if priority not in ['a', 'b', 'c', 'd', 'e']: # 优先级无效 - return False - userInfo['priority'] = priority - if remain is not None: # 剩余次数变动 - remain = int(remain) - if remain < 0: - remain = -1 # 不限次数 - userInfo['remain'] = remain - redisObject.set( - redisPrefix + 'user-' + userId, # 记录账号信息 - json.dumps(userInfo) - ) - return True - except: - return False - -@api.route(apiPath + '/user', methods = ['GET', 'POST']) -def apiUser() -> dict: - if request.method == 'GET': # 获取账号列表 - if not isAdminToken(request.args.get('token')): # 非管理员token - return genError('invalid admin token') - userList = getUserList() - if userList is None: # 获取失败 - return genError('server error') - return genSuccess({ - 'user': userList - }) - elif request.method == 'POST': # 添加账号 - if not isAdminToken(httpPostArg('token')): # 非管理员token - return genError('invalid admin token') - priority = httpPostArg('priority') - if priority is None: - priority = 'c' # 默认优先级 - remain = httpPostArg('remain') - if remain is None: - remain = '-1' # 默认剩余次数 - status, userId = addUser(priority, remain) # 创建新账号 - if not status: - return genError(userId) # 创建错误 - return genSuccess({ - 'userId': userId # 创建成功 - }) - -@api.route(apiPath + '/user/', methods = ['GET', 'PUT', 'PATCH', 'DELETE']) -def apiUserId(userId: str) -> dict: - if request.method == 'GET': # 获取账号信息 - userInfo = getUserInfo(userId) - if userInfo is None: - return genError('invalid user id') - return genSuccess(userInfo) - elif request.method == 'PUT' or request.method == 'PATCH': # 更新账号信息 - if not isAdminToken(httpPostArg('token')): # 非管理员token - return genError('invalid admin token') - priority = httpPostArg('priority') - remain = httpPostArg('remain') - if request.method == 'PUT': - if priority is None or remain is None: # 参数不全 - return genError('missing parameter') - if not modifyUserInfo(userId, priority = priority, remain = remain): # 更新账号信息 - return genError('server error') - return genSuccess( - getUserInfo(userId) # 更新成功 - ) - elif request.method == 'DELETE': # 销毁账号 - if not isAdminToken(httpPostArg('token')): # 非管理员token - return genError('invalid admin token') - status, reason = delUser(userId) - if not status: - return genError(reason) - return genSuccess({ - 'userId': userId # 删除成功 - }) - -@api.route(apiPath + '/check', methods = ['GET', 'POST']) -def apiCheck() -> dict: - if request.method == 'GET': # 获取检测任务列表 - token = request.args.get('token') - if not isUserToken(token): - return genError('invalid user token') - taskList = getCheckList(token) - if taskList is None: - return genError('server error') - return genSuccess({ - 'taskList': taskList - }) - elif request.method == 'POST': # 添加检测任务 - token = httpPostArg('token') - if not isUserToken(token): - return genError('invalid user token') - checkList = httpPostArg('check') # 检测列表 - if checkList is None: - return genError('missing check list') - proxyList = httpPostArg('proxy') # 代理列表 - if proxyList is None: - return genError('missing proxy list') - priority = getUserInfo(token, minus = True)['priority'] # 获取账号优先级 - if priority is None: - return genError('server error') - return addCheckTask(checkList, proxyList, priority, token) - -@api.route(apiPath + '/check/', methods = ['GET', 'DELETE']) -def apiCheckId(checkId: str) -> dict: - if request.method == 'GET': # 获取检测任务状态 - return getTaskInfo(checkId) - elif request.method == 'DELETE': # 删除检测任务 - return deleteTask(checkId) - -redisObject = redis.StrictRedis( - db = 0, - host = redisHost, - port = redisPort -) -api.run(host = '0.0.0.0', port = 43581, debug = True) diff --git a/docker/init.sh b/docker/init.sh deleted file mode 100644 index 42d9b55..0000000 --- a/docker/init.sh +++ /dev/null @@ -1,8 +0,0 @@ -python /usr/local/share/ProxyC/docker/compile.py& -/usr/bin/redis-server /etc/redis.conf - -dnsproxy -p 53 -u 223.5.5.5 & -echo "nameserver 127.0.0.1" > /etc/resolv.conf - -python /usr/local/share/ProxyC/Loop.py& -python /usr/local/share/ProxyC/Web.py