更新Django版本,增加celery定时任务

pull/15/head
youngS 4 years ago
parent 2cb0f1a8f5
commit 179f46b2b3
  1. 40
      fir_ser/api/tasks.py
  2. 2
      fir_ser/api/utils/apple/appleapiv3.py
  3. 11
      fir_ser/api/utils/crontab/ctasks.py
  4. 90
      fir_ser/api/utils/crontab/run.py
  5. 53
      fir_ser/api/utils/crontab/runWin.py
  6. 130
      fir_ser/api/utils/decorators.py
  7. 6
      fir_ser/api/utils/pay/alipay/__init__.py
  8. 5
      fir_ser/api/utils/storage/caches.py
  9. 14
      fir_ser/api/utils/throttle.py
  10. 8
      fir_ser/api/views/__init__.py
  11. 2
      fir_ser/api/views/apps.py
  12. 6
      fir_ser/api/views/download.py
  13. 14
      fir_ser/api/views/uploads.py
  14. 2
      fir_ser/fir_ser/celery.py
  15. 46
      fir_ser/fir_ser/settings.py
  16. 276
      fir_ser/readme.txt
  17. 111
      fir_ser/requirements.txt

@ -6,9 +6,17 @@
from celery import shared_task
from django.core.cache import cache
from celery import Celery
from api.utils.storage.storage import get_local_storage
from api.models import Apps
from api.utils.app.supersignutils import IosUtils, resign_by_app_id
from api.utils.crontab.ctasks import sync_download_times, auto_clean_upload_tmp_file, auto_delete_tmp_file, \
auto_check_ios_developer_active
from api.utils.geetest.geetest_utils import check_bypass_status
app = Celery()
@shared_task
@ -41,3 +49,35 @@ 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)
@app.task
def start_api_sever_do_clean():
# 启动服务的时候,同时执行下面操作,主要是修改配置存储的时候,需要执行清理,否则会出问题,如果不修改,则无需执行
get_local_storage(clean_cache=True)
check_bypass_status()
@app.task
def sync_download_times_job():
sync_download_times()
@app.task
def check_bypass_status_job():
check_bypass_status()
@app.task
def auto_clean_upload_tmp_file_job():
auto_clean_upload_tmp_file()
@app.task
def auto_delete_tmp_file_job():
auto_delete_tmp_file()
@app.task
def auto_check_ios_developer_active_job():
auto_check_ios_developer_active()

@ -680,7 +680,7 @@ class AppStoreConnectApi(DevicesAPI, BundleIDsAPI, BundleIDsCapabilityAPI, Profi
}
jwt_encoded = jwt.encode(data, self.p8_private_key, algorithm=self.JWT_ALG, headers=jwt_headers)
headers = {
'Authorization': 'Bearer %s' % (jwt_encoded.decode('utf-8'))
'Authorization': 'Bearer %s' % jwt_encoded
}
self.headers = headers

@ -11,7 +11,6 @@ from api.utils.utils import send_ios_developer_active_status
from django.core.cache import cache
from fir_ser.settings import CACHE_KEY_TEMPLATE, SYNC_CACHE_TO_DATABASE, SUPER_SIGN_ROOT
import time, os
from django_apscheduler.models import DjangoJobExecution
import logging
logger = logging.getLogger(__file__)
@ -47,16 +46,6 @@ def auto_clean_upload_tmp_file():
logger.info("auto_clean_upload_tmp_file upload_tem_file_key :%s " % (upload_tem_file_key))
def auto_delete_job_log():
job_execution = DjangoJobExecution.objects.order_by("-id").values("id").first()
if job_execution:
need_count = SYNC_CACHE_TO_DATABASE.get("auto_clean_apscheduler_log", 10000)
max_id = job_execution.get("id")
count = DjangoJobExecution.objects.count()
if count > need_count:
DjangoJobExecution.objects.filter(id__lte=max_id - need_count).delete()
def auto_delete_tmp_file():
mobileconfig_tmp_dir = os.path.join(SUPER_SIGN_ROOT, 'tmp', 'mobileconfig')
for root, dirs, files in os.walk(mobileconfig_tmp_dir, topdown=False):

@ -1,90 +0,0 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 4月
# author: liuyu
# date: 2020/4/7
from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job
from fir_ser.settings import SYNC_CACHE_TO_DATABASE, GEETEST_CYCLE_TIME
from api.utils.crontab.ctasks import sync_download_times, auto_clean_upload_tmp_file, auto_delete_job_log, \
auto_delete_tmp_file, auto_check_ios_developer_active
import logging
from api.utils.storage.storage import get_local_storage
from api.utils.geetest.geetest_utils import check_bypass_status
logger = logging.getLogger(__file__)
import atexit
import fcntl
logging.basicConfig()
logging.getLogger('apscheduler').setLevel(logging.ERROR)
# 主要是为了防止多进程出现的多个定时任务同时执行
f = open("scheduler.lock", "wb")
try:
fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
# 开启定时工作
try:
# 实例化调度器
scheduler = BackgroundScheduler()
# 调度器使用DjangoJobStore()
scheduler.add_jobstore(DjangoJobStore(), "default")
# 另一种方式为每天固定时间执行任务,对应代码为:
# @register_job(scheduler, 'cron', day_of_week='mon-fri', hour='9', minute='30', second='10',id='task_time')
@register_job(scheduler, "interval", seconds=SYNC_CACHE_TO_DATABASE.get("download_times"))
def sync_download_times_job():
# 这里写你要执行的任务
sync_download_times()
@register_job(scheduler, "interval", seconds=GEETEST_CYCLE_TIME)
def check_bypass_status_job():
check_bypass_status()
@register_job(scheduler, "interval", seconds=SYNC_CACHE_TO_DATABASE.get("auto_clean_tmp_file_times"))
def auto_clean_upload_tmp_file_job():
auto_clean_upload_tmp_file()
auto_delete_job_log()
@register_job(scheduler, "interval", seconds=SYNC_CACHE_TO_DATABASE.get("auto_clean_local_tmp_file_times"))
def auto_delete_tmp_file_job():
auto_delete_tmp_file()
@register_job(scheduler, "interval",
seconds=SYNC_CACHE_TO_DATABASE.get("auto_check_ios_developer_active_times"))
def auto_check_ios_developer_active_job():
auto_check_ios_developer_active()
register_events(scheduler)
scheduler.start()
# 启动服务的时候,同时执行下面操作
get_local_storage(clean_cache=True)
check_bypass_status()
except Exception as e:
logger.error("scheduler failed,so shutdown it Exception:%s" % (e))
# 有错误就停止定时器
scheduler.shutdown()
except:
pass
def unlock():
fcntl.flock(f, fcntl.LOCK_UN)
f.close()
atexit.register(unlock)

@ -1,53 +0,0 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 4月
# author: liuyu
# date: 2020/4/7
from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job
from fir_ser.settings import SYNC_CACHE_TO_DATABASE
from api.utils.crontab.ctasks import sync_download_times
# import atexit
# import fcntl
#
# # 主要是为了防止多进程出现的多个定时任务同时执行
# f = open("scheduler.lock", "wb")
# try:
# fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
# 开启定时工作
try:
# 实例化调度器
scheduler = BackgroundScheduler()
# 调度器使用DjangoJobStore()
scheduler.add_jobstore(DjangoJobStore(), "default")
# 设置定时任务,选择方式为interval,时间间隔为10s
# 另一种方式为每天固定时间执行任务,对应代码为:
# @register_job(scheduler, 'cron', day_of_week='mon-fri', hour='9', minute='30', second='10',id='task_time')
@register_job(scheduler, "interval", seconds=SYNC_CACHE_TO_DATABASE.get("download_times"))
def sync_download_times_job():
# 这里写你要执行的任务
sync_download_times()
register_events(scheduler)
scheduler.start()
except Exception as e:
print(e)
# 有错误就停止定时器
scheduler.shutdown()
#
# except:
# pass
#
#
# def unlock():
# fcntl.flock(f, fcntl.LOCK_UN)
# f.close()
#
#
# atexit.register(unlock)

@ -0,0 +1,130 @@
from functools import wraps, WRAPPER_ASSIGNMENTS
from django.http.response import HttpResponse
def get_cache(alias):
from django.core.cache import caches
return caches[alias]
class CacheResponse:
"""
Store/Receive and return cached `HttpResponse` based on DRF response.
.. note::
This decorator will render and discard the original DRF response in
favor of Django's `HttpResponse`. The allows the cache to retain a
smaller memory footprint and eliminates the need to re-render
responses on each request. Furthermore it eliminates the risk for users
to unknowingly cache whole Serializers and QuerySets.
"""
def __init__(self,
timeout=None,
key_func=None,
cache=None,
cache_errors=None):
if timeout is None:
self.timeout = None
else:
self.timeout = timeout
if key_func is None:
self.key_func = ''
else:
self.key_func = key_func
if cache_errors is None:
self.cache_errors = True
else:
self.cache_errors = cache_errors
self.cache = get_cache(cache or 'default')
def __call__(self, func):
this = self
@wraps(func, assigned=WRAPPER_ASSIGNMENTS)
def inner(self, request, *args, **kwargs):
return this.process_cache_response(
view_instance=self,
view_method=func,
request=request,
args=args,
kwargs=kwargs,
)
return inner
def process_cache_response(self,
view_instance,
view_method,
request,
args,
kwargs):
key = self.calculate_key(
view_instance=view_instance,
view_method=view_method,
request=request,
args=args,
kwargs=kwargs
)
timeout = self.calculate_timeout(view_instance=view_instance)
response_triple = self.cache.get(key)
if not response_triple:
# render response to create and cache the content byte string
response = view_method(view_instance, request, *args, **kwargs)
response = view_instance.finalize_response(request, response, *args, **kwargs)
response.render()
if not response.status_code >= 400 or self.cache_errors:
# django 3.0 has not .items() method, django 3.2 has not ._headers
if hasattr(response, '_headers'):
headers = response._headers.copy()
else:
headers = {k: (k, v) for k, v in response.items()}
response_triple = (
response.rendered_content,
response.status_code,
headers
)
self.cache.set(key, response_triple, timeout)
else:
# build smaller Django HttpResponse
content, status, headers = response_triple
response = HttpResponse(content=content, status=status)
for k, v in headers.values():
response[k] = v
if not hasattr(response, '_closable_objects'):
response._closable_objects = []
return response
def calculate_key(self,
view_instance,
view_method,
request,
args,
kwargs):
if isinstance(self.key_func, str):
key_func = getattr(view_instance, self.key_func)
else:
key_func = self.key_func
return key_func(
view_instance=view_instance,
view_method=view_method,
request=request,
args=args,
kwargs=kwargs,
)
def calculate_timeout(self, view_instance, **_):
if isinstance(self.timeout, str):
self.timeout = getattr(view_instance, self.timeout)
return self.timeout
cache_response = CacheResponse

@ -11,9 +11,9 @@ from functools import partial
import hashlib
import OpenSSL
from Cryptodome.Hash import SHA, SHA256
from Cryptodome.PublicKey import RSA
from Cryptodome.Signature import PKCS1_v1_5
from Crypto.Hash import SHA, SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from .compat import decodebytes, encodebytes, quote_plus, urlopen
from .exceptions import AliPayException, AliPayValidationError

@ -148,7 +148,6 @@ def del_cache_response_by_short(app_id, udid=''):
def del_cache_response_by_short_util(short, app_id, udid):
logger.info("del_cache_response_by_short short:%s app_id:%s udid:%s" % (short, app_id, udid))
cache.delete("_".join([CACHE_KEY_TEMPLATE.get("download_short_key"), short]))
key = "_".join([CACHE_KEY_TEMPLATE.get("download_short_key"), short, '*'])
for app_download_key in cache.iter_keys(key):
cache.delete(app_download_key)
@ -427,8 +426,8 @@ def update_order_info(user_id, out_trade_no, payment_number, payment_type):
if not timezone.is_naive(now):
now = timezone.make_naive(now, timezone.utc)
order_obj.pay_time = now
order_obj.description = "充值成功,充值下载次数 %s ,现共可用次数 %s" % (
download_times, user_obj.download_times)
order_obj.description = "充值成功,充值下载次数 %s ,现共可用次数 %s" % (
download_times, user_obj.download_times + download_times)
order_obj.save()
add_user_download_times(user_id, download_times)
logger.info("%s 订单 %s msg:%s" % (user_obj, out_trade_no, order_obj.description))

@ -27,6 +27,20 @@ class InstallShortThrottle(SimpleRateThrottle):
return 'short_access_' + self.get_ident(request)
class InstallThrottle1(VisitShortThrottle):
"""短连接用户访问频率限制"""
scope = "InstallAccess1"
def get_cache_key(self, request, view):
return 'install_access_' + self.get_ident(request) + hashlib.md5(
request.META.get('HTTP_USER_AGENT', '').encode("utf-8")).hexdigest()
class InstallThrottle2(InstallThrottle1):
"""短连接用户访问频率限制"""
scope = "InstallAccess2"
class LoginUserThrottle(SimpleRateThrottle):
"""登录用户访问频率限制"""
scope = "LoginUser"

@ -3,11 +3,3 @@
# project: 10月
# author: liuyu
# date: 2020/10/12
import logging
logger = logging.getLogger(__file__)
try:
from api.utils.crontab import run
except Exception as e:
logger.error("import crontab.run failed Exception:%s" % (e))

@ -224,7 +224,7 @@ class AppInfoView(APIView):
if do_sign_flag == 1:
c_task = run_resign_task.apply_async((apps_obj.app_id, True))
if do_sign_flag == 2:
c_task = run_resign_task.apply_async((apps_obj.app_id, False)).get(propagate=False)
c_task = run_resign_task.apply_async((apps_obj.app_id, False))
if c_task:
c_task.get(propagate=False)
if c_task.successful():

@ -15,13 +15,13 @@ 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_app_permission
import os
from rest_framework_extensions.cache.decorators import cache_response
from api.utils.decorators import cache_response # 本来使用的是 drf-extensions==0.7.0 但是还未支持该版本Django
from api.utils.serializer import AppsShortSerializer
from api.models import Apps, AppReleaseInfo, APPToDeveloper, APPSuperSignUsedInfo
from django.http import FileResponse
import logging
from api.utils.baseutils import get_profile_full_path, get_app_domain_name
from api.utils.throttle import VisitShortThrottle, InstallShortThrottle
from api.utils.throttle import VisitShortThrottle, InstallShortThrottle, InstallThrottle1, InstallThrottle2
logger = logging.getLogger(__file__)
@ -185,7 +185,7 @@ class ShortDownloadView(APIView):
class InstallView(APIView):
throttle_classes = [VisitShortThrottle, InstallShortThrottle]
throttle_classes = [InstallThrottle1, InstallThrottle2]
'''
安装操作前端通过token 认证认证成功之后返回 下载连接并且 让下载次数加一
'''

@ -65,17 +65,8 @@ class AppAnalyseView(APIView):
png_key = png_id + '.png' + settings.FILE_UPLOAD_TMP_KEY
storage = Storage(request.user)
storage_type = storage.get_storage_type()
if storage_type == 1:
upload_token = storage.get_upload_token(upload_key)
png_token = storage.get_upload_token(png_key)
elif storage_type == 2:
upload_token = storage.get_upload_token(upload_key)
png_token = storage.get_upload_token(png_key)
else:
upload_token = storage.get_upload_token(upload_key)
png_token = storage.get_upload_token(png_key)
upload_token = storage.get_upload_token(upload_key)
png_token = storage.get_upload_token(png_key)
upload_file_tmp_name("set", png_key, request.user.id)
upload_file_tmp_name("set", upload_key, request.user.id)
res.data = {"app_uuid": app_uuid, "short": short,
@ -130,7 +121,6 @@ class AppAnalyseView(APIView):
if app_info:
if app_info.issupersign and app_info.user_id.supersign_active:
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:

@ -8,6 +8,8 @@ import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
from fir_ser.settings import SYNC_CACHE_TO_DATABASE, GEETEST_CYCLE_TIME
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fir_ser.settings')
app = Celery('fir_ser')

@ -37,7 +37,6 @@ INSTALLED_APPS = [
'django.contrib.messages',
'django.contrib.staticfiles',
'api.apps.ApiConfig',
'django_apscheduler', # 定时执行任务
'rest_framework',
'captcha',
'django_celery_beat',
@ -131,6 +130,8 @@ REST_FRAMEWORK = {
'RegisterUser2': '300/h',
'GetAuthC1': '60/m',
'GetAuthC2': '300/h',
'InstallAccess1': '10/m',
'InstallAccess2': '20/h',
}
}
# Internationalization
@ -146,6 +147,8 @@ USE_L10N = True
USE_TZ = False
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
@ -527,8 +530,6 @@ CELERY_BROKER_URL = 'redis://:%s@%s/2' % (
#: 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 # 任务结果过期时间
@ -540,9 +541,44 @@ CELERYD_MAX_TASKS_PER_CHILD = 200 # 每个worker执行了多少任务就会死
# CELERYD_WORKER_PREFETCH_MULTIPLIER =1
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_ENABLE_UTC = False
DJANGO_CELERY_BEAT_TZ_AWARE = False
CELERY_TIMEZONE = TIME_ZONE
CELERY_TASK_TRACK_STARTED = True
CELERY_TASK_TIME_LIMIT = 30 * 60
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_BEAT_SCHEDULE = {
'sync_download_times_job': {
'task': 'api.tasks.sync_download_times_job',
'schedule': SYNC_CACHE_TO_DATABASE.get("download_times"),
'args': ()
},
'check_bypass_status_job': {
'task': 'api.tasks.check_bypass_status_job',
'schedule': GEETEST_CYCLE_TIME,
'args': ()
},
'auto_clean_upload_tmp_file_job': {
'task': 'api.tasks.auto_clean_upload_tmp_file_job',
'schedule': SYNC_CACHE_TO_DATABASE.get("auto_clean_tmp_file_times"),
'args': ()
},
'auto_delete_tmp_file_job': {
'task': 'api.tasks.auto_delete_tmp_file_job',
'schedule': SYNC_CACHE_TO_DATABASE.get("auto_clean_local_tmp_file_times"),
'args': ()
},
'auto_check_ios_developer_active_job': {
'task': 'api.tasks.auto_check_ios_developer_active_job',
'schedule': SYNC_CACHE_TO_DATABASE.get("auto_check_ios_developer_active_times"),
'args': ()
},
'start_api_sever_do_clean': {
'task': 'api.tasks.start_api_sever_do_clean',
'schedule': 6,
'args': (),
'one_off': True
},
}

@ -0,0 +1,276 @@
导入默认数据
python manage.py dumpdata api.Price api.DomainCnameInfo > dumpdata.json
python manage.py loaddata dumpdata.json
#启动超级签工作者
#celery -A fir_ser worker --scheduler django --loglevel=debug
启动多节点
celery multi start 4 -A fir_ser -l INFO -c4 --pidfile=/var/run/celery/%n.pid --logfile=logs/%p.log
启动beat
celery -A fir_ser beat --scheduler django -l INFO
#开发测试
celery -A fir_ser worker --beat --scheduler django --loglevel=debug
var app_id = 21254;
var app_name = '';
var btnstr = '免费安装';
var udid= '';
var tipstr= '';
var btnstatus = '1';
var urlscheme = 'wxec1a63d7795bef19';
var android_url = '';
var geetest = JSON.parse('{}');
window.onload = function () {
Vue.use(VueAwesomeSwiper)
Vue.component(VueQrcode.name, VueQrcode)
const router = new VueRouter({
mode: 'history'
})
new Vue({
el: '#app',
router,
data: {
init: false,
message: 'Hello Vue.js!',
app_id: app_id,
udid: udid,
btnstr: btnstr,
tipstr: tipstr,
btnstatus: btnstatus,
app_name : app_name,
permissioncodedialog: false,
btndownloading: false,
showgosafari: false,
showgobrowser: false,
showsteptips: false,
showmchelp: false,
showios12help: false,
ismobile: false,
isandroid: false,
copyurl: 'text',
permissioncode: '',
urlscheme: urlscheme,
swiperOption: {
pagination: {
el: '.swiper-pagination'
}
},
swiper2option: {
scrollbar: '.imgs-box .swiper-scrollbar',
scrollbarHide: true,
slidesPerView: 'auto',
grabCursor: true
},
captchaObj: {}
},
mounted() {
var thats = this
if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mac|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
this.ismobile = true
this.isandroid = navigator.userAgent.indexOf('Android') > -1 || navigator.userAgent.indexOf('Adr') > -1;
}
this.copyurl = location.href
var copyBtn = new ClipboardJS('.gosafari .copy-url button');
copyBtn.on('success', function (e) {
thats.gosafari()
alert('链接复制成功,快去分享吧~');
});
var copyBtn = new ClipboardJS('.gobrowser .copy-url button');
copyBtn.on('success', function (e) {
thats.gobrowser()
alert('链接复制成功,快去分享吧~');
});
copyBtn.on('error', function (e) {
console.log(e);
});
document.getElementById('app').style.display = 'block';
if (this.$route.query.autorequest == 1) {
this.install()
}
if (this.$route.query.code) {
this.permissioncode = this.$route.query.code
}
thats.init = true
},
methods: {
getudid() {
let button = document.createElement('button');
let clipboard = new ClipboardJS(button, {
text: () => this.udid
})
clipboard.on('success', event => {
event.clearSelection();
weui.toast('复制成功');
});
clipboard.on('error', event => {
event.clearSelection();
weui.toast('复制失败');
});
weui.alert('如果出现无法安装等情况,请将下面的设备号复制一份发给我们!<br/><br/>当前设备:' + this.udid, {
className: "text-align-left",
buttons: [{
label: '复制设备号',
type: 'primary',
onClick: () => {
button.click()
}
}]
});
},
gosafari() {
this.showgosafari = !this.showgosafari
},
gobrowser() {
this.showgobrowser = !this.showgobrowser
},
install() {
if (this.isandroid) {
if(this.isWeChat()) {
this.gobrowser()
} else {
this.jsgotourl(android_url)
}
} else if (this.isiOSSafari()) {
if (this.btnstatus == 1) {
this.goinstall()
} else if (this.btnstatus == 2) {
this.doinstall()
} else if (this.btnstatus == 4) {
this.jsgotourl(this.urlscheme + "://")
}
} else {
this.gosafari()
}
},
goinstall() {
this.jsgotourl('/Kirin/MobileConfig?app_id=' + this.app_id + '&code=' + this.permissioncode)
var str = navigator.userAgent.toLowerCase();
var ver = str.match(/os (.*?) like mac os/);
if (ver) {
ver = ver[1].replace(/_/g, ".")
}
if (ver && this.cpr_version(ver, "12.2") >= 0) {
var thats = this
setTimeout(function () {
thats.jsgotourl('/Kirin/MobileConfig/JumpToSetting')
}, 5000)
}
},
doinstall() {
var thats = this
axios.get('/Kirin/Download/Request?udid=' + this.udid + '&app_id=' + this.app_id + '&permissioncode=' + this.permissioncode).then(function(response){
if (response.data.errno == 2005) {
thats.permissioncodedialog = true
} else if (response.data.errno !== 0) {
thats.$message({
message: response.data.errmsg,
type: 'error'
});
} else {
thats.permissioncodedialog = false
location.href = response.data.data.plist_url
thats.getprocess(response.data.data.task_id)
}
})
},
getprocess(task_id) {
var thats = this
axios.get('/Kirin/Download/Process?task_id=' + task_id).then(function(response){
if(response.data.errno !== 0) {
thats.$message({
message: response.data.errmsg,
type: 'error'
});
} else {
if (response.data.data.status == 1) {
thats.getinstallprocess(response.data.data.installtime)
} else {
thats.btndownloading = true
thats.btnstr = "<span>下载中 " + response.data.data.process + "%</span><em style='width: " + response.data.data.process + "%'></em>"
setTimeout(function () {
thats.getprocess(task_id);
}, 1000)
}
}
})
},
getinstallprocess(installtime) {
var thats = this
thats.btnstr = "安装中"
thats.btndownloading = false
thats.btnstatus = 3
setTimeout(function () {
thats.btnstr = "请回到桌面查看"
}, 1000 * installtime)
},
gosteptips() {
this.showsteptips = !this.showsteptips
},
gomchelp() {
this.showmchelp = !this.showmchelp
},
jsgotourl(url) {
// 创建隐藏的可下载链接
var eleLink = document.createElement('a');
eleLink.style.display = 'none';
eleLink.href = url;
// 触发点击
document.body.appendChild(eleLink);
eleLink.click();
// 然后移除
document.body.removeChild(eleLink);
},
toNum(a) {
var a = a.toString();
//也可以这样写 var c=a.split(/\./);
var c = a.split('.');
var num_place = ["", "0", "00", "000", "0000"], r = num_place.reverse();
for (var i = 0; i < c.length; i++) {
var len = c[i].length;
c[i] = r[len] + c[i];
}
var res = c.join('');
return res;
},
cpr_version(a, b) {
var _a = this.toNum(a), _b = this.toNum(b);
if (_a == _b) return 0;
if (_a > _b) return 1;
if (_a < _b) return -1;
},
isiOSSafari() {
var userAgent = navigator.userAgent
return (/(iPad|iPhone|iPod|Mac)/gi).test(userAgent) &&
(/Safari/).test(userAgent) &&
!(/CriOS/).test(userAgent) &&
!(/FxiOS/).test(userAgent) &&
!(/OPiOS/).test(userAgent) &&
!(/mercury/).test(userAgent) &&
!(/UCBrowser/).test(userAgent) &&
!(/Baidu/).test(userAgent) &&
!(/MicroMessenger/).test(userAgent) &&
!(/QQ/i).test(userAgent)
},
isWeChat() {
var userAgent = navigator.userAgent
return (/MicroMessenger/).test(userAgent)
}
}
})
}

@ -1,96 +1,17 @@
aliyun-python-sdk-core==2.13.15
aliyun-python-sdk-core-v3==2.13.11
aliyun-python-sdk-kms==2.10.1
aliyun-python-sdk-sts==3.0.1
androguard==3.3.5
appdirs==1.4.4
APScheduler==3.6.3
asgiref==3.2.3
asn1crypto==1.3.0
backcall==0.1.0
bcrypt==3.1.7
biplist==1.0.3
certifi==2019.11.28
cffi==1.14.0
chardet==3.0.4
Click==7.0
codecov==2.1.11
colorama==0.4.3
construct==2.10.61
coverage==5.5
crcmod==1.7
cryptodemo==0.0.1
Cryptodome==1.0
cryptography==3.4.6
cycler==0.10.0
decorator==4.4.2
distlib==0.3.1
Django==3.0.3
django-apscheduler==0.3.0
django-qrcode==0.3
django-ranged-response==0.2.0
django-redis==4.11.0
django-rest-framework==0.1.0
django-simple-captcha==0.5.12
djangorestframework==3.11.0
dnspython==1.16.0
drf-extensions==0.6.0
filelock==3.0.12
future==0.18.2
idna==2.9
importlib-metadata==3.10.0
importlib-resources==5.1.2
ipython==7.13.0
ipython-genutils==0.2.0
jedi==0.16.0
jmespath==0.9.5
kiwisolver==1.1.0
lxml==4.5.0
matplotlib==3.2.0
memoizer==0.0.1
mock==2.0.0
mysqlclient==1.4.6
networkx==2.4
numpy==1.18.1
oss2==2.9.1
packaging==20.9
paramiko==2.7.1
parso==0.6.2
pbr==5.5.1
pexpect==4.8.0
pickleshare==0.7.5
Pillow==7.0.0
pluggy==0.13.1
prompt-toolkit==3.0.3
ptyprocess==0.6.0
py==1.10.0
pyasn1==0.4.8
pycparser==2.20
pycryptodome==3.10.1
pycryptodomex==3.9.4
pydot==1.4.1
Pygments==2.5.2
PyJWT==1.7.1
PyMySQL==0.9.3
PyNaCl==1.3.0
pyOpenSSL==20.0.1
pyparsing==2.4.6
python-dateutil==2.8.1
pytz==2019.3
qiniu==7.2.8
redis==3.4.1
requests==2.23.0
rsa==4.7.2
six==1.14.0
sqlparse==0.3.1
toml==0.10.2
tox==3.23.0
traitlets==4.3.3
typing-extensions==3.7.4.3
tzlocal==2.0.0
urllib3==1.25.8
uWSGI==2.0.18
virtualenv==20.4.3
wcwidth==0.1.8
celery==5.1.0
django-celery-results==2.0.1
django-celery-beat==2.2.0
Django==3.2.3
djangorestframework==3.12.4
django-simple-captcha==0.5.14
mysqlclient==2.0.3
django-redis==4.12.1
dnspython==2.1.0
oss2==2.14.0
aliyun-python-sdk-sts==3.0.2
qiniu==7.4.1
xmltodict==0.12.0
zipp==3.4.1
pyOpenSSL==20.0.1
paramiko==2.7.2
PyJWT==2.1.0
drf-extensions==0.7.0
Loading…
Cancel
Save