From a2c5d1bd3f1851874fab53b5f16169f4aef9e1c5 Mon Sep 17 00:00:00 2001 From: youngS Date: Mon, 15 Nov 2021 18:07:13 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B6=85=E7=BA=A7=E7=AD=BE=E5=90=8D=E5=B9=B6?= =?UTF-8?q?=E5=8F=91=E4=BC=98=E5=8C=96=EF=BC=8C=E7=AD=BE=E5=90=8D=E4=BD=99?= =?UTF-8?q?=E9=A2=9D=E8=BF=98=E6=9C=AA=E9=99=90=E5=88=B6=EF=BC=8C=E4=B8=8B?= =?UTF-8?q?=E4=B8=AA=E7=89=88=E6=9C=AC=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fir_client/vue.config.js | 2 +- fir_ser/api/tasks.py | 37 +- fir_ser/api/utils/app/iossignapi.py | 111 +++-- fir_ser/api/utils/app/supersignutils.py | 521 ++++++++++++++---------- fir_ser/api/utils/baseutils.py | 5 +- fir_ser/api/utils/storage/caches.py | 28 ++ fir_ser/api/views/apps.py | 6 +- fir_ser/api/views/receiveudids.py | 37 +- fir_ser/api/views/uploads.py | 9 +- fir_ser/fir_ser/settings.py | 13 +- fir_ser/tests/postudid.py | 94 ++++- 11 files changed, 540 insertions(+), 323 deletions(-) diff --git a/fir_client/vue.config.js b/fir_client/vue.config.js index 68fa608..7edf959 100644 --- a/fir_client/vue.config.js +++ b/fir_client/vue.config.js @@ -82,7 +82,7 @@ if (page) { } } -const version='1.2.8'; +const version='1.3.1'; const pro_base_env = { baseUrl: 'https://flyapps.cn', diff --git a/fir_ser/api/tasks.py b/fir_ser/api/tasks.py index d780c44..17e3b7d 100644 --- a/fir_ser/api/tasks.py +++ b/fir_ser/api/tasks.py @@ -26,26 +26,25 @@ def run_sign_task(format_udid_info, short, client_ip): ios_obj = IosUtils(format_udid_info, app_obj.user_id, app_obj) if ios_obj.developer_obj is None: return '签名余额不足' - with cache.lock("%s_%s_%s" % ('run_sign_task', app_obj.app_id, ios_obj.developer_obj.issuer_id), timeout=60 * 10): - ios_obj.get_developer_auth() - status, msg = ios_obj.sign_ipa(client_ip) - if not status: - code = msg.get("code", -1) - if code == 0: - msg = "" - elif code == 1005: - msg = "签名余额不足" - elif code == 1002: - msg = "维护中" - elif code == 1003: - msg = "应用余额不足" - elif code in [1004, 1001, 1009]: - msg = msg.get('msg', '未知错误') - else: - msg = '系统内部错误' - else: + ios_obj.get_developer_auth() + status, msg = ios_obj.sign_ipa(client_ip) + if not status: + code = msg.get("code", -1) + if code == 0: msg = "" - return msg + elif code == 1005: + msg = "签名余额不足" + elif code == 1002: + msg = "维护中" + elif code == 1003: + msg = "应用余额不足" + elif code in [1004, 1001, 1009]: + msg = msg.get('msg', '未知错误') + else: + msg = '系统内部错误' + else: + msg = "" + return msg @shared_task diff --git a/fir_ser/api/utils/app/iossignapi.py b/fir_ser/api/utils/app/iossignapi.py index bdddb69..7a99ca1 100644 --- a/fir_ser/api/utils/app/iossignapi.py +++ b/fir_ser/api/utils/app/iossignapi.py @@ -295,54 +295,6 @@ class AppDeveloperApiV2(object): result['return_info'] = "%s" % e return False, result - def get_profile(self, app_obj, udid_info, provision_name, auth, developer_app_id, - device_id_list, profile_id, device_err_callback, app_id_err_callback): - result = {} - bundle_id = app_obj.bundle_id - app_id = app_obj.app_id - s_type = app_obj.supersign_type - try: - apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key) - if developer_app_id: - pass - else: - if s_type == 0: - bundle_obj = apple_obj.register_bundle_id(app_id, f"{bundle_id}.{self.issuer_id}.{app_id}") - else: - bundle_obj = apple_obj.register_bundle_id_enable_capability(app_id, - f"{bundle_id}.{self.issuer_id}.{app_id}", - s_type) - developer_app_id = bundle_obj.id - result['aid'] = developer_app_id - if udid_info: - device_udid = udid_info.get('udid') - device_name = udid_info.get('product') - device_obj = apple_obj.register_device(device_name, device_udid) - if device_obj: - result['did'] = device_obj.id - device_id_list.append(device_obj.id) - - profile_obj = apple_obj.create_profile(profile_id, developer_app_id, auth.get('cert_id'), - provision_name.split("/")[-1], - device_id_list) - if profile_obj: - result['profile_id'] = profile_obj.id - n = base64.b64decode(profile_obj.profileContent) - if not os.path.isdir(os.path.dirname(provision_name)): - os.makedirs(os.path.dirname(provision_name)) - with open(provision_name, 'wb') as f: - f.write(n) - return True, result - except Exception as e: - logger.error(f"app_id {app_obj.app_id} ios developer make profile Failed Exception:{e}") - result['return_info'] = "%s" % e - if "There are no current ios devices" in str(e): - device_err_callback() - if "There is no App ID with ID" in str(e): - app_id_err_callback() - - return False, result - def del_profile(self, profile_id, profile_name): result = {} try: @@ -354,7 +306,7 @@ class AppDeveloperApiV2(object): result['return_info'] = "%s" % e return False, result - def set_device_status(self, status, device_id, device_name, device_udid): + def set_device_status(self, status, device_id, device_name, device_udid, device_err_callback=None): result = {} try: apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key) @@ -368,6 +320,8 @@ class AppDeveloperApiV2(object): except Exception as e: logger.error("ios developer set devices status Failed Exception:%s" % e) result['return_info'] = "%s" % e + if device_err_callback and ("There are no current ios devices" in str(e) or "Device obj is None" in str(e)): + device_err_callback() return False, result def get_device(self): @@ -394,21 +348,66 @@ class AppDeveloperApiV2(object): result['return_info'] = "%s" % e return False, result - # 该方法未使用 - def create_app(self, bundle_id, app_id, s_type): + def create_app(self, bundle_id, app_id, s_type, app_id_err_callback=None): + if app_id_err_callback is None: + app_id_err_callback = [] result = {} try: + result = {} apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key) - bundle_obj = apple_obj.register_bundle_id_enable_capability(app_id, - f"{bundle_id}.{self.issuer_id}.{app_id}", - s_type) - developer_app_id = bundle_obj.id - result['aid'] = developer_app_id + if s_type == 0: + bundle_obj = apple_obj.register_bundle_id(app_id, f"{bundle_id}.{self.issuer_id}.{app_id}") + else: + bundle_obj = apple_obj.register_bundle_id_enable_capability(app_id, + f"{bundle_id}.{self.issuer_id}.{app_id}", + s_type) + result['aid'] = bundle_obj.id return True, result except Exception as e: logger.error("ios developer create app Failed Exception:%s" % e) result['return_info'] = "%s" % e + if app_id_err_callback and "There is no App ID with ID" in str(e): + for call_fun in app_id_err_callback: + call_fun() + return False, result + + def register_device(self, device_udid, device_name, device_err_callback=None): + result = {} + try: + apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key) + return True, apple_obj.register_device(device_name, device_udid) + except Exception as e: + logger.error("ios developer register device Failed Exception:%s" % e) + result['return_info'] = "%s" % e + if device_err_callback and "There are no current ios devices" in str(e): + device_err_callback() + return False, result + + def make_and_download_profile(self, app_obj, provision_name, auth, developer_app_id, device_id_list, profile_id, + app_id_err_callback=None): + if app_id_err_callback is None: + app_id_err_callback = [] + result = {} + try: + apple_obj = AppStoreConnectApi(self.issuer_id, self.private_key_id, self.p8key) + profile_obj = apple_obj.create_profile(profile_id, developer_app_id, auth.get('cert_id'), + provision_name.split("/")[-1], + device_id_list) + if profile_obj: + result['profile_id'] = profile_obj.id + n = base64.b64decode(profile_obj.profileContent) + if not os.path.isdir(os.path.dirname(provision_name)): + os.makedirs(os.path.dirname(provision_name)) + with open(provision_name, 'wb') as f: + f.write(n) + return True, result + except Exception as e: + logger.error(f"app_id {app_obj.app_id} ios developer make profile Failed Exception:{e}") + result['return_info'] = "%s" % e + if app_id_err_callback and "There is no App ID with ID" in str(e): + for call_fun in app_id_err_callback: + call_fun() return False, result def modify_capability(self, app_obj, developer_app_id): diff --git a/fir_ser/api/utils/app/supersignutils.py b/fir_ser/api/utils/app/supersignutils.py index da918ed..2751f99 100644 --- a/fir_ser/api/utils/app/supersignutils.py +++ b/fir_ser/api/utils/app/supersignutils.py @@ -9,6 +9,7 @@ import os import time import uuid import zipfile +from functools import wraps import xmltodict from django.core.cache import cache @@ -22,7 +23,7 @@ from api.utils.modelutils import get_ios_developer_public_num, check_ipa_is_late from api.utils.response import BaseResponse from api.utils.serializer import BillAppInfoSerializer, BillDeveloperInfoSerializer from api.utils.storage.caches import del_cache_response_by_short, send_msg_over_limit, check_app_permission, \ - consume_user_download_times_by_app_obj + consume_user_download_times_by_app_obj, add_udid_cache_queue, get_and_clean_udid_cache_queue from api.utils.storage.storage import Storage from api.utils.utils import delete_app_to_dev_and_file, send_ios_developer_active_status, delete_local_files, \ download_files_form_oss, get_developer_udided @@ -53,14 +54,18 @@ def resign_by_app_id(app_obj, need_download_profile=True, force=True): developer_app_id = developer_app_id_obj.aid d_time = time.time() if need_download_profile: - with cache.lock("%s_%s_%s" % ('download_profile', app_obj.app_id, developer_obj.issuer_id), timeout=60): + with cache.lock("%s_%s_%s" % ('make_and_download_profile', developer_obj.issuer_id, app_obj.app_id), + timeout=60): IosUtils.modify_capability(developer_obj, app_obj, developer_app_id) - download_flag, result = IosUtils.exec_download_profile(app_obj, developer_obj, None, 2) + status, download_profile_result = IosUtils.make_and_download_profile(app_obj, + developer_obj, + developer_app_id_obj) else: - download_flag = True + status = True with cache.lock("%s_%s_%s" % ('run_sign', app_obj.app_id, developer_obj.issuer_id), timeout=60 * 10): - status, result = IosUtils.run_sign(user_obj, app_obj, developer_obj, download_flag, '', d_time, {}) - info_list.append({'developer_id': developer_obj.issuer_id, 'result': (status, result)}) + if status: + status, result = IosUtils.run_sign(user_obj, app_obj, developer_obj, d_time, None, []) + info_list.append({'developer_id': developer_obj.issuer_id, 'result': (status, result)}) return info_list @@ -194,12 +199,50 @@ def get_apple_udid_key(auth): def err_callback(func, *args, **kwargs): + @wraps(func) def wrapper(): return func(*args, **kwargs) return wrapper +def disable_developer_and_send_email(app_obj, developer_obj): + logger.error(f"app {app_obj} developer {developer_obj} sign failed. so disabled") + developer_obj.is_actived = False + developer_obj.save(update_fields=['is_actived']) + send_ios_developer_active_status(developer_obj.user_id, + MSGTEMPLATE.get('ERROR_DEVELOPER') % ( + developer_obj.user_id.first_name, app_obj.name, + developer_obj.issuer_id)) + + +def call_function_try_attempts(try_attempts=3, sleep_time=2, failed_callback=None): + def decorator(func): + @wraps(func) + def wrapper(*args, **kwargs): + res = False, {} + start_time = time.time() + for i in range(try_attempts): + res = func(*args, **kwargs) + status, result = res + if status: + return res + else: + logger.warning(f'exec {func} failed. {try_attempts} times in total. now {sleep_time} later try ' + f'again...{i}') + time.sleep(sleep_time) + if not res[0]: + logger.error(f'exec {func} failed after the maximum number of attempts. Failed:{res[1]}') + if failed_callback: + failed_callback() + logger.info(f"exec {func} finished. time:{time.time() - start_time}") + return res + + return wrapper + + return decorator + + def get_developer_user_by_app_udid(user_obj, udid): use_device_obj = APPSuperSignUsedInfo.objects.filter(udid__udid__udid=udid, user_id=user_obj, developerid__is_actived=True, @@ -296,73 +339,6 @@ class IosUtils(object): provision_name = os.path.join(cert_dir_path, self.app_obj.app_id) return provision_name + '.mobileprovision' - @staticmethod - def exec_download_profile(app_obj, developer_obj, udid_info, sign_try_attempts=3): - result = {} - developer_app_id = None - auth = get_auth_form_developer(developer_obj) - while sign_try_attempts > 0: - logger.info( - f"exec_download_profile app_id:{app_obj} developer:{developer_obj} sign_try_attempts:{sign_try_attempts}") - device_id_list = DeveloperDevicesID.objects.filter(app_id=app_obj, - developerid=developer_obj).values_list('did') - device_id_lists = [did[0] for did in device_id_list] - developer_app_id = None - profile_id = None - add_did_flag = False - sync_device_obj = None - developer_app_id_obj = DeveloperAppID.objects.filter(developerid=developer_obj, - app_id=app_obj).first() - if developer_app_id_obj: - developer_app_id = developer_app_id_obj.aid - profile_id = developer_app_id_obj.profile_id - if udid_info: - sync_device_obj = UDIDsyncDeveloper.objects.filter(udid=udid_info.get('udid'), - developerid=developer_obj, status=True).first() - if sync_device_obj: - DeveloperDevicesID.objects.update_or_create(did=sync_device_obj.serial, udid=sync_device_obj, - developerid=developer_obj, - app_id=app_obj) - - device_id_lists.append(sync_device_obj.serial) - udid_info = None - add_did_flag = True - logger.info(f"app {app_obj} device {sync_device_obj.serial} already in developer {developer_obj}") - - status, result = get_api_obj(auth).get_profile(app_obj, udid_info, - get_profile_full_path(developer_obj, app_obj), - auth, developer_app_id, device_id_lists, profile_id, - err_callback(IosUtils.get_device_from_developer, - developer_obj), - err_callback(IosUtils.clean_super_sign_things_by_app_obj, - app_obj, developer_obj)) - if add_did_flag and sync_device_obj: - result['did'] = sync_device_obj.serial - result['did_exists'] = True - if not status: - sign_try_attempts -= 1 - logger.warning(f"app {app_obj} developer {developer_obj} sign failed {result} .try again ") - time.sleep(3) - else: - sign_try_attempts = -1 - if sign_try_attempts != -1: - logger.error(f"app {app_obj} developer {developer_obj} sign failed {result}") - developer_obj.is_actived = False - developer_obj.save(update_fields=['is_actived']) - send_ios_developer_active_status(developer_obj.user_id, - MSGTEMPLATE.get('ERROR_DEVELOPER') % ( - developer_obj.user_id.first_name, app_obj.name, - developer_obj.issuer_id)) - return False, result - - if not developer_app_id and result.get("aid", None): - DeveloperAppID.objects.create(aid=result["aid"], developerid=developer_obj, app_id=app_obj) - if result.get("profile_id", None): - DeveloperAppID.objects.filter(developerid=developer_obj, app_id=app_obj).update( - profile_id=result.get("profile_id", None)) - - return True, result - @staticmethod def zip_cert(user_obj, developer_obj): auth = get_auth_form_developer(developer_obj) @@ -407,8 +383,8 @@ class IosUtils(object): return False, result @staticmethod - def update_sign_file_name(user_obj, app_obj, developer_obj, release_obj, random_file_name): - apptodev_obj = APPToDeveloper.objects.filter(developerid=developer_obj, app_id=app_obj).first() + def update_sign_file_name(user_obj, app_obj, developer_obj_id, release_obj, random_file_name): + apptodev_obj = APPToDeveloper.objects.filter(developerid_id=developer_obj_id, app_id=app_obj).first() storage_obj = Storage(user_obj) if apptodev_obj: delete_local_files(apptodev_obj.binary_file + ".ipa") @@ -421,76 +397,47 @@ class IosUtils(object): logger.warning(f"update sign file , now clean ole {old_release_file}.ipa file") delete_local_files(old_release_file + ".ipa") else: - APPToDeveloper.objects.create(developerid=developer_obj, app_id=app_obj, + APPToDeveloper.objects.create(developerid_id=developer_obj_id, app_id=app_obj, binary_file=random_file_name, release_file=release_obj.release_id) logger.info(f"update sign file end, now upload {storage_obj.storage} {random_file_name}.ipa file") return storage_obj.upload_file(os.path.join(MEDIA_ROOT, random_file_name + ".ipa")) - def update_developer_used_data(self, client_ip): - udid_obj = AppUDID.objects.filter(app_id=self.app_obj, udid__udid=self.udid, - udid__developerid=self.developer_obj).first() + @staticmethod + def update_developer_used_data(user_obj, app_obj, developer_obj, udid, client_ip): + udid_obj = AppUDID.objects.filter(app_id=app_obj, udid__udid=udid, + udid__developerid=developer_obj).first() udid_obj.is_download = True udid_obj.save(update_fields=['is_download']) - APPSuperSignUsedInfo.objects.update_or_create(app_id=self.app_obj, - user_id=self.user_obj, - developerid=self.developer_obj, + APPSuperSignUsedInfo.objects.update_or_create(app_id=app_obj, + user_id=user_obj, + developerid=developer_obj, udid=udid_obj) - udid_sync_info = UDIDsyncDeveloper.objects.filter(developerid=self.developer_obj, - udid=self.udid).first() - IosDeveloperPublicPoolBill.objects.update_or_create(user_id=self.user_obj, - app_info=BillAppInfoSerializer(self.app_obj).data, + udid_sync_info = UDIDsyncDeveloper.objects.filter(developerid=developer_obj, + udid=udid).first() + IosDeveloperPublicPoolBill.objects.update_or_create(user_id=user_obj, + app_info=BillAppInfoSerializer(app_obj).data, developer_info=BillDeveloperInfoSerializer( - self.developer_obj).data, + developer_obj).data, action=0, number=1, udid_sync_info=udid_sync_info, remote_addr=client_ip, product=udid_sync_info.product, - udid=self.udid, version=udid_sync_info.version, - app_id=self.app_obj + udid=udid, version=udid_sync_info.version, + app_id=app_obj ) @staticmethod - def update_sign_data(user_obj, app_obj, developer_obj, random_file_name, release_obj, udid): + def update_sign_data(user_obj, app_obj, developer_obj_id, random_file_name, release_obj, udid_list): # 更新新签名的ipa包 - if IosUtils.update_sign_file_name(user_obj, app_obj, developer_obj, release_obj, + if IosUtils.update_sign_file_name(user_obj, app_obj, developer_obj_id, release_obj, random_file_name): - if udid: - udid_obj = UDIDsyncDeveloper.objects.filter(developerid=developer_obj, udid=udid).first() - AppUDID.objects.filter(app_id=app_obj, udid=udid_obj).update(**{"is_signed": True}) - del_cache_response_by_short(app_obj.app_id, udid=udid) - return True - - @staticmethod - def run_sign(user_obj, app_obj, developer_obj, download_flag, udid, d_time, result): - d_result = {'code': 0, 'msg': 'success'} - start_time = time.time() - if download_flag: - logger.info(f"app_id {app_obj} download profile success. time:{start_time - d_time}") - random_file_name = make_from_user_uuid(developer_obj.user_id) - release_obj = AppReleaseInfo.objects.filter(app_id=app_obj, is_master=True).first() - status, e_result = IosUtils.exec_sign(developer_obj.user_id, app_obj, developer_obj, random_file_name, - release_obj) - if status: - s_time1 = time.time() - logger.info(f"app_id {app_obj} exec sign ipa success. time:{s_time1 - start_time}") - if not IosUtils.update_sign_data(user_obj, app_obj, developer_obj, random_file_name, release_obj, - udid): - d_result['code'] = 1004 - d_result['msg'] = '数据更新失败,请稍后重试' - return status, d_result + if udid_list: + for udid in udid_list: + udid_obj = UDIDsyncDeveloper.objects.filter(developerid_id=developer_obj_id, udid=udid).first() + AppUDID.objects.filter(app_id=app_obj, udid=udid_obj).update(**{"is_signed": True}) + del_cache_response_by_short(app_obj.app_id, udid=udid) else: - d_result['code'] = 1004 - d_result['msg'] = '签名失败,请检查包是否正常' - return status, d_result - else: - msg = f"app_id {app_obj} download profile failed. {result} time:{time.time() - start_time}" - d_result['code'] = 1002 - d_result['msg'] = msg - logger.error(d_result) - return False, d_result - msg = f"app_id {app_obj} developer {developer_obj} sign end... time:{time.time() - start_time}" - logger.info(msg) - d_result['msg'] = msg - return True, d_result + del_cache_response_by_short(app_obj.app_id) + return True def check_sign_permission(self): d_result = {'code': 0, 'msg': 'success'} @@ -514,16 +461,7 @@ class IosUtils(object): return False, d_result return True, d_result - def sign_ipa(self, client_ip, sign_try_attempts=3): - """ - :param client_ip: - :param sign_try_attempts: - :return: status, result - :des: 仅用于苹果设备发送设备udid签名使用 - """ - status, msg = self.check_sign_permission() - if not status: - return status, msg + def check_sign_is_exists(self, client_ip): d_result = {'code': 0, 'msg': 'success'} app_udid_obj = AppUDID.objects.filter(app_id=self.app_obj, udid__udid=self.udid, udid__developerid=self.developer_obj).first() @@ -543,9 +481,148 @@ class IosUtils(object): with cache.lock("%s_%s_%s" % ('run_sign', self.app_obj.app_id, self.developer_obj.issuer_id), timeout=60 * 10): logger.info("start run_sign ...") - return IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, 1, - self.udid, time.time(), - None) + return IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, + time.time(), client_ip, [self.udid]) + + @staticmethod + @call_function_try_attempts() + def check_or_register_devices(app_obj, developer_obj, udid_info): + """ + :param app_obj: + :param developer_obj: + :param udid_info: + :return: + """ + device_udid = udid_info.get('udid') + device_name = udid_info.get('product') + if not device_udid: + logger.error("device udid is not exists. so return and exit") + return True, 'continue' + sync_device_obj = UDIDsyncDeveloper.objects.filter(udid=device_udid, + developerid=developer_obj).first() + auth = get_auth_form_developer(developer_obj) + # 库里面存在,并且设备是可用状态,因此无需api注册 + if sync_device_obj: + logger.info(f"app {app_obj} device {sync_device_obj.serial} already in developer {developer_obj}") + if not sync_device_obj.status: + # 库里面存在,并且设备是禁用状态,需要调用api启用 + status, result = get_api_obj(auth).set_device_status("enable", sync_device_obj.serial, + sync_device_obj.product, sync_device_obj.udid, + err_callback(IosUtils.get_device_from_developer, + developer_obj)) + if not status: # 已经包含异常操作,暂定 + return status, result + sync_device_obj.status = True + sync_device_obj.save(update_fields=['status']) + else: + # 库里面不存在,注册设备,新设备注册默认就是启用状态 + status, device_obj = get_api_obj(auth).register_device(device_udid, device_name, + err_callback(IosUtils.get_device_from_developer, + developer_obj)) + if not status: + return status, device_obj + + device = { + "serial": device_obj.id, + "product": device_obj.name, + "udid": device_obj.udid, + "version": device_obj.model, + "status": True if device_obj.status == 'ENABLED' else False + } + sync_device_obj, _ = UDIDsyncDeveloper.objects.update_or_create(developerid=developer_obj, + udid=device_obj.udid, defaults=device) + + # 更新设备状态 + # 1. UDIDsyncDeveloper 库,通过udid 更新或创建设备信息 + # 2. DeveloperDevicesID 添加新应用-设备绑定信息数据 + # 3. AppUDID 添加数据,该数据主要是为了记录使用,is_signed 判断是否已经签名成功 + del udid_info['udid'] + udid_info['is_signed'] = False + udid_info['is_download'] = False + AppUDID.objects.update_or_create(app_id=app_obj, udid=sync_device_obj, + defaults=udid_info) + + DeveloperDevicesID.objects.update_or_create(did=sync_device_obj.serial, udid=sync_device_obj, + developerid=developer_obj, + app_id=app_obj) + return True, (sync_device_obj.serial, sync_device_obj.udid) + + @staticmethod + @call_function_try_attempts() + def check_or_add_new_bundles(app_obj, developer_obj, failed_callback=None): + if failed_callback is None: + failed_callback = [] + failed_callback.append(err_callback(IosUtils.clean_super_sign_things_by_app_obj, + app_obj, developer_obj)) + developer_app_id_obj = DeveloperAppID.objects.filter(developerid=developer_obj, + app_id=app_obj).first() + if not developer_app_id_obj: + auth = get_auth_form_developer(developer_obj) + bundle_id = app_obj.bundle_id + app_id = app_obj.app_id + s_type = app_obj.supersign_type + status, result = get_api_obj(auth).create_app(bundle_id, app_id, s_type, failed_callback) + if status and result.get('aid'): + developer_app_id_obj = DeveloperAppID.objects.create(aid=result.get('aid'), developerid=developer_obj, + app_id=app_obj) + else: + return status, result + + return True, developer_app_id_obj + + @staticmethod + @call_function_try_attempts() + def make_and_download_profile(app_obj, developer_obj, developer_app_id_obj=None, new_device_id_list=None, + failed_callback=None): + if new_device_id_list is None: + new_device_id_list = [] + + if failed_callback is None: + failed_callback = [] + failed_callback.append(err_callback(IosUtils.clean_super_sign_things_by_app_obj, + app_obj, developer_obj)) + device_id_list = DeveloperDevicesID.objects.filter(app_id=app_obj, + developerid=developer_obj).values_list('did') + device_id_lists = [did[0] for did in device_id_list] + if new_device_id_list: + device_id_lists.extend(new_device_id_list) + device_id_lists = list(set(device_id_lists)) + if not developer_app_id_obj: + developer_app_id_obj = DeveloperAppID.objects.filter(developerid=developer_obj, app_id=app_obj).first() + if not developer_app_id_obj: + logger.error("bundle id not found. so return and exit") + return True, 'continue' + developer_app_id = developer_app_id_obj.aid + profile_id = developer_app_id_obj.profile_id + auth = get_auth_form_developer(developer_obj) + status, result = get_api_obj(auth).make_and_download_profile(app_obj, + get_profile_full_path(developer_obj, app_obj), + auth, developer_app_id, + device_id_lists, profile_id, failed_callback) + + if not status: + return False, result + if result.get("profile_id", None): + DeveloperAppID.objects.filter(developerid=developer_obj, app_id=app_obj).update( + profile_id=result.get("profile_id", None)) + return True, True + + def sign_failed_fun(self, d_result, msg): + d_result['code'] = 1002 + d_result['msg'] = msg + logger.error(d_result) + disable_developer_and_send_email(self.app_obj, self.developer_obj) + self.get_developer_auth() + + def sign_ipa(self, client_ip): + status, msg = self.check_sign_permission() + if not status: + return status, msg + d_result = {'code': 0, 'msg': 'success'} + + result = self.check_sign_is_exists(client_ip) + if result: + return result logger.info("udid %s not exists app_id %s ,need sign" % (self.udid, self.app_obj)) @@ -556,79 +633,101 @@ class IosUtils(object): return False, d_result call_flag = True - download_flag = False - count = 1 - result = {} + count = 0 start_time = time.time() while call_flag: - logger.info( + count += 1 + if count > 3: + break + logger.warning( "call_loop download_profile appid:%s developer:%s count:%s" % (self.app_obj, self.developer_obj, count)) if self.developer_obj: - with cache.lock("%s_%s_%s" % ('download_profile', self.app_obj.app_id, self.developer_obj.issuer_id), - timeout=180): - - sync_device_obj = UDIDsyncDeveloper.objects.filter(udid=self.udid, - developerid=self.developer_obj, - status=True).first() - if sync_device_obj: - download_flag, result = IosUtils.exec_download_profile(self.app_obj, self.developer_obj, - self.udid_info, sign_try_attempts) + with cache.lock("%s_%s_%s" % ('check_or_register_devices', self.developer_obj.issuer_id, self.udid), + timeout=60): + status, did_udid_result = IosUtils.check_or_register_devices(self.app_obj, self.developer_obj, + self.udid_info) + if not status: + msg = f"app_id {self.app_obj} register devices failed. {did_udid_result}" + self.sign_failed_fun(d_result, msg) + continue + if status and 'continue' in [str(did_udid_result)]: + return True, True + with cache.lock("%s_%s_%s" % ( + 'check_or_add_new_bundles', self.developer_obj.issuer_id, self.app_obj.app_id), + timeout=60): + status, bundle_result = IosUtils.check_or_add_new_bundles(self.app_obj, self.developer_obj) + if not status: + msg = f"app_id {self.app_obj} create bundles failed. {bundle_result}" + self.sign_failed_fun(d_result, msg) + continue + prefix_key = f"{self.developer_obj.issuer_id}-{self.app_obj.app_id}" + if 'continue' not in [str(did_udid_result)]: + add_udid_cache_queue(prefix_key, did_udid_result) + + time.sleep(5) + with cache.lock("%s_%s_%s" % ( + 'make_and_download_profile', self.developer_obj.issuer_id, self.app_obj.app_id), + timeout=60 * 10): + did_udid_lists = get_and_clean_udid_cache_queue(prefix_key) + if not did_udid_lists: + return True, True + logger.warning( + f'app {self.app_obj} receive {len(did_udid_lists)} did_udid_result: {did_udid_lists}') + status, download_profile_result = IosUtils.make_and_download_profile(self.app_obj, + self.developer_obj, + new_device_id_list=[did_udid[0] + for + did_udid in + did_udid_lists]) + if not status: + msg = f"app_id {self.app_obj} download profile failed. {download_profile_result}" + self.sign_failed_fun(d_result, msg) + continue else: - with cache.lock("%s_%s_%s" % ( - 'download_profile_and_add_device', self.developer_obj.issuer_id, self.udid), - timeout=120): - download_flag, result = IosUtils.exec_download_profile(self.app_obj, self.developer_obj, - self.udid_info, sign_try_attempts) - if download_flag: - call_flag = False - else: - self.get_developer_auth() - else: - call_flag = False - count += 1 - if download_flag: - app_udid_obj = UDIDsyncDeveloper.objects.filter(developerid=self.developer_obj, - udid=self.udid) - udid_info = self.udid_info - del udid_info['udid'] - AppUDID.objects.update_or_create(app_id=self.app_obj, udid=app_udid_obj.first(), - defaults=udid_info) - if not result.get("did_exists", None): - app_udid_obj = app_udid_obj.filter(status=True).first() - if not app_udid_obj: - appudid_obj = AppUDID.objects.filter(app_id=self.app_obj, udid__udid=self.udid, - udid__developerid=self.developer_obj) - device = appudid_obj.values("serial", - 'product', - 'udid__udid', - 'version').first() - if result.get("did", None): - device['serial'] = result["did"] - device['status'] = True - app_udid_obj, _ = UDIDsyncDeveloper.objects.update_or_create(developerid=self.developer_obj, - udid=device['udid__udid'], - defaults=device) - DeveloperDevicesID.objects.create(did=result["did"], udid=app_udid_obj, - developerid=self.developer_obj, - app_id=self.app_obj) - else: - if result.get("did", None): - DeveloperDevicesID.objects.create(did=result["did"], udid=app_udid_obj, - developerid=self.developer_obj, - app_id=self.app_obj) - - self.update_developer_used_data(client_ip) + if 'continue' in [str(did_udid_result), str(download_profile_result)]: + return True, True + return IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, + start_time, client_ip, + [did_udid[1] for did_udid in did_udid_lists]) if not self.developer_obj: d_result['code'] = 1005 d_result['msg'] = '未找到可用苹果开发者' logger.error(d_result) return False, d_result - with cache.lock("%s_%s_%s" % ('run_sign', self.app_obj.app_id, self.developer_obj.issuer_id), timeout=60 * 10): - logger.info("start run_sign ...") - return IosUtils.run_sign(self.user_obj, self.app_obj, self.developer_obj, download_flag, - self.udid, start_time, - result) + return True, True + + @staticmethod + def run_sign(user_obj, app_obj, developer_obj, d_time, client_ip, udid_list=None): + if udid_list is None: + udid_list = [] + d_result = {'code': 0, 'msg': 'success'} + for udid in udid_list: + IosUtils.update_developer_used_data(user_obj, app_obj, developer_obj, udid, client_ip) + + start_time = time.time() + logger.info(f"app_id {app_obj} download profile success. time:{start_time - d_time}") + random_file_name = make_from_user_uuid(developer_obj.user_id.uid) + release_obj = AppReleaseInfo.objects.filter(app_id=app_obj, is_master=True).first() + status, e_result = IosUtils.exec_sign(developer_obj.user_id, app_obj, developer_obj, random_file_name, + release_obj) + if status: + s_time1 = time.time() + logger.info(f"app_id {app_obj} exec sign ipa success. time:{s_time1 - start_time}") + if not IosUtils.update_sign_data(user_obj, app_obj, developer_obj.pk, random_file_name, release_obj, + udid_list): + d_result['code'] = 1004 + d_result['msg'] = '数据更新失败,请稍后重试' + return status, d_result + else: + d_result['code'] = 1004 + d_result['msg'] = '签名失败,请检查包是否正常' + return status, d_result + + msg = f"app_id {app_obj} developer {developer_obj} sign end... time:{time.time() - start_time}" + logger.info(msg) + d_result['msg'] = msg + return True, d_result @staticmethod def disable_udid(udid_obj, app_id): @@ -699,18 +798,12 @@ class IosUtils(object): def clean_app_by_developer_obj(app_obj, developer_obj): auth = get_auth_form_developer(developer_obj) developer_app_id_obj = DeveloperAppID.objects.filter(developerid=developer_obj, app_id=app_obj).first() - identifier_id = None - profile_id = None if developer_app_id_obj: - identifier_id = developer_app_id_obj.aid - profile_id = developer_app_id_obj.profile_id - - app_api_obj = get_api_obj(auth) - app_api_obj.del_profile(profile_id, app_obj.app_id) - app_api_obj2 = get_api_obj(auth) - - app_api_obj2.del_app(identifier_id, app_obj.bundle_id, app_obj.app_id) - developer_app_id_obj.delete() + app_api_obj = get_api_obj(auth) + app_api_obj.del_profile(developer_app_id_obj.profile_id, app_obj.app_id) + app_api_obj2 = get_api_obj(auth) + app_api_obj2.del_app(developer_app_id_obj.aid, app_obj.bundle_id, app_obj.app_id) + developer_app_id_obj.delete() @staticmethod def clean_developer(developer_obj, user_obj, delete_file=True): diff --git a/fir_ser/api/utils/baseutils.py b/fir_ser/api/utils/baseutils.py index 37b7b19..f606a71 100644 --- a/fir_ser/api/utils/baseutils.py +++ b/fir_ser/api/utils/baseutils.py @@ -56,10 +56,9 @@ class AESCipher(object): return data -def make_from_user_uuid(userinfo): - user_id = userinfo.uid +def make_from_user_uuid(uid): random_str = uuid.uuid1().__str__().split("-")[0:-1] - user_ran_str = uuid.uuid5(uuid.NAMESPACE_DNS, user_id).__str__().split("-") + user_ran_str = uuid.uuid5(uuid.NAMESPACE_DNS, uid).__str__().split("-") user_ran_str.extend(random_str) new_str = "".join(user_ran_str) return new_str diff --git a/fir_ser/api/utils/storage/caches.py b/fir_ser/api/utils/storage/caches.py index 6f29beb..e9d7de1 100644 --- a/fir_ser/api/utils/storage/caches.py +++ b/fir_ser/api/utils/storage/caches.py @@ -528,6 +528,10 @@ class CleanSignDataState(CacheBaseState): ... +class CleanAppSignDataState(CacheBaseState): + ... + + def add_download_times_free_base(user_obj, amount, payment_name, description, order_type=1): order_number = get_order_num() order_obj = Order.objects.create(payment_type=2, order_number=order_number, payment_number=order_number, @@ -553,3 +557,27 @@ def admin_change_user_download_times(user_obj, amount=200): def auth_user_download_times_gift(user_obj, amount=200): description = '实名认证赠送下载次数 %s ,现共可用次数 %s' return add_download_times_free_base(user_obj, amount, '系统', description, 2) + + +def add_udid_cache_queue(prefix_key, values): + prefix_key = f"{CACHE_KEY_TEMPLATE.get('ipa_sign_udid_queue_key')}_{prefix_key}" + with cache.lock("%s_%s" % ('add_udid_cache_queue', prefix_key), timeout=10): + data = cache.get(prefix_key) + if data and isinstance(data, list): + data.append(values) + else: + data = [values] + cache.set(prefix_key, list(set(data)), 60 * 60) + return data + + +def get_and_clean_udid_cache_queue(prefix_key): + prefix_key = f"{CACHE_KEY_TEMPLATE.get('ipa_sign_udid_queue_key')}_{prefix_key}" + with cache.lock("%s_%s" % ('add_udid_cache_queue', prefix_key), timeout=10): + data = cache.get(prefix_key) + if data and isinstance(data, list): + ... + else: + data = [] + cache.delete(prefix_key) + return data diff --git a/fir_ser/api/views/apps.py b/fir_ser/api/views/apps.py index 62348f7..d9af31e 100644 --- a/fir_ser/api/views/apps.py +++ b/fir_ser/api/views/apps.py @@ -19,7 +19,8 @@ from api.utils.auth import ExpiringTokenAuthentication from api.utils.modelutils import get_user_domain_name, get_app_domain_name, check_super_sign_permission from api.utils.response import BaseResponse from api.utils.serializer import AppsSerializer, AppReleaseSerializer, AppsListSerializer -from api.utils.storage.caches import del_cache_response_by_short, get_app_today_download_times, del_cache_by_delete_app +from api.utils.storage.caches import del_cache_response_by_short, get_app_today_download_times, del_cache_by_delete_app, \ + CleanAppSignDataState from api.utils.storage.storage import Storage from api.utils.utils import delete_local_files, delete_app_screenshots_files @@ -138,8 +139,11 @@ class AppInfoView(APIView): clean = data.get("clean", None) if clean: logger.info(f"app_id:{app_id} clean:{clean} ,close super_sign should clean_app_by_user_obj") + CleanAppSignDataState.set_state(request.user.uid, timeout=60 * 10) app_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first() IosUtils.clean_app_by_user_obj(app_obj) + CleanAppSignDataState.del_state(request.user.uid) + return Response(res.dict) has_combo = data.get("has_combo", None) diff --git a/fir_ser/api/views/receiveudids.py b/fir_ser/api/views/receiveudids.py index 91333f4..c55d21c 100644 --- a/fir_ser/api/views/receiveudids.py +++ b/fir_ser/api/views/receiveudids.py @@ -22,9 +22,42 @@ from api.utils.throttle import ReceiveUdidThrottle1, ReceiveUdidThrottle2 from fir_ser.celery import app logger = logging.getLogger(__name__) +from rest_framework import exceptions -class IosUDIDView(View): +class UdidView(View): + throttle_classes = [] + + def check_throttles(self, request): + """ + Check if request should be throttled. + Raises an appropriate exception if the request is throttled. + """ + throttle_durations = [] + for throttle in [throttle() for throttle in self.throttle_classes]: + if not throttle.allow_request(request, self): + throttle_durations.append(throttle.wait()) + + if throttle_durations: + durations = [ + duration for duration in throttle_durations + if duration is not None + ] + + duration = max(durations, default=None) + raise exceptions.Throttled(duration) + + def dispatch(self, request, *args, **kwargs): + try: + self.check_throttles(request) + except Exception as e: + r_url = f"{get_redirect_server_domain(request)}/{kwargs.get('short')}?udid={str(e)}&msg=访问受限制,请稍后再试" + logger.error(f"ip:{get_real_ip_address(request)} short:{kwargs.get('short')} {str(e)}") + return HttpResponsePermanentRedirect(r_url) + return super().dispatch(request, *args, **kwargs) + + +class IosUDIDView(UdidView): throttle_classes = [ReceiveUdidThrottle1, ReceiveUdidThrottle2] def post(self, request, short): @@ -52,7 +85,7 @@ class IosUDIDView(View): task_id = c_task.id logger.info(f"sign app {app_obj} task_id:{task_id}") try: - result = c_task.get(propagate=False, timeout=2) + result = c_task.get(propagate=False, timeout=0.5) except TimeoutError: result = '' if c_task.successful(): diff --git a/fir_ser/api/views/uploads.py b/fir_ser/api/views/uploads.py index 7453002..8d7aaab 100644 --- a/fir_ser/api/views/uploads.py +++ b/fir_ser/api/views/uploads.py @@ -44,8 +44,9 @@ class AppAnalyseView(APIView): if app_type.lower() == 'iOS'.lower(): ap = 'ipa' app_uuid = make_app_uuid(request.user, bundle_id + ap) - release_id = make_from_user_uuid(request.user) - png_id = make_from_user_uuid(request.user) + uid = request.user.uid + release_id = make_from_user_uuid(uid) + png_id = make_from_user_uuid(uid) app_obj = Apps.objects.filter(app_id=app_uuid).first() binary_url = '' enable_sign = False @@ -189,7 +190,7 @@ class UploadView(APIView): else: if f_type and f_type == 'certification': storage = Storage(request.user, None, True) - upload_key = make_from_user_uuid(request.user) + '.' + app_type + settings.FILE_UPLOAD_TMP_KEY + upload_key = make_from_user_uuid(request.user.uid) + '.' + app_type + settings.FILE_UPLOAD_TMP_KEY upload_token = storage.get_upload_token(upload_key) storage_type = storage.get_storage_type() res.data = { @@ -269,7 +270,7 @@ class UploadView(APIView): res.msg = "错误的类型" return Response(res.dict) - random_file_name = make_from_user_uuid(request.user) + random_file_name = make_from_user_uuid(request.user.uid) local_file = os.path.join(settings.MEDIA_ROOT, cert_info.get("upload_key", random_file_name)) # 读取传入的文件 logger.info(f"user:{request.user} save file:{local_file}") diff --git a/fir_ser/fir_ser/settings.py b/fir_ser/fir_ser/settings.py index 755ec69..6bb85d2 100644 --- a/fir_ser/fir_ser/settings.py +++ b/fir_ser/fir_ser/settings.py @@ -215,6 +215,7 @@ CACHE_KEY_TEMPLATE = { 'super_sign_failed_send_msg_times_key': 'super_sign_failed_send_msg_times', 'wx_access_token_key': 'wx_basic_access_token', 'wx_ticket_info_key': 'wx_ticket_info', + 'ipa_sign_udid_queue_key': 'ipa_sign_udid_queue', } DATA_DOWNLOAD_KEY = "d_token" @@ -359,16 +360,14 @@ CELERY_BROKER_URL = 'redis://:%s@%s/2' % ( #: Only add pickle to this list if your broker is secured -CELERYD_CONCURRENCY = 10 # worker并发数 +CELERY_WORKER_CONCURRENCY = 30 # worker并发数 CELERYD_FORCE_EXECV = True # 非常重要,有些情况下可以防止死 -CELERY_TASK_RESULT_EXPIRES = 3600 # 任务结果过期时间 +CELERY_RESULT_EXPIRES = 3600 # 任务结果过期时间 -CELERY_DISABLE_RATE_LIMITS = True # 任务发出后,经过一段时间还未收到acknowledge , 就将任务重新交给其他worker执行 -CELERYD_PREFETCH_MULTIPLIER = 3 # celery worker 每次去redis取任务的数量 +CELERY_WORKER_DISABLE_RATE_LIMITS = True # 任务发出后,经过一段时间还未收到acknowledge , 就将任务重新交给其他worker执行 +CELERY_WORKER_PREFETCH_MULTIPLIER = 60 # celery worker 每次去redis取任务的数量 -CELERYD_MAX_TASKS_PER_CHILD = 200 # 每个worker执行了多少任务就会死掉,我建议数量可以大一些,比如200 - -# CELERYD_WORKER_PREFETCH_MULTIPLIER =1 +CELERY_WORKER_MAX_TASKS_PER_CHILD = 1000 # 每个worker执行了多少任务就会死掉,我建议数量可以大一些,比如200 CELERY_ENABLE_UTC = False DJANGO_CELERY_BEAT_TZ_AWARE = False diff --git a/fir_ser/tests/postudid.py b/fir_ser/tests/postudid.py index 8d360a9..3f04a18 100644 --- a/fir_ser/tests/postudid.py +++ b/fir_ser/tests/postudid.py @@ -1,16 +1,16 @@ import random +import time import requests udid_lists = [ - "75f14e4aee3dad37568a1a374f6c8b661b32d05e", "00008030-000C185C1143802E", "cadb0511abdb545d7eb7e828fd641a93e3164d02", - "efa8e5eb2a58fe65e303d1d9fad99d8b8670b6bb", "2525def0a63af76b8a09ea0dce0574d720925800", - "fdefbf544b7729db27c5294cd652e0dbb462cd22", "00008030-00122CD21A82402E", "e9f4cdc73fe24b1e20a4c33ae842d0d9ce6f8e34", + "75f14e4aee3dad37568a1a374f6c8b661b32d05e", "00008030-000C185C1143802E", + "efa8e5eb2a58fe65e303d1d9fad99d8b8670b6bb", "e9f4cdc73fe24b1e20a4c33ae842d0d9ce6f8e34", "cd84e936355f492ee68b7182f12ce3a7d0205557", "00008101-000B05E4368B001E", "f81a3a4170cf8e6c71d525464e175049134a6dbc", "6bae15671c8fe7096a40752071d87c6a837dd132", "7dd77d8cf13789e3f547f28ceb3e0c67b8694e37", "53e663905fcd81887abffc0d92e5c116ea2bfe5c", "00008101-001325EE1188001E", "f55df38afe5c1242b8bc478d0182bbd0d7d08929", "00008020-000951C40C12002E", "760862a7367dea986542dae17ee31cd139e454ad", "079d0e46eab5369184830d37cbed345f664e835a", - "00008030-000E6CC122D2402E", "00008101-0012758822A2001E", "00008020-00192CDE3A41002E", + "00008030-000E6CC122D2402E", "00008020-00192CDE3A41002E", "e2bcc2bdf73bf815bfde88becdeee05abdebf4d1", "000f0a85cf2d0b65b7a1fa21f143516500e040e0", "6dd86c12ab5506a1f7e45b0f58b6b1448f5cdf54", "49d8ca930a5610ba00190565ef756e24af97e63c", "ad4016d3749277b58f6294a9496ad97fa7c88110", "6a245252fb9cca583fc84413a092e73f7afc3182", @@ -24,7 +24,7 @@ udid_lists = [ "00008101-001661290169001E", "00008020-001B78E93461002E", "a84919cf236558b0f83496302237fd7f62a212a7", "00008101-0008093E3611001E", "00008110-00162C9A3C82801E", "638525bfd0ef1f029ed4c216f1430688093e5ac5", "00008030-000A51AE0EFA402E", "00008110-0016082C1E32801E", "00008030-001828411163802E", - "20737b4d60c2e0ff34e32edde224e64d042f72c1", "41d1b77e3a831f82a0ca306beaceeb955280b57a" + ] udid_lists2 = [ @@ -33,20 +33,19 @@ udid_lists2 = [ "00008020-00192CDE3A41002E", "00008101-001614893A42001E", "00008101-001449580100001E", - "00008101-0012758822A2001E", "019e2418ebf7bebbe82b42e4255b06f60f43fdda", "d3c7d88e66bb84b5b1b03fc70a12b568118464da", "f55df38afe5c1242b8bc478d0182bbd0d7d08929" ] short_list = [ - "wgvn", - "ynei", - "mecg", - "plzd", - "ibhp", - "zpus", - "ucwk" + "tiok", + "semi", + "lify", + "nyvr", + "uwdy", + "ceuj", + "bqpi" ] @@ -62,8 +61,71 @@ from concurrent.futures import ThreadPoolExecutor # postudid(udid="f55df38afe5c1242b8bc478d0182bbd0d7d08929") # exit() +# import oss2 + +# tokens = { +# "access_key_id": "STS.NUrQfSoT1hxZt953jpkzpAxrD", +# "access_key_secret": "3DYz3ZVLCYaCF7mU7BT5DPdRDmCqpW1sFUwr2T6obt3X", +# "bucket": "fly001-storage", +# "endpoint": "oss-cn-beijing.aliyuncs.com", +# "expiration": 1636451222, +# "request_id": "E792C7D3-051E-5D77-8439-5F596F525827", +# "security_token": "CAISpAN1q6Ft5B2yfSjIr5bHGtzngosQ37qxdh+E12olZ/Vcrr3Zpjz2IHxKfHJtBukfs/synWtY7P4elpUoRsBMGhbINccstZoKoAqoM9Gb6pPp4OwP2c2vSTSeUEGq1ZTYPL2nEIqBI670ZluUnyQoh6P8enO+WkT9hDVoQCYgPLotRQCdQWdsq740T1IQAaZ4WFLVMfGySDeI5kPbEEtvvCdllGp78t7R68aA6x3Y/hyYr+gOvNbJP4SDZcthN4sdI9Cux75ffK3bzAtN7wRL7K5skJFc/TDOsquAYT9r7g6BLvDf//B2MQZ9fdJaIaNfq+XmnvAKi47sno/smRFWJrMXAWaNSoSxmJOdXfi1Mcwweru8YHmS24/VOsH571gqPCMSPVMRIYt+dnIgAk18QGGGJ/T4qVmRaFj7FfTcjPhviJd+n1zjppySIVfJX7CB815BYcNlNxxyZ0JHhTOwLf9eSWEWLQM7XYTyZJ5ocRVTpZnvuQDvTSB6xhlVxaaiOauN5/9GMNigA8sdgdBFOI4lvW87Ck/rTKinhUoE+J+r/3PICMMagAGS1Fzpp9+iSHjA8FQ0GKWeLqGIewHIijtDrjVAlXMikLPUiFJfZB9b0bO/9fUuFj8cmVEwF3uGsMfuaAorJ8oQzRkeVz87B67W391gwlx92P1KRtppvUxv0ic7lJI6nlp0Spd4hhpe3m80KYKG1LpVl7ZJBg2f+4CJ71yJsVmlQg==" +# } +# +# auth = oss2.StsAuth(tokens.get('access_key_id'), tokens.get('access_key_secret'), tokens.get('security_token')) +# bucket_get = oss2.Bucket(auth, tokens.get('endpoint'), tokens.get('bucket')) +# bucket_get.copy_object(tokens.get('bucket'), '3e7a72d0d43f59aa832974e8c98b84e3a0b305fc2d7a11ec96de.jpg', 'xxxx.jpg') +# res = bucket_get +# print(res) +# exit(1) + +udid_test_s = [ + "f81a3a4170cf8e6c71d525464e175049134a6dbc", + "6bae15671c8fe7096a40752071d87c6a837dd132", + "7dd77d8cf13789e3f547f28ceb3e0c67b8694e37", + "53e663905fcd81887abffc0d92e5c116ea2bfe5c", + "00008101-001325EE1188001E", + "f55df38afe5c1242b8bc478d0182bbd0d7d08929", + "00008020-000951C40C12002E", + "760862a7367dea986542dae17ee31cd139e454ad", + "079d0e46eab5369184830d37cbed345f664e835a", + "00008030-000E6CC122D2402E" +] + + +# postudid(udid="760862a7367dea986542dae17ee31cd139e454ad", short='semi') +# exit() + + +def call_function_try_attempts(try_attempts=3): + def decorator(func): + def wrapper(*args, **kwargs): + for _ in range(try_attempts): + print('111111111111111111111111111111111111111111111111', _) + res = func(*args, **kwargs) + status, result = res + if status: + return res + time.sleep(1) + return res + + return wrapper + + return decorator + + +# @call_function_try_attempts() +# def aaaa(x,y): +# if random.randrange(1,10) == sum([x,y]): +# return True,True +# return False,False +# +# print(aaaa(4,2)) + if __name__ == '__main__': - for udid in udid_lists: - with ThreadPoolExecutor(max_workers=10) as executor: - future = executor.submit(postudid, random.choice(short_list), udid) + for i in range(9): + for udid in udid_test_s: + with ThreadPoolExecutor(max_workers=20) as executor: + future = executor.submit(postudid, random.choice(short_list), udid)