Skip to content

Commit 6c25462

Browse files
committed
fix: 修复了单位,更新了 web dashboard 等等
1 parent 4fa2acc commit 6c25462

File tree

8 files changed

+185
-50
lines changed

8 files changed

+185
-50
lines changed

core/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55
import atexit
66
from . import cluster
77
from . import scheduler
8+
from . import web
9+
from . import dashboard
810

911
_WAITLOCK = utils.CountLock()
1012

1113
async def main():
1214
start = time.monotonic_ns()
1315
await scheduler.init()
16+
await web.init()
17+
await dashboard.init()
1418
await cluster.init()
1519
_WAITLOCK.acquire()
1620
end = time.monotonic_ns()
@@ -20,6 +24,7 @@ async def main():
2024
except:
2125
logger.tdebug("main.debug.service_unfinish")
2226
finally:
27+
await web.unload()
2328
await scheduler.unload()
2429

2530
def init():

core/cluster.py

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ async def write_file(self, file: File, content: bytes):
7171
return all(await asyncio.gather(*(asyncio.create_task(storage.write_file(convert_file_to_storage_file(file), content, file.mtime)) for storage in self.available_storages)))
7272

7373
async def get_missing_files(self, files: set[File]) -> set[File | Any]:
74-
function = None
74+
async def _(file: File, storage: storages.iStorage):
75+
return True
76+
function = _
7577
if function is None:
7678
logger.twarning("cluster.warning.no_check_function")
7779
function = self._check_exists
@@ -81,21 +83,24 @@ async def get_missing_files(self, files: set[File]) -> set[File | Any]:
8183
unit="file",
8284
unit_scale=True,
8385
) as pbar:
84-
missing_files = set().union(await asyncio.gather(*(self._get_missing_file(function, file, pbar) for file in files)))
85-
if None in missing_files:
86-
missing_files.remove(None)
86+
missing_files = set()
87+
waiting_files: asyncio.Queue[File] = asyncio.Queue()
88+
89+
for file in files:
90+
waiting_files.put_nowait(file)
91+
92+
await asyncio.gather(*(self._get_missing_file_storage(function, missing_files, waiting_files, storage, pbar) for storage in self.available_storages))
8793
return missing_files or set()
88-
89-
90-
async def _get_missing_file(self, function: Callable[..., Coroutine[Any, Any, bool]], file: File, pbar: tqdm):
91-
if all(await asyncio.gather(*(self._get_missing_file_storage(function, file, storage, pbar) for storage in self.available_storages))):
92-
return None
93-
return file
9494

95-
async def _get_missing_file_storage(self, function: Callable[..., Coroutine[Any, Any, bool]], file: File, storage: storages.iStorage, pbar: tqdm):
96-
result = await function(file, storage)
97-
pbar.update(1)
98-
return result
95+
async def _get_missing_file_storage(self, function: Callable[..., Coroutine[Any, Any, bool]], missing_files: set[File], files: asyncio.Queue[File], storage: storages.iStorage, pbar: tqdm):
96+
while not files.empty():
97+
file = await files.get()
98+
if await function(file, storage):
99+
pbar.update(1)
100+
else:
101+
missing_files.add(file)
102+
files.task_done()
103+
await asyncio.sleep(0)
99104

100105
async def _check_exists(self, file: File, storage: storages.iStorage):
101106
return await storage.exists(file.hash)
@@ -161,7 +166,7 @@ class FileListManager:
161166
def __init__(self, clusters: 'ClusterManager'):
162167
self.clusters = clusters
163168
self.cluster_last_modified: defaultdict['Cluster', int] = defaultdict(lambda: 0)
164-
self.sync_sem: utils.SemaphoreLock = utils.SemaphoreLock(10)
169+
self.sync_sem: utils.SemaphoreLock = utils.SemaphoreLock(256)
165170
self.download_statistics = DownloadStatistics()
166171

167172
async def _get_filelist(self, cluster: 'Cluster'):
@@ -205,6 +210,10 @@ async def sync(self):
205210

206211
missing = await self.clusters.storage_manager.get_missing_files(result)
207212

213+
if not missing:
214+
logger.tsuccess("cluster.success.no_missing_files")
215+
return
216+
208217
await self.clusters.storage_manager.available()
209218
configurations: defaultdict[str, deque[OpenBMCLAPIConfiguration]] = defaultdict(deque)
210219
for configuration in await asyncio.gather(*(asyncio.create_task(self._get_configuration(cluster)) for cluster in self.clusters.clusters)):
@@ -213,7 +222,7 @@ async def sync(self):
213222
# get better configuration
214223
configuration = max(configurations.items(), key=lambda x: x[1][0].concurrency)[1][0]
215224
logger.tinfo("cluster.info.sync_configuration", source=configuration.source, concurrency=configuration.concurrency)
216-
self.sync_sem.set_value(configuration.concurrency)
225+
#self.sync_sem.set_value(configuration.concurrency)
217226

218227
await self.download(missing)
219228

@@ -315,7 +324,7 @@ def report(self, file: File, error: Exception, resp: Optional[aiohttp.ClientResp
315324
responses.append(f"{r.status} | {r.url}")
316325
responses.append(f"{resp.status} | {resp.url}")
317326
host = resp.host
318-
hash = msg[0] if len(msg) > 0 else None
327+
hash = msg[0] if len(msg) > 0 and type == "file" else None
319328
logger.debug(error)
320329
logger.terror(f"clusters.error.downloading", type=type, file_hash=file.hash, file_size=units.format_bytes(file.size), host=host, file_path=file.path, hash=hash, responses="\n".join(("", *responses)))
321330

@@ -351,6 +360,8 @@ async def start(self):
351360
# check files
352361
await self.file_manager.sync()
353362

363+
# start job
364+
354365

355366

356367
class Cluster:
@@ -455,7 +466,10 @@ async def init():
455466
continue
456467
logger.tsuccess("cluster.success.load_cluster", id=cluster.id, host=cluster.host, port=cluster.port)
457468
clusters.add_cluster(cluster)
458-
469+
if len(clusters.clusters) == 0:
470+
logger.terror("cluster.error.no_cluster")
471+
utils.pause()
472+
return
459473
config_storages = config_clusters = config.Config.get("storages")
460474
for cstorage in config_storages:
461475
type = cstorage['type']

core/config.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
"advanced.sync_interval": 60,
1414
"advanced.base_url": "https://openbmclapi.bangbang93.com",
1515
"advanced.threads": 128,
16+
"web": {
17+
"port": -1,
18+
"public_port": 6000
19+
},
1620
"clusters": [
1721
{
1822
"id": "",
1923
"secret": "",
2024
"host": "",
2125
"byoc": False,
22-
"public_port": -1,
23-
"port": 8800,
2426
"cert": "./cert/cert.pem",
2527
"key": "./cert/key.pem",
2628
}
@@ -93,4 +95,8 @@ def base_url(self) -> str:
9395
def threads(self):
9496
return Config.get("advanced.threads", 128)
9597

98+
@property
99+
def public_port(self):
100+
return Config.get("web.public_port", 6000)
101+
96102
const = Const()

core/dashboard.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from .web import routes as route
2+
from aiohttp import web
3+
4+
@route.get('/dashboard/')
5+
@route.get("/dashboard/{tail:.*}")
6+
async def _(request: web.Request):
7+
return web.FileResponse("./assets/index.html")
8+
9+
@route.get('/')
10+
async def _(request: web.Request):
11+
return web.HTTPFound('/dashboard/')
12+
13+
route.static("/assets", "./assets")
14+
15+
16+
async def init():
17+
...

core/units.py

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,64 @@
33
NUMBER_UNITS = (
44
('', 1),
55
('K', 1e3),
6-
('M', 1e6),
7-
('G', 1e9),
8-
('T', 1e12),
9-
('P', 1e15),
10-
('E', 1e18),
11-
('Z', 1e21),
12-
('Y', 1e24),
6+
('M', 1e3),
7+
('G', 1e3),
8+
('T', 1e3),
9+
('P', 1e3),
10+
('E', 1e3),
11+
('Z', 1e3),
12+
('Y', 1e3),
1313
)
1414

1515
TIME_UNITS = (
1616
('ns', 1),
1717
('μs', 1e3),
18-
('ms', 1e6),
19-
('s', 1e9),
20-
('min', 6e10),
21-
('h', 3.6e12),
18+
('ms', 1e3),
19+
('s', 1e3),
20+
('min', 60),
21+
('h', 60),
2222
)
2323
# 1024
2424
BYTES_UNITS = (
2525
('iB', 1),
2626
('KiB', 1024),
27-
('MiB', 1024**2),
28-
('GiB', 1024**3),
29-
('TiB', 1024**4),
30-
('PiB', 1024**5),
31-
('EiB', 1024**6),
32-
('ZiB', 1024**7),
33-
('YiB', 1024**8)
27+
('MiB', 1024),
28+
('GiB', 1024),
29+
('TiB', 1024),
30+
('PiB', 1024),
31+
('EiB', 1024),
32+
('ZiB', 1024),
33+
('YiB', 1024)
3434
)
3535

3636
def format_bytes(n: float) -> str:
3737
i = 0
38-
while n >= 1024 and i < len(BYTES_UNITS) - 1:
39-
n /= 1024
38+
for u, un in BYTES_UNITS[1:]:
39+
if n / un < 1:
40+
break
41+
n /= un
4042
i += 1
4143
return f'{n:.2f}{BYTES_UNITS[i][0]}'
4244

4345

4446
def format_number(n: float) -> str:
45-
i = 0
46-
while n >= 1000 and i < len(NUMBER_UNITS) - 1:
47-
n /= 1000
47+
i = 0
48+
for u, un in NUMBER_UNITS[1:]:
49+
if n / un < 1:
50+
break
51+
n /= un
4852
i += 1
4953
return f'{n:.2f}{NUMBER_UNITS[i][0]}'
5054

5155

52-
def format_count_time(n: float) -> str:
56+
def format_count_time(n: float, round: int = 2) -> str:
5357
i = 0
54-
for unit, t in TIME_UNITS:
55-
if n < t:
58+
for u, un in TIME_UNITS[1:]:
59+
if n / un < 1:
5660
break
57-
n /= t
61+
n /= un
5862
i += 1
59-
return f'{n:.2f}{TIME_UNITS[i][0]}'
63+
return f'{n:.{round}f}{TIME_UNITS[i][0]}'
6064

6165
def format_count_datetime(secs: float) -> str:
6266
ms = int(secs * 1000)

core/utils.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,11 @@ def get_hash_hexdigest(origin: str, content: bytes):
121121
h = hashlib.sha1
122122
if len(origin) == 32:
123123
h = hashlib.md5
124-
return h(content).hexdigest()
124+
return h(content).hexdigest()
125+
126+
def pause():
127+
try:
128+
input("Press Enter to continue...")
129+
except KeyboardInterrupt:
130+
exit()
131+
pass

core/web.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import asyncio
2+
import time
3+
from typing import Any, Optional
4+
from aiohttp import web
5+
from aiohttp.web_urldispatcher import SystemRoute
6+
7+
from . import units
8+
from . import config
9+
from .logger import logger
10+
11+
@web.middleware
12+
async def middleware(request: web.Request, handler: Any) -> web.Response:
13+
with request.match_info.set_current_app(app):
14+
start = time.monotonic_ns()
15+
resp = None
16+
try:
17+
resp = await handler(request)
18+
return resp
19+
finally:
20+
status = 500
21+
if isinstance(request.match_info.route, SystemRoute):
22+
status = request.match_info.route.status
23+
if resp is not None:
24+
if isinstance(resp, web.StreamResponse):
25+
status = resp.status
26+
end = time.monotonic_ns()
27+
logger.tdebug("web.debug.request_info", time=units.format_count_time(end - start, 4).rjust(16), host=request.host, address=(request.remote or "").rjust(16), user_agent=request.headers.get("User-Agent"), real_path=request.raw_path, method=request.method.ljust(9), status=status)
28+
29+
30+
routes = web.RouteTableDef()
31+
32+
app = web.Application(
33+
middlewares=[
34+
middleware
35+
]
36+
)
37+
runner: Optional[web.AppRunner] = None
38+
site: Optional[web.TCPSite] = None
39+
public_server: Optional[asyncio.Server] = None
40+
41+
async def get_free_port():
42+
async def _(_, __):
43+
...
44+
server = await asyncio.start_server(_, port=-1)
45+
port = server.sockets[0].getsockname()[1]
46+
server.close()
47+
await server.wait_closed()
48+
return port
49+
50+
async def handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
51+
...
52+
53+
async def init():
54+
global runner, site, public_server, routes, app
55+
56+
app.add_routes(routes)
57+
58+
runner = web.AppRunner(app)
59+
await runner.setup()
60+
61+
port = await get_free_port()
62+
63+
site = web.TCPSite(runner, '0.0.0.0', port)
64+
await site.start()
65+
66+
logger.tdebug("web.debug.local_port", port=site._port)
67+
68+
69+
public_server = await asyncio.start_server(
70+
handle, port=config.const.public_port
71+
)
72+
logger.tsuccess("web.success.public_port", port=config.const.public_port)
73+
74+
75+
async def unload():
76+
global app
77+
await app.cleanup()
78+
await app.shutdown()

i18n/zh_cn.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,9 @@
1313
"cluster.processbar.download_files": "下载文件",
1414
"i18n.prompt.failed": " 未找到 i18n 字符串",
1515
"cluster.warning.no_check_function": "没有找到检查函数,使用类型为 exists",
16-
"clusters.error.downloading": "下载时候出错,原因 [${type}],文件 [${file_path} ${file_hash}(${file_size})],主机 [${host}] 下载时候的历史记录:${responses}"
16+
"clusters.error.downloading": "下载时候出错,原因 [${type}],文件 [${file_path} ${file_hash}(${file_size})] 下载后的哈希值 [${hash}],主机 [${host}] 下载时候的历史记录:${responses}",
17+
"web.debug.local_port": "内部开放端口为 [${port}]",
18+
"web.success.public_port": "当前 Web 服务器在 [${port}] 端口上开启",
19+
"web.error.any": "Web 服务器出错 ${e}",
20+
"web.debug.request_info": "${host} | ${time} | ${address} | ${method} ${status} | ${real_path} - ${user_agent}"
1721
}

0 commit comments

Comments
 (0)