parent
2cb0f1a8f5
commit
179f46b2b3
@ -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 |
@ -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 |
celery==5.1.0 |
||||||
aliyun-python-sdk-core-v3==2.13.11 |
django-celery-results==2.0.1 |
||||||
aliyun-python-sdk-kms==2.10.1 |
django-celery-beat==2.2.0 |
||||||
aliyun-python-sdk-sts==3.0.1 |
Django==3.2.3 |
||||||
androguard==3.3.5 |
djangorestframework==3.12.4 |
||||||
appdirs==1.4.4 |
django-simple-captcha==0.5.14 |
||||||
APScheduler==3.6.3 |
mysqlclient==2.0.3 |
||||||
asgiref==3.2.3 |
django-redis==4.12.1 |
||||||
asn1crypto==1.3.0 |
dnspython==2.1.0 |
||||||
backcall==0.1.0 |
oss2==2.14.0 |
||||||
bcrypt==3.1.7 |
aliyun-python-sdk-sts==3.0.2 |
||||||
biplist==1.0.3 |
qiniu==7.4.1 |
||||||
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 |
|
||||||
xmltodict==0.12.0 |
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…
Reference in new issue