修改超级签名使用任务队列进行签名

dependabot/npm_and_yarn/fir_admin/dns-packet-1.3.4
youngS 4 years ago
parent 8b0fab87b5
commit 0df8cf68be
  1. 76
      fir_client/src/components/FirDownload.vue
  2. 68
      fir_client/src/components/ShortDownload.vue
  3. 11
      fir_client/src/restful/download.js
  4. 15
      fir_client/src/restful/index.js
  5. 11
      fir_ser/api/base_views.py
  6. 43
      fir_ser/api/tasks.py
  7. 3
      fir_ser/api/urls.py
  8. 53
      fir_ser/api/utils/app/supersignutils.py
  9. 5
      fir_ser/api/utils/pay/__init__.py
  10. 34
      fir_ser/api/utils/storage/caches.py
  11. 2
      fir_ser/api/utils/utils.py
  12. 48
      fir_ser/api/views/apps.py
  13. 22
      fir_ser/api/views/download.py
  14. 76
      fir_ser/api/views/receiveudids.py
  15. 8
      fir_ser/api/views/uploads.py
  16. 3
      fir_ser/fir_ser/__init__.py
  17. 43
      fir_ser/fir_ser/celery.py
  18. 41
      fir_ser/fir_ser/settings.py

@ -70,8 +70,8 @@
</el-button>
<button type="button" v-else-if="wrong">{{ msg }}</button>
<div v-else>
<div v-if="isdownload" style="margin-top: 20%;margin-bottom: 20%">
<div v-else style="margin-top: 20%;margin-bottom: 20%">
<div v-if="isdownload">
<div v-if="gomobile">
<button disabled="" class="loading"
style="min-width: 42px; width: 42px; padding: 21px 0; border-top-color: transparent; border-left-color: transparent;">
@ -94,7 +94,7 @@
</div>
</div>
<div v-else style="margin-top: 20%;margin-bottom: 20%">
<div v-else>
<div v-if="currentappinfo.need_password" style="margin:0 auto; width:166px">
<el-input prefix-icon="el-icon-lock" clearable
placeholder="请输入密码" v-model="password"
@ -250,7 +250,7 @@
<script>
import QRCode from 'qrcodejs2'
import {getdownloadurl, getShortAppinfo} from '@/restful'
import {getdownloadurl, getShortAppinfo, gettask} from '@/restful'
export default {
name: "FirDownload",
@ -301,6 +301,46 @@
clearTimeout(this.timer);
},
methods: {
show_err_msg(msg) {
this.msg = msg;
this.$message({
message: msg,
type: 'error',
duration: 0
});
},
loop_check_task() {
let c_count = 1;
// eslint-disable-next-line no-unused-vars
const loop_t = window.setInterval(res => {
gettask(data => {
c_count += 1;
if (c_count > 120) {
window.clearInterval(loop_t);
}
if (data.code === 1000) {
window.clearInterval(loop_t);
if (data.msg) {
this.show_err_msg(data.msg);
} else {
this.$message.success('签名完成,请点击下载安装');
this.wrong = false;
}
} else {
if (data.code === 1002) {
window.clearInterval(loop_t);
data.msg = '应用不存在'
}
if (data.msg) {
this.msg = data.msg + ' ○ ' + c_count;
}
}
}, {
"short": this.$route.params.short,
data: {"task_id": this.$route.query.task_id}
})
}, 3000)
},
jiaocheng(act) {
let signhelp = this.$refs.signhelp;
let bg = this.$refs.signhelp;
@ -316,24 +356,20 @@
gomobileaction() {
window.location.href = this.mobileprovision;
},
check_msg(callback) {
if (this.$route.query.msg && this.$route.query.udid) {
check_msg() {
if (this.$route.query.udid) {
if (this.$route.query.task_id) {
this.wrong = true;
this.msg = this.$route.query.msg;
this.$message({
message: this.msg,
type: 'error',
duration: 0
});
} else (
callback()
)
this.msg = '签名处理中,请耐心等待';
this.loop_check_task()
} else if (this.$route.query.msg) {
this.wrong = true;
this.show_err_msg(this.$route.query.msg);
}
}
},
download() {
if (this.currentappinfo.app_id) {
// eslint-disable-next-line no-unused-vars
this.check_msg(_ => {
this.isdownload = true;
getdownloadurl(res => {
if (res.code === 1000) {
@ -414,7 +450,6 @@
},
'app_id': this.currentappinfo.app_id
})
})
}
},
qrcode() {
@ -626,6 +661,9 @@
this.getDownloadTokenFun();
this.full_url = location.href;
this.qrcode();
if (this.agent !== '') {
this.check_msg();
}
}, filters: {
formatName: function (name) {
if (name) {

@ -91,8 +91,8 @@
</button>
<button type="button" v-else-if="wrong">{{ msg }}</button>
<div v-else>
<div v-if="isdownload" style="margin-top: 20%;margin-bottom: 20%">
<div v-else style="margin-top: 20%;margin-bottom: 20%">
<div v-if="isdownload">
<div v-if="gomobile">
<button disabled="" class="loading"
style="min-width: 42px; width: 42px; padding: 21px 0; border-top-color: transparent; border-left-color: transparent;">
@ -115,11 +115,11 @@
</div>
</div>
<div v-else style="margin-top: 20%;margin-bottom: 20%">
<div v-else>
<div v-if="currentappinfo.need_password" style="margin:0 auto; width:166px">
<input class="passwd" placeholder="请输入密码" v-model="password"/>
</div>
<br/>
<br v-if="currentappinfo.need_password"/>
<button @click="download">
<a :underline="false"> 下载安装 </a>
</button>
@ -247,7 +247,7 @@
<script>
import QRCode from 'qrcodejs2'
import {getdownloadurl, getShortAppinfo} from '@/restful/download'
import {getdownloadurl, getShortAppinfo, gettask} from '@/restful/download'
export default {
name: "ShortDownload",
@ -300,6 +300,41 @@
clearTimeout(this.timer);
},
methods: {
show_err_msg(msg) {
this.msg = msg;
alert(this.msg)
},
loop_check_task() {
let c_count = 1;
// eslint-disable-next-line no-unused-vars
const loop_t = window.setInterval(res => {
gettask(data => {
c_count += 1;
if (c_count > 120) {
window.clearInterval(loop_t);
}
if (data.code === 1000) {
window.clearInterval(loop_t);
if (data.msg) {
this.show_err_msg(data.msg);
} else {
this.wrong = false;
}
} else {
if (data.code === 1002) {
window.clearInterval(loop_t);
data.msg = '应用不存在'
}
if (data.msg) {
this.msg = data.msg + ' ○ ' + c_count;
}
}
}, {
"short": this.$route.params.short,
data: {"task_id": this.$route.query.task_id}
})
}, 3000)
},
jiaocheng(act) {
let signhelp = this.$refs.signhelp;
let bg = this.$refs.signhelp;
@ -315,19 +350,20 @@
gomobileaction() {
window.location.href = this.mobileprovision;
},
check_msg(callback) {
if (this.$route.query.msg && this.$route.query.udid) {
check_msg() {
if (this.$route.query.udid) {
if (this.$route.query.task_id) {
this.wrong = true;
this.msg = this.$route.query.msg;
alert(this.msg)
} else (
callback()
)
this.msg = '签名处理中,请耐心等待';
this.loop_check_task()
} else if (this.$route.query.msg) {
this.wrong = true;
this.show_err_msg(this.$route.query.msg);
}
}
},
download() {
if (this.currentappinfo.app_id) {
// eslint-disable-next-line no-unused-vars
this.check_msg(_ => {
this.isdownload = true;
getdownloadurl(res => {
if (res.code === 1000) {
@ -401,7 +437,6 @@
},
'app_id': this.currentappinfo.app_id
})
})
}
},
qrcode() {
@ -612,6 +647,9 @@
this.getDownloadTokenFun();
this.full_url = location.href;
this.qrcode();
if (this.agent !== '') {
this.check_msg();
}
}, filters: {
formatName: function (name) {
if (name) {

@ -86,3 +86,14 @@ export function getdownloadurl(callBack, params) {
},
);
}
/**获取签名任务状态 */
export function gettask(callBack, params) {
getData(
USERSEVER + '/task/' + params.short,
params.data,
data => {
callBack(data);
},
);
}

@ -555,3 +555,18 @@ export function domainFun(callBack, params, load = true) {
true
);
}
/**获取签名任务状态 */
export function gettask(callBack, params, load = true) {
getData(
'GET',
USERSEVER + '/task/' + params.short,
params.data,
data => {
callBack(data);
},
load,
true,
true
);
}

@ -4,23 +4,16 @@
# author: NinEveN
# date: 2021/4/13
from rest_framework.views import APIView
from api.utils.response import BaseResponse
from api.utils.auth import ExpiringTokenAuthentication
from rest_framework.response import Response
from django.db.models import Sum
from api.utils.app.supersignutils import IosUtils, resign_by_app_obj
from api.utils.app.supersignutils import IosUtils
from api.utils.storage.storage import Storage
from api.utils.storage.caches import del_cache_response_by_short, get_app_today_download_times, del_cache_by_delete_app, \
del_cache_storage
from api.models import Apps, AppReleaseInfo, APPToDeveloper, AppIOSDeveloperInfo, UserInfo, AppScreenShot, AppStorage
from api.utils.serializer import AppsSerializer, AppReleaseSerializer
from rest_framework.pagination import PageNumberPagination
import logging
from fir_ser.settings import SERVER_DOMAIN
from api.utils.utils import delete_local_files, delete_app_screenshots_files, change_storage_and_change_head_img, \
migrating_storage_data, clean_storage_data, check_storage_is_new_storage
from api.utils.baseutils import is_valid_domain
logger = logging.getLogger(__name__)

@ -0,0 +1,43 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 5月
# author: NinEveN
# date: 2021/5/27
from celery import shared_task
from django.core.cache import cache
from api.models import Apps
from api.utils.app.supersignutils import IosUtils, resign_by_app_id
@shared_task
def run_sign_task(format_udid_info, short):
app_info = Apps.objects.filter(short=short).first()
with cache.lock("%s_%s_%s" % ('task_sign', app_info.app_id, format_udid_info.get('udid')), timeout=60 * 10):
ios_obj = IosUtils(format_udid_info, app_info.user_id, app_info)
status, msg = ios_obj.sign()
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:
msg = ""
return msg
@shared_task
def run_resign_task(app_id, need_download_profile=True):
app_obj = Apps.objects.filter(app_id=app_id).first()
with cache.lock("%s_%s" % ('task_resign', app_id), timeout=60 * 60):
return resign_by_app_id(app_obj, need_download_profile)

@ -22,7 +22,7 @@ from api.views.apps import AppsView, AppInfoView, AppReleaseinfoView
from api.views.download import ShortDownloadView
from api.views.uploads import AppAnalyseView, UploadView
from api.views.storage import StorageView
from api.views.receiveudids import IosUDIDView
from api.views.receiveudids import IosUDIDView, TaskView
from api.views.order import PriceView, OrderView, PaySuccess
from api.views.supersign import DeveloperView, SuperSignUsedView, AppUDIDUsedView
from api.views.domain import DomainCnameView
@ -47,6 +47,7 @@ urlpatterns = [
re_path("^token", UserApiTokenView.as_view()),
re_path(r"^short/(?P<short>\w+)$", ShortDownloadView.as_view()),
re_path(r"^udid/(?P<short>\w+)$", IosUDIDView.as_view()),
re_path(r"^task/(?P<short>\w+)$", TaskView.as_view()),
re_path("^analyse$", AppAnalyseView.as_view()),
re_path("^supersign/developer$", DeveloperView.as_view()),
re_path("^supersign/devices$", SuperSignUsedView.as_view()),

@ -5,12 +5,14 @@
# date: 2020/3/6
import uuid, xmltodict, os, re, logging, time
from api.utils.response import BaseResponse
from fir_ser.settings import SUPER_SIGN_ROOT, MEDIA_ROOT, SERVER_DOMAIN, MOBILECONFIG_SIGN_SSL
from api.utils.app.iossignapi import ResignApp, AppDeveloperApiV2
from api.models import APPSuperSignUsedInfo, AppUDID, AppIOSDeveloperInfo, AppReleaseInfo, Apps, APPToDeveloper, \
UDIDsyncDeveloper, DeveloperAppID, DeveloperDevicesID
from api.utils.app.randomstrings import make_app_uuid, make_from_user_uuid
from api.utils.storage.caches import del_cache_response_by_short, send_msg_over_limit
from api.utils.storage.caches import del_cache_response_by_short, send_msg_over_limit, check_app_permission
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
from api.utils.baseutils import file_format_path, delete_app_profile_file, get_profile_full_path, get_user_domain_name, \
@ -32,7 +34,7 @@ def check_org_file(user_obj, org_file):
return download_files_form_oss(storage_obj, org_file)
def resign_by_app_obj(app_obj, need_download_profile=True):
def resign_by_app_id(app_obj, need_download_profile=True):
user_obj = app_obj.user_id
if app_obj.issupersign and user_obj.supersign_active:
for dappid_obj in DeveloperAppID.objects.filter(app_id=app_obj).all():
@ -40,10 +42,12 @@ def resign_by_app_obj(app_obj, need_download_profile=True):
developer_app_id = dappid_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):
IosUtils.modify_capability(developer_obj, app_obj, developer_app_id)
download_flag, result = IosUtils.exec_download_profile(app_obj, developer_obj, None, 2)
else:
download_flag = True
with cache.lock("%s_%s_%s" % ('run_sign', app_obj.app_id, developer_obj.issuer_id), timeout=60 * 10):
IosUtils.run_sign(user_obj, app_obj, developer_obj, download_flag, None, d_time, {}, True)
@ -362,11 +366,11 @@ class IosUtils(object):
properties_info)
if status:
logger.info("%s %s %s sign_ipa success" % (user_obj, developer_obj, app_obj))
return True
return True, result
else:
logger.error(
"%s %s %s sign_ipa failed ERROR:%s" % (user_obj, developer_obj, app_obj, result.get("err_info")))
return False
return False, result
@staticmethod
def update_sign_file_name(user_obj, app_obj, developer_obj, release_obj, random_file_name):
@ -384,14 +388,7 @@ class IosUtils(object):
storage_obj.upload_file(os.path.join(MEDIA_ROOT, random_file_name + ".ipa"))
def update_sign_data(self, random_file_name, release_obj):
newdata = {
"is_signed": True,
"binary_file": random_file_name
}
# 更新已经完成签名状态,设备消耗记录,和开发者已消耗数量
AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).update(**newdata)
def update_developer_used_data(self):
appsupersign_obj = APPSuperSignUsedInfo.objects.filter(udid__udid=self.udid_info.get('udid'),
developerid=self.developer_obj)
if appsupersign_obj.count() == 0:
@ -406,6 +403,15 @@ class IosUtils(object):
developerid=self.developer_obj,
udid=AppUDID.objects.filter(app_id=self.app_obj,
udid=self.udid_info.get('udid')).first())
def update_sign_data(self, random_file_name, release_obj):
newdata = {
"is_signed": True,
"binary_file": random_file_name
}
# 更新已经完成签名状态,设备消耗记录,和开发者已消耗数量
AppUDID.objects.filter(app_id=self.app_obj, udid=self.udid_info.get('udid')).update(**newdata)
# 更新新签名的ipa包
IosUtils.update_sign_file_name(self.user_obj, self.app_obj, self.developer_obj, release_obj, random_file_name)
@ -419,13 +425,16 @@ class IosUtils(object):
logger.info("app_id %s download profile success. time:%s" % (app_obj, start_time - d_time))
random_file_name = make_from_user_uuid(user_obj)
release_obj = AppReleaseInfo.objects.filter(app_id=app_obj, is_master=True).first()
if IosUtils.exec_sign(user_obj, app_obj, developer_obj, random_file_name, release_obj):
status, e_result = IosUtils.exec_sign(user_obj, app_obj, developer_obj, random_file_name, release_obj)
if status:
s_time1 = time.time()
logger.info("app_id %s exec sign ipa success. time:%s" % (app_obj, s_time1 - start_time))
if resign:
IosUtils.update_sign_file_name(user_obj, app_obj, developer_obj, release_obj, random_file_name)
else:
obj.update_sign_data(random_file_name, release_obj)
else:
return status, e_result
else:
msg = "app_id %s download profile failed. %s time:%s" % (app_obj, result, time.time() - start_time)
d_result['code'] = 1002
@ -438,6 +447,11 @@ class IosUtils(object):
return True, d_result
def sign(self, sign_try_attempts=3):
"""
:param sign_try_attempts:
:return: status, result
:des: 仅用于苹果设备发送设备udid签名使用
"""
d_result = {'code': 0, 'msg': 'success'}
state, used_num = check_app_sign_limit(self.app_obj)
if not state:
@ -447,9 +461,13 @@ class IosUtils(object):
logger.error(d_result)
return False, d_result
res = check_app_permission(self.app_obj, BaseResponse())
if res.code != 1000:
return False, {'code': res.code, 'msg': res.msg}
if not self.developer_obj:
msg = "udid %s app %s not exists apple developer" % (self.udid_info.get('udid'), self.app_obj)
d_result['code'] = 1001
d_result['code'] = 1005
d_result['msg'] = msg
logger.error(d_result)
return False, d_result
@ -473,7 +491,8 @@ class IosUtils(object):
logger.info(
"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, self.developer_obj)):
with cache.lock("%s_%s_%s" % ('download_profile', self.app_obj.app_id, self.developer_obj.issuer_id),
timeout=60):
download_flag, result = IosUtils.exec_download_profile(self.app_obj, self.developer_obj,
self.udid_info, sign_try_attempts)
if download_flag:
@ -507,7 +526,9 @@ class IosUtils(object):
developerid=self.developer_obj,
app_id=self.app_obj)
with cache.lock("%s_%s_%s" % ('run_sign', self.app_obj, self.developer_obj)):
self.update_developer_used_data()
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, start_time,
result)

@ -0,0 +1,5 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 5月
# author: NinEveN
# date: 2021/5/27

@ -333,8 +333,8 @@ def get_user_free_download_times(user_id, act='get', amount=1, auth_status=False
def consume_user_download_times(user_id, app_id, amount=1, auth_status=False):
with cache.lock("%s_%s" % ('consume_user_download_times', user_id)):
if get_user_free_download_times(user_id, 'get', amount, auth_status) > 0:
with cache.lock("%s_%s" % ('consume_user_download_times', user_id), timeout=10, blocking_timeout=6):
if get_user_free_download_times(user_id, 'get', amount, auth_status) - amount >= 0:
get_user_free_download_times(user_id, 'set', amount, auth_status)
else:
if not check_user_can_download(user_id):
@ -357,7 +357,7 @@ def enable_user_download(user_id):
def add_user_download_times(user_id, download_times=0):
with cache.lock("%s_%s" % ('consume_user_download_times', user_id)):
with cache.lock("%s_%s" % ('consume_user_download_times', user_id), timeout=10, blocking_timeout=6):
try:
UserInfo.objects.filter(pk=user_id).update(download_times=F('download_times') + download_times)
return enable_user_download(user_id)
@ -377,7 +377,9 @@ def get_user_cert_auth_status(user_id):
def check_user_has_all_download_times(app_obj):
user_id = app_obj.user_id_id
auth_status = get_user_cert_auth_status(user_id)
return get_user_free_download_times(user_id, auth_status=auth_status) > 0 or check_user_can_download(user_id)
d_count = get_app_d_count_by_app_id(app_obj.app_id)
return get_user_free_download_times(user_id, auth_status=auth_status) - d_count >= 0 or check_user_can_download(
user_id)
def user_auth_success(user_id):
@ -392,7 +394,7 @@ def user_auth_success(user_id):
def update_order_status(out_trade_no, status):
with cache.lock("%s_%s" % ('user_order_', out_trade_no)):
with cache.lock("%s_%s" % ('user_order_', out_trade_no), timeout=10, blocking_timeout=6):
order_obj = Order.objects.filter(order_number=out_trade_no).first()
if order_obj:
order_obj.status = status
@ -400,7 +402,7 @@ def update_order_status(out_trade_no, status):
def update_order_info(user_id, out_trade_no, payment_number, payment_type):
with cache.lock("%s_%s" % ('user_order_', out_trade_no)):
with cache.lock("%s_%s" % ('user_order_', out_trade_no), timeout=10, blocking_timeout=6):
try:
user_obj = UserInfo.objects.filter(pk=user_id).first()
order_obj = Order.objects.filter(user_id=user_obj, order_number=out_trade_no).first()
@ -434,3 +436,23 @@ def update_order_info(user_id, out_trade_no, payment_number, payment_type):
except Exception as e:
logger.error("%s download_times less then 0. Exception:%s" % (user_obj, e))
return False
def check_app_permission(app_obj, res):
if not app_obj:
res.code = 1003
res.msg = "该应用不存在"
if app_obj.status != 1:
res.code = 1004
res.msg = "该应用被封禁,无法下载安装"
if not check_user_has_all_download_times(app_obj):
res.code = 1009
res.msg = "可用下载额度不足,请联系开发者"
if not app_obj.isshow:
res.code = 1004
res.msg = "您没有权限访问该应用"
return res

@ -234,7 +234,7 @@ def migrating_storage_file_data(user_obj, filename, new_storage_obj, clean_old_d
def migrating_storage_data(user_obj, new_storage_obj, clean_old_data):
with cache.lock("%s_%s" % ('migrating_storage_data', user_obj.uid)):
with cache.lock("%s_%s" % ('migrating_storage_data', user_obj.uid), timeout=60 * 60 * 24):
auth_status = False
certification = getattr(user_obj, 'certification', None)

@ -5,20 +5,21 @@
# date: 2020/3/4
from rest_framework.views import APIView
from api.tasks import run_resign_task
from api.utils.response import BaseResponse
from api.utils.auth import ExpiringTokenAuthentication
from rest_framework.response import Response
from django.db.models import Sum
from api.utils.app.supersignutils import IosUtils, resign_by_app_obj
from api.utils.app.supersignutils import IosUtils
from api.utils.storage.storage import Storage
from api.utils.storage.caches import del_cache_response_by_short, get_app_today_download_times, del_cache_by_delete_app
from api.models import Apps, AppReleaseInfo, APPToDeveloper, AppIOSDeveloperInfo, UserInfo, AppScreenShot
from api.utils.serializer import AppsSerializer, AppReleaseSerializer
from rest_framework.pagination import PageNumberPagination
import logging
from fir_ser.settings import SERVER_DOMAIN
from api.utils.utils import delete_local_files, delete_app_screenshots_files
from api.utils.baseutils import is_valid_domain, get_user_domain_name, get_app_domain_name
from api.utils.baseutils import get_user_domain_name, get_app_domain_name
from api.base_views import app_delete
logger = logging.getLogger(__name__)
@ -142,7 +143,6 @@ class AppInfoView(APIView):
return Response(res.dict)
has_combo = data.get("has_combo", None)
# domain_name = data.get("domain_name", None)
if has_combo:
actions = has_combo.get("action", None)
hcombo_id = has_combo.get("hcombo_id", None)
@ -168,36 +168,6 @@ class AppInfoView(APIView):
logger.error("app_id:%s actions:%s hcombo_id:%s Exception:%s" % (app_id, actions, hcombo_id, e))
res.code = 1004
res.msg = "该应用已经关联"
# elif domain_name:
# apps_obj = Apps.objects.filter(user_id=request.user, app_id=app_id).first()
# logger.info("app_id:%s update old data:%s" % (app_id, apps_obj.__dict__))
# domain_name_list = domain_name.strip(' ').replace("http://", "").replace("https://", "").split("/")
# if len(domain_name_list) > 0:
# domain_name = domain_name_list[0]
# if len(domain_name) > 3 and is_valid_domain(domain_name):
# if domain_name == SERVER_DOMAIN.get("REDIRECT_UDID_DOMAIN").split("//")[1]:
# user_admin_obj = UserInfo.objects.filter(is_superuser=True, uid=request.user.uid).order_by(
# 'pk').first()
# if user_admin_obj:
# apps_obj.domain_name = domain_name
# else:
# res.code = 1004
# res.msg = "域名设置失败,请更换其他域名"
# return Response(res.dict)
# else:
# apps_obj.domain_name = domain_name
# else:
# res.code = 1004
# res.msg = "域名校验失败"
# return Response(res.dict)
#
# if domain_name == '':
# apps_obj.domain_name = None
# if not get_user_domain_name(request.user):
# apps_obj.wxeasytype = True
# apps_obj.save()
# del_cache_response_by_short(apps_obj.app_id)
# return Response(res.dict)
else:
try:
do_sign_flag = 0
@ -250,11 +220,15 @@ class AppInfoView(APIView):
logger.info("app_id:%s update new data:%s" % (app_id, apps_obj.__dict__))
apps_obj.save()
if apps_obj.issupersign:
c_task = None
if do_sign_flag == 1:
resign_by_app_obj(apps_obj)
c_task = run_resign_task.apply_async((apps_obj.app_id, True))
if do_sign_flag == 2:
resign_by_app_obj(apps_obj, need_download_profile=False)
c_task = run_resign_task.apply_async((apps_obj.app_id, False)).get(propagate=False)
if c_task:
c_task.get(propagate=False)
if c_task.successful():
c_task.forget()
del_cache_response_by_short(apps_obj.app_id)
except Exception as e:
logger.error("app_id:%s update Exception:%s" % (app_id, e))

@ -13,7 +13,7 @@ from api.utils.app.apputils import make_resigned
from api.utils.app.supersignutils import make_sign_udid_mobileconfig, get_post_udid_url, get_redirect_server_domain
from api.utils.storage.storage import Storage, get_local_storage
from api.utils.storage.caches import get_app_instance_by_cache, get_download_url_by_cache, set_app_download_by_cache, \
del_cache_response_by_short, consume_user_download_times, check_user_has_all_download_times
del_cache_response_by_short, consume_user_download_times, check_app_permission
import os
from rest_framework_extensions.cache.decorators import cache_response
from api.utils.serializer import AppsShortSerializer
@ -150,24 +150,8 @@ class ShortDownloadView(APIView):
release_id = request.query_params.get("release_id", None)
udid = request.query_params.get("udid", None)
app_obj = Apps.objects.filter(short=short).first()
if not app_obj:
res.code = 1003
res.msg = "该应用不存在"
return Response(res.dict)
if app_obj.status != 1:
res.code = 1004
res.msg = "该应用被封禁,无法下载安装"
return Response(res.dict)
if not check_user_has_all_download_times(app_obj):
res.code = 1009
res.msg = "可用下载额度不足,请联系开发者"
return Response(res.dict)
if not app_obj.isshow:
res.code = 1004
res.msg = "您没有权限访问该应用"
res = check_app_permission(app_obj, res)
if res.code != 1000:
return Response(res.dict)
if udid:

@ -8,9 +8,16 @@ from api.utils.app.supersignutils import udid_bytes_to_dict, get_redirect_server
from api.models import Apps
from django.views import View
from django.http import HttpResponsePermanentRedirect
from rest_framework.response import Response
from api.tasks import run_sign_task
from api.utils.response import BaseResponse
from api.utils.storage.caches import check_app_permission
from fir_ser.celery import app
import logging
from rest_framework.views import APIView
from api.utils.baseutils import get_app_domain_name
from celery.exceptions import TimeoutError
logger = logging.getLogger(__file__)
@ -22,37 +29,60 @@ class IosUDIDView(View):
format_udid_info = udid_bytes_to_dict(stream_f)
logger.info("short %s get new udid %s" % (short, format_udid_info))
server_domain = get_redirect_server_domain(request)
msg = {}
status = True
try:
if True:
app_info = Apps.objects.filter(short=short).first()
if app_info:
server_domain = get_redirect_server_domain(request, app_info.user_id, get_app_domain_name(app_info))
if app_info.issupersign and app_info.user_id.supersign_active:
ios_obj = IosUtils(format_udid_info, app_info.user_id, app_info)
status, msg = ios_obj.sign()
res = check_app_permission(app_info, BaseResponse())
if res.code != 1000:
msg = "&msg=%s" % res.msg
else:
c_task = run_sign_task.apply_async((format_udid_info, short))
task_id = c_task.id
logger.info("sign app %s task_id:%s" % (app_info, task_id))
try:
result = c_task.get(propagate=False, timeout=2)
except TimeoutError:
result = ''
if c_task.successful():
c_task.forget()
msg = "&msg=%s" % result
else:
msg = "&task_id=%s" % task_id
else:
return HttpResponsePermanentRedirect(
"%s/%s" % (server_domain, short))
else:
return HttpResponsePermanentRedirect(
"%s/%s" % (server_domain, short))
except Exception as e:
logger.error("short %s receive udid Exception:%s" % (short, e))
if not status:
code = msg.get("code")
if code == 0:
msg = ""
elif code == 1001:
msg = "账户余额不足"
elif code == 1002:
msg = "维护中"
elif code == 1003:
msg = "应用余额不足"
else:
msg = "内部错误,请联系管理员"
else:
msg = ""
# except Exception as e:
# logger.error("short %s receive udid Exception:%s" % (short, e))
return HttpResponsePermanentRedirect(
"%s/%s?udid=%s&msg=%s" % (server_domain, short, format_udid_info.get("udid"), msg))
"%s/%s?udid=%s%s" % (server_domain, short, format_udid_info.get("udid"), msg))
class TaskView(APIView):
def get(self, request, short):
res = BaseResponse()
task_id = request.query_params.get('task_id', None)
if task_id:
app_info = Apps.objects.filter(short=short).first()
if app_info:
result = app.AsyncResult(task_id)
logger.info("app %s sign task state %s AA %s" % (app_info, result.state, result.successful()))
if result.successful():
res.msg = result.get(propagate=False)
return Response(res.dict)
elif result.state in ['PENDING']:
res.msg = '签名队列中'
elif result.state in ['STARTED']:
res.msg = '正在签名中'
else:
res.msg = ''
res.code = 1001
return Response(res.dict)
res.code = 1002
return Response(res.dict)

@ -17,7 +17,8 @@ from api.utils.app.randomstrings import make_from_user_uuid
from rest_framework.response import Response
from fir_ser import settings
from api.utils.TokenManager import DownloadToken
from api.utils.app.supersignutils import resign_by_app_obj, get_redirect_server_domain
from api.utils.app.supersignutils import get_redirect_server_domain
from api.tasks import run_resign_task
import os, json, logging
logger = logging.getLogger(__file__)
@ -127,7 +128,10 @@ class AppAnalyseView(APIView):
app_info = Apps.objects.filter(bundle_id=data.get("bundleid")).first()
if app_info:
if app_info.issupersign and app_info.user_id.supersign_active:
resign_by_app_obj(app_info, need_download_profile=False)
c_task = run_resign_task.apply_async((app_info.app_id, False)).get(propagate=False)
c_task.get(propagate=False)
if c_task.successful():
c_task.forget()
else:
storage.delete_file(app_tmp_filename)
storage.delete_file(png_tmp_filename)

@ -0,0 +1,3 @@
from .celery import app as celery_app
__all__ = ('celery_app',)

@ -0,0 +1,43 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 5月
# author: NinEveN
# date: 2021/5/27
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fir_ser.settings')
app = Celery('fir_ser')
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')
# Load task modules from all registered Django apps.
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
'''
pip install django-celery-beat==1.1.0
export PYTHONOPTIMIZE=1
celery -A DevOps beat -l info -S django --logfile=./celery.beat.log
celery multi start b1 -A DevOps beat -l info -S django
export PYTHONOPTIMIZE=1
celery -O OPTIMIZATION -A DevOps worker -l debug
celery multi start w1 -O OPTIMIZATION -A DevOps worker -l info --logfile=./celery.worker.log
celery -A DevOps flower --port=5566
'''

@ -40,6 +40,8 @@ INSTALLED_APPS = [
'django_apscheduler', # 定时执行任务
'rest_framework',
'captcha',
'django_celery_beat',
'django_celery_results',
]
MIDDLEWARE = [
@ -163,7 +165,7 @@ AUTH_USER_MODEL = "api.UserInfo"
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100},
@ -507,3 +509,40 @@ bIX1aWjPxirQX9mzaL3oEQI=
}
}
]
# 结果存放到Django|redis
# CELERY_RESULT_BACKEND = 'django-db'
# CELERY_RESULT_BACKEND = 'django-cache'
# result_backend = 'redis://username:password@host:port/db'
# result_backend = 'redis://:password@host:port/db'
CELERY_RESULT_BACKEND = 'django-db'
# CELERY_RESULT_BACKEND = 'db+sqlite:///results.sqlite'
# broker redis|mq
DJANGO_DEFAULT_CACHES = CACHES['default']
CELERY_BROKER_URL = 'redis://:%s@%s/2' % (
DJANGO_DEFAULT_CACHES["OPTIONS"]["PASSWORD"], DJANGO_DEFAULT_CACHES["LOCATION"].split("/")[2])
# CELERY_BROKER_URL = 'amqp://guest@localhost//'
#: Only add pickle to this list if your broker is secured
CELERY_ENABLE_UTC = True
CELERYD_CONCURRENCY = 4 # worker并发数
CELERYD_FORCE_EXECV = True # 非常重要,有些情况下可以防止死
CELERY_TASK_RESULT_EXPIRES = 3600 # 任务结果过期时间
CELERY_DISABLE_RATE_LIMITS = True # 任务发出后,经过一段时间还未收到acknowledge , 就将任务重新交给其他worker执行
CELERYD_PREFETCH_MULTIPLIER = 3 # celery worker 每次去redis取任务的数量
CELERYD_MAX_TASKS_PER_CHILD = 200 # 每个worker执行了多少任务就会死掉,我建议数量可以大一些,比如200
# CELERYD_WORKER_PREFETCH_MULTIPLIER =1
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'

Loading…
Cancel
Save