bugfix
This commit is contained in:
parent
7ba58a135c
commit
5630669c17
57
README.md
57
README.md
@ -0,0 +1,57 @@
|
|||||||
|
# DownloadMgr
|
||||||
|
a web ui for aria2
|
||||||
|
|
||||||
|
## Dependent
|
||||||
|
* [apppublic](https://git.opencomputing.cn/yumoqing/apppublic)
|
||||||
|
* [sqlor](https://git.opencomputing.cn/yumoqing/sqlor)
|
||||||
|
* [ahserver](https://git.opencomputing.cn/yumoqing/ahserver)
|
||||||
|
* [appbase](https://git.opencomputing.cn/yumoqing/appbase)
|
||||||
|
* [rbac](https://git.opencomputing.cn/yumoqing/rbac)
|
||||||
|
* [uapi](https://git.opencomputing.cn/yumoqing/uapi)
|
||||||
|
* [bricks](https://git.opencomputing.cn/yumoqing/bricks)
|
||||||
|
|
||||||
|
also depentent on
|
||||||
|
* [xls2ddl](https://git.opencomputing.cn/yumoqing/xls2ddl)
|
||||||
|
use it to translates database definintion excel file to database ddl sql file
|
||||||
|
and translate table information to CRUD UI for bricks.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
```
|
||||||
|
pip install git+https://git.opencomputing.cn/yumoqing/downloadmgr
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
in your web app
|
||||||
|
```
|
||||||
|
from downloadmgr.init import load_downloadmgr
|
||||||
|
# call the load_downloadmgr() before the web server start listening
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## examples:
|
||||||
|
```
|
||||||
|
from ahserver.webapp import webapp
|
||||||
|
from ahserver.serverenv import ServerEnv
|
||||||
|
from appbase.init import load_appbase
|
||||||
|
from rbac.init import load_rbac
|
||||||
|
from downloadmgr.init import load_downloadmgr
|
||||||
|
|
||||||
|
def get_module_dbanme(modulename):
|
||||||
|
return 'mydb' # assume all modules use same database 'mydb'
|
||||||
|
|
||||||
|
def init():
|
||||||
|
env = ServerEnv()
|
||||||
|
env.get_module_dbname = get_module_dbname
|
||||||
|
load_appbase()
|
||||||
|
load_rbac()
|
||||||
|
load_downloadmgr()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
webapp(init)
|
||||||
|
```
|
||||||
|
|
||||||
|
## database table
|
||||||
|
downloadmgr use a table named "download", it record the user download infomation
|
||||||
|
|
||||||
|
|
||||||
BIN
downloadmgr/.download.py.swp
Normal file
BIN
downloadmgr/.download.py.swp
Normal file
Binary file not shown.
0
downloadmgr/__init__.py
Normal file
0
downloadmgr/__init__.py
Normal file
106
downloadmgr/download.py
Normal file
106
downloadmgr/download.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import time
|
||||||
|
import json
|
||||||
|
from appPublic.dictObject import DictObject
|
||||||
|
from sqlor.dbpools import DBPools
|
||||||
|
from ahserver.serverenv import ServerEnv, get_serverenv
|
||||||
|
|
||||||
|
class DownloadMgr:
|
||||||
|
def __init__(self,request):
|
||||||
|
self.request = request
|
||||||
|
self.env = request['run_ns']
|
||||||
|
self.uapi = self.env.UAPI(request, **self.env)
|
||||||
|
self.uappid = 'downloader'
|
||||||
|
|
||||||
|
async def save_finished_task(self, taskid):
|
||||||
|
db = DBPools()
|
||||||
|
userid = await self.env.get_user()
|
||||||
|
dbname = self.env.get_module_dbname('downloadmgr')
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
ns = {
|
||||||
|
"id": taskid,
|
||||||
|
"finish_time": time.time(),
|
||||||
|
}
|
||||||
|
await sor.U('download', ns)
|
||||||
|
|
||||||
|
async def save_task(self, taskid):
|
||||||
|
db = DBPools()
|
||||||
|
userid = await self.env.get_user()
|
||||||
|
dbname = self.env.get_module_dbname('downloadmgr')
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
ns = {
|
||||||
|
"id": taskid,
|
||||||
|
"userid": userid,
|
||||||
|
"start_time": time.time()
|
||||||
|
}
|
||||||
|
await sor.C('download', ns)
|
||||||
|
|
||||||
|
async def get_user_tasks(self):
|
||||||
|
db = DBPools()
|
||||||
|
userid = await self.env.get_user()
|
||||||
|
dbname = self.env.get_module_dbname('downloadmgr')
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
sql = """select * from download
|
||||||
|
where userid=${userid}$
|
||||||
|
and finish_time is NULL"""
|
||||||
|
ns = {
|
||||||
|
'userid': userid
|
||||||
|
}
|
||||||
|
recs = await sor.sqlExe(sql, ns)
|
||||||
|
return recs
|
||||||
|
return []
|
||||||
|
|
||||||
|
async def uapicall(self, apiname, ns):
|
||||||
|
userid = await self.env.get_user()
|
||||||
|
x = self.uapi.call(self.uappname,
|
||||||
|
apiname,
|
||||||
|
userid,
|
||||||
|
ns)
|
||||||
|
d = json.loads(x.decode('utf-8')
|
||||||
|
return DictObject(**d)
|
||||||
|
|
||||||
|
async download(self, url):
|
||||||
|
try:
|
||||||
|
d = await self.uapicall('addUrl', {'url':url})
|
||||||
|
await self.save_task(d.result)
|
||||||
|
return d.result
|
||||||
|
except Exception as e:
|
||||||
|
self.env.exception(f'{url=},{e}\n{format_exc()}')
|
||||||
|
raise e
|
||||||
|
|
||||||
|
async def delete_file(self, filename):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async remove_task(self, taskid):
|
||||||
|
await self.uapicall('remove-task', {'taskid':taskid})
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def file_downloaded(self, filename):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def check_download_finished(self, status):
|
||||||
|
s = status
|
||||||
|
if s.totalLength == s.completedLength:
|
||||||
|
await self.save_finished_task(s.gid)
|
||||||
|
await self.file_downloaded(s.info.name)
|
||||||
|
await self.remove_task(s.gid)
|
||||||
|
await self.delete_file(s.info.name)
|
||||||
|
|
||||||
|
async def get_task_status(self, tid):
|
||||||
|
d = await self.uapicall('get_task_status', {'taskid':tid})
|
||||||
|
await self.check_downlaod_finished(d.result)
|
||||||
|
rzt = d.result
|
||||||
|
rzt.filename = rzt.info.name
|
||||||
|
return rzt
|
||||||
|
|
||||||
|
async get_tasks_status(self):
|
||||||
|
recs = await self.get_user_tasks(userid)
|
||||||
|
urls = [r.id for r in recs]
|
||||||
|
try:
|
||||||
|
d = await self.uapicall('get_task_status', {'taskid':tid})
|
||||||
|
await self.check_downlaod_finished(d.result)
|
||||||
|
return d.result
|
||||||
|
except Exception as e:
|
||||||
|
self.env.exception(f'{e=}\n{format_exc()}')
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
6
downloadmgr/init.py
Normal file
6
downloadmgr/init.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from downloadmgr.download import DownloadMgr
|
||||||
|
from ahserver.serverenv import ServerEnv
|
||||||
|
|
||||||
|
def load_downloadmgr():
|
||||||
|
env = ServerEnv()
|
||||||
|
env.DownloadMgr = DownloadMgr
|
||||||
BIN
models/download.xlsx
Normal file
BIN
models/download.xlsx
Normal file
Binary file not shown.
4
pyproject.toml
Normal file
4
pyproject.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=61", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
16
setup.cfg
Normal file
16
setup.cfg
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[metadata]
|
||||||
|
name=downloadmgr
|
||||||
|
version = 0.0.1
|
||||||
|
description = a web ui for aria2
|
||||||
|
author = "yu moqing"
|
||||||
|
author_email = "yumoqing@gmail.com"
|
||||||
|
readme = "README.md"
|
||||||
|
license = "MIT"
|
||||||
|
[options]
|
||||||
|
packages = find:
|
||||||
|
requires_python = ">=3.8"
|
||||||
|
install_requires =
|
||||||
|
apppublic
|
||||||
|
sqlor
|
||||||
|
ahserver
|
||||||
|
|
||||||
26
wwwroot/add_new_download.ui
Normal file
26
wwwroot/add_new_download.ui
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"Form",
|
||||||
|
"options":{
|
||||||
|
"width":"100%",
|
||||||
|
"height":"100%",
|
||||||
|
"fields":[
|
||||||
|
{
|
||||||
|
"name":"url",
|
||||||
|
"label":"下载地址",
|
||||||
|
"uitype":"text",
|
||||||
|
"required":true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"binds":[
|
||||||
|
{
|
||||||
|
"wid":"self",
|
||||||
|
"event":"submit",
|
||||||
|
"actiontype":"urlwidget",
|
||||||
|
"target":"self",
|
||||||
|
"options":{
|
||||||
|
"url":"{{entire_url('./download_url.dspy')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
8
wwwroot/download_url.dspy
Normal file
8
wwwroot/download_url.dspy
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
dmgr = DownloadMgr(request)
|
||||||
|
try:
|
||||||
|
x = await dmgr.download(params_kw.url)
|
||||||
|
return UiMessage(title='download', message=f'download submited')
|
||||||
|
except Exception as e:
|
||||||
|
exception(f'{params_kw.url} download failed,{e=}\n{format_exc()}')
|
||||||
|
return UiError(title='download error', message=f'{params_kw.url} download failed,{e=}')
|
||||||
22
wwwroot/list_downloading.ui
Normal file
22
wwwroot/list_downloading.ui
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"widgettype":"DynamicColumn",
|
||||||
|
"options":{
|
||||||
|
"width":"100%",
|
||||||
|
"height":"100%"
|
||||||
|
},
|
||||||
|
"subwidgets":[
|
||||||
|
{% set dmgr = DownloadMgr(request) %}
|
||||||
|
{for task in dmgr.get_user_tasks() %}
|
||||||
|
{
|
||||||
|
"widgettype":"urlwidget",
|
||||||
|
"options":{
|
||||||
|
"params":{
|
||||||
|
"taskid":"{{task.id}}"
|
||||||
|
},
|
||||||
|
"url":"{{entire_url('task_info.ui')}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{% if not loop.last %},{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
]
|
||||||
|
}
|
||||||
26
wwwroot/task_info.ui
Normal file
26
wwwroot/task_info.ui
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{% set dmgr=DownloadMgr(request) %}
|
||||||
|
{% set status=dmgr.get_task_status(params_kw.taskid) %}
|
||||||
|
{
|
||||||
|
"widgettype":"VBox",
|
||||||
|
"options":{
|
||||||
|
"cwidth":16,
|
||||||
|
"cheight":14,
|
||||||
|
"css":"card"
|
||||||
|
},
|
||||||
|
"subwidgets":[
|
||||||
|
{
|
||||||
|
"widgettype":"Title3",
|
||||||
|
"options:{
|
||||||
|
"text":"{{status.filename}}",
|
||||||
|
"wrap":true,
|
||||||
|
"halign":"left"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgettype":"Text",
|
||||||
|
"options":{
|
||||||
|
"text":"{{status.completedLength}}/{{status.totalLength}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user