Skip to content

Commit 459ca23

Browse files
authored
Merge pull request #5 from TTB-Network/dev/dashboard
✨ 新增 Dashboard
2 parents 921c20a + 1932de4 commit 459ca23

File tree

10 files changed

+1316
-52
lines changed

10 files changed

+1316
-52
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11

22
<div align="center">
33

4-
![](https://s21.ax1x.com/2024/03/09/pFsjxVf.png)
4+
![](https://s21.ax1x.com/2024/03/09/pFyV90g.png)
55

6-
# **OpenBMCLAPI for Python**
6+
# OpenBMCLAPI for Python
77

88
![GitHub Issues or Pull Requests](https://img.shields.io/github/issues-pr/tianxiu2b2t/python-openbmclapi)
99
![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/tianxiu2b2t/python-openbmclapi)
@@ -17,6 +17,8 @@
1717

1818
🎨 **跨系统****跨架构****Docker** 支持。
1919

20+
🎉 __*新增功能!*__基于 Echart 的 OpenBMCLAPI 仪表盘(Dashboard)。
21+
2022
</div>
2123

2224
# 简介
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<meta charset="utf-8"/>
8+
<title>OPENBMCLAPI - TTB Network</title>
9+
</head>
10+
<body>
11+
</body>
12+
<script src="./static/js/extend.js"></script>
13+
<script src="./static/js/echarts.min.js"></script>
14+
<script src="./static/js/axios.min.js"></script>
15+
<script src="./static/js/index.js"></script>
16+
</html>

container/bmclapi_dashboard/static/js/axios.min.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

container/bmclapi_dashboard/static/js/echarts.min.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

container/bmclapi_dashboard/static/js/extend.js

Lines changed: 956 additions & 0 deletions
Large diffs are not rendered by default.

container/bmclapi_dashboard/static/js/index.js

Lines changed: 304 additions & 0 deletions
Large diffs are not rendered by default.

container/cluster.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ async def check_file(self):
129129
filepath = Path(str(self.dir) + f"/{file.hash[:2]}/{file.hash}")
130130
if not filepath.exists() or filepath.stat().st_size != file.size:
131131
miss.append(file)
132-
await asyncio.sleep(0)
132+
...
133+
await asyncio.sleep(0)
133134
b = utils.calc_more_bytes(byte, filesize)
134135
byte += file.size
135136
print(f"<<<flush>>>Check file {i}/{total} ({b[0]}/{b[1]})")
@@ -178,7 +179,7 @@ async def enable(self):
178179
"byoc": config.BYOC,
179180
"noFastEnable": False
180181
})
181-
if not (Path(".ssl/cert.pem").exists() and Path(".ssl/key.pem").exists()):
182+
if not web.get_ssl() and not (Path(".ssl/cert.pem").exists() and Path(".ssl/key.pem").exists()):
182183
await self.emit("request-cert")
183184
self.cur_counter = stats.Counters()
184185
print("Connected Main Server.")
@@ -304,9 +305,16 @@ async def _(request: web.Request, hash: str, s: str, e: str):
304305
COUNTER.hit += 1
305306
return data.getbuffer()
306307
router: web.Router = web.Router("/bmcl")
308+
dir = Path("./bmclapi_dashboard/")
309+
dir.mkdir(exist_ok=True, parents=True)
310+
app.mount_resource(web.Resource("/bmcl", dir, show_dir=True))
307311
@router.get("/")
308312
async def _(request: web.Request):
309-
print(request.get_ip())
313+
return Path("./bmclapi_dashboard/index.html")
314+
@router.get("/master")
315+
async def _(request: web.Request, url: str):
316+
resp = await aiohttp.ClientSession(URL).get(url)
317+
return resp.content.iter_chunked(config.REQUEST_BUFFER) # type: ignore
310318
app.mount(router)
311319

312320
async def clearCache():

container/main.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,3 @@
1-
import importlib
2-
import subprocess
3-
4-
def install_module(module_name, module = None):
5-
module = module or module_name
6-
try:
7-
importlib.import_module(module_name)
8-
except ImportError:
9-
print(f"正在安装模块 '{module_name}'...")
10-
subprocess.check_call(["pip", "install", module])
11-
print(f"模块 '{module_name}' 安装成功")
12-
13-
def init():
14-
install_module('socketio')
15-
install_module('aiohttp')
16-
install_module("hmac")
17-
install_module("pyzstd")
18-
install_module("avro", "avro-python3")
19-
20-
init()
21-
221
if __name__ == "__main__":
232
import web
243
web.init()

container/web.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import base64
23
from dataclasses import dataclass
34
import datetime
45
import inspect
@@ -70,12 +71,15 @@ def post(self, path):
7071

7172
class Resource:
7273
def __init__(self, url: str, path: Path, show_dir: bool = False) -> None:
73-
if not path.is_dir():
74+
if not path.exists():
7475
raise RuntimeError(f"The path {path} is not dir.")
76+
self.path = path
7577
self.dir = str(path.absolute()).replace("\\", "/").removesuffix("/")
7678
self.url = f"/" + url.lstrip("/")
7779
self.show_dir = show_dir
78-
async def __call__(self, url: str, request: 'Request') -> Any:
80+
async def __call__(self, request: 'Request') -> Any:
81+
if self.path.is_file():
82+
return self.dir
7983
path = (self.dir + request.path.removeprefix(self.url))
8084
filepath = Path(self.dir + request.path.removeprefix(self.url))
8185
if filepath.is_dir() and self.show_dir:
@@ -107,7 +111,7 @@ async def __call__(self, url: str, request: 'Request') -> Any:
107111
return content
108112
elif filepath.is_file():
109113
return filepath
110-
return "Not Found"
114+
return Response("Not Found", status_code=404)
111115

112116
class Application:
113117
def __init__(self) -> None:
@@ -180,7 +184,7 @@ async def handle(self, request: 'Request', client: Client):
180184
else:
181185
for resource in self._resources:
182186
if request.url.startswith(resource.url):
183-
result = await resource(request.url, request)
187+
result = await resource(request)
184188
break
185189
if result == None:
186190
accept = await request.get_headers("Accept", ) or ""
@@ -504,15 +508,22 @@ async def handle(data, client: Client):
504508
import web
505509
server: Optional[asyncio.Server] = None
506510
cert = None
511+
cur_ssl = False
512+
def get_ssl():
513+
global cur_ssl
514+
return cur_ssl
507515

508516
def load_cert():
509-
global cert
517+
global cert, cur_ssl
510518
if Path(".ssl/cert.pem").exists() and Path(".ssl/key.pem").exists():
511519
cert = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
512520
cert.check_hostname = False
513521
cert.load_cert_chain(Path(".ssl/cert.pem"), Path(".ssl/key.pem"))
514522
if server:
515523
server.close()
524+
cur_ssl = True
525+
else:
526+
cur_ssl = False
516527

517528
async def _handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
518529
client = Client(reader, writer)
@@ -529,16 +540,21 @@ async def _handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
529540
async def main():
530541
global cert, server
531542
load_cert()
543+
import cluster
544+
await cluster.init()
532545
while 1:
533546
try:
534547
server = await asyncio.start_server(_handle, host='0.0.0.0', port=config.PORT, ssl=cert)
535548
print(f"Server listen on {config.PORT}{' with ssl' if cert else ''}!")
536-
import cluster
537-
await cluster.init()
538549
await server.serve_forever()
539550
except:
540551
if server:
541552
server.close()
542553
traceback.print_exc()
554+
555+
@app.get("/favicon.ico")
556+
async def _():
557+
return base64.b64decode("AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAKBEAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAHA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/wAAAP8AAAD/HA37/xwN+/8AAAD/AAAA/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8AAAD/AAAA/xwN+/8cDfv/AAAA/wAAAP8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAHA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/Gwz0/xsM9P8bDPT/Gwz0/xsM9P8bDPT/Gwz0/xsM9P8bDPT/Gwz0/xsM9P8bDPT/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xsM9P8BAQ7/AAAH/wAAB/8AAAf/AAAH/wAAB/8AAAf/AAAH/wAAB/8AAAf/AAAH/wEBDv8bDPT/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/Gwz0/wAAB/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAH/xsM9P8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8bDPT/AAAH/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAf/Gwz0/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xsM9P8BAQ7/AAAH/wAAB/8AAAf/AAAH/wAAB/8AAAf/AAAH/wAAB/8AAAf/AAAH/wEBDv8bDPT/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xsM9P8bDPT/Gwz0/xsM9P8bDPT/Gwz0/xsM9P8bDPT/Gwz0/xsM9P8bDPT/Gwz0/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/Gwz0/xsM9P8bDPT/Gwz0/xwN+/8cDfv/HA37/xwN+/8bDPT/Gwz0/xsM9P8bDPT/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xsM9P8BAQ7/AAAH/wAAB/8BAQ7/Gwz0/xwN+/8cDfv/Gwz0/wEBDv8AAAf/AAAH/wEBDv8bDPT/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/Gwz0/wAAB/8AAAD/AAAA/wAAB/8bDPT/HA37/xwN+/8bDPT/AAAH/wAAAP8AAAD/AAAH/xsM9P8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8bDPT/AAAH/wAAAP8AAAD/AAAH/xsM9P8cDfv/HA37/xsM9P8AAAf/AAAA/wAAAP8AAAf/Gwz0/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xsM9P8BAQ7/AAAH/wAAB/8BAQ7/Gwz0/xwN+/8cDfv/Gwz0/wEBDv8AAAf/AAAH/wEBDv8bDPT/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xsM9P8bDPT/Gwz0/xsM9P8cDfv/HA37/xwN+/8cDfv/Gwz0/xsM9P8bDPT/Gwz0/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/xwN+/8cDfv/HA37/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
558+
543559
def init():
544560
asyncio.run(main())

main.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,8 @@
1-
import importlib
2-
import io
3-
import json
41
from pathlib import Path
52
import queue
63
import subprocess
74
import threading
85
from typing import Optional
9-
10-
11-
def install_module(module_name, module = None):
12-
module = module or module_name
13-
try:
14-
importlib.import_module(module_name)
15-
except ImportError:
16-
print(f"正在安装模块 '{module_name}'...")
17-
subprocess.check_call(["pip", "install", module])
18-
print(f"模块 '{module_name}' 安装成功")
19-
20-
def init():
21-
install_module('watchdog')
22-
23-
init()
24-
256
import sys
267
import time
278
from watchdog.observers import Observer

0 commit comments

Comments
 (0)