Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

<div align="center">

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

# **OpenBMCLAPI for Python**
# OpenBMCLAPI for Python

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

🎨 **跨系统**、**跨架构**和 **Docker** 支持。

🎉 __*新增功能!*__基于 Echart 的 OpenBMCLAPI 仪表盘(Dashboard)。

</div>

# 简介
Expand Down
16 changes: 16 additions & 0 deletions container/bmclapi_dashboard/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8"/>
<title>OPENBMCLAPI - TTB Network</title>
</head>
<body>
</body>
<script src="./static/js/extend.js"></script>
<script src="./static/js/echarts.min.js"></script>
<script src="./static/js/axios.min.js"></script>
<script src="./static/js/index.js"></script>
</html>
1 change: 1 addition & 0 deletions container/bmclapi_dashboard/static/js/axios.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions container/bmclapi_dashboard/static/js/echarts.min.js

Large diffs are not rendered by default.

956 changes: 956 additions & 0 deletions container/bmclapi_dashboard/static/js/extend.js

Large diffs are not rendered by default.

304 changes: 304 additions & 0 deletions container/bmclapi_dashboard/static/js/index.js

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions container/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ async def check_file(self):
filepath = Path(str(self.dir) + f"/{file.hash[:2]}/{file.hash}")
if not filepath.exists() or filepath.stat().st_size != file.size:
miss.append(file)
await asyncio.sleep(0)
...
await asyncio.sleep(0)
b = utils.calc_more_bytes(byte, filesize)
byte += file.size
print(f"<<<flush>>>Check file {i}/{total} ({b[0]}/{b[1]})")
Expand Down Expand Up @@ -178,7 +179,7 @@ async def enable(self):
"byoc": config.BYOC,
"noFastEnable": False
})
if not (Path(".ssl/cert.pem").exists() and Path(".ssl/key.pem").exists()):
if not web.get_ssl() and not (Path(".ssl/cert.pem").exists() and Path(".ssl/key.pem").exists()):
await self.emit("request-cert")
self.cur_counter = stats.Counters()
print("Connected Main Server.")
Expand Down Expand Up @@ -304,9 +305,16 @@ async def _(request: web.Request, hash: str, s: str, e: str):
COUNTER.hit += 1
return data.getbuffer()
router: web.Router = web.Router("/bmcl")
dir = Path("./bmclapi_dashboard/")
dir.mkdir(exist_ok=True, parents=True)
app.mount_resource(web.Resource("/bmcl", dir, show_dir=True))
@router.get("/")
async def _(request: web.Request):
print(request.get_ip())
return Path("./bmclapi_dashboard/index.html")
@router.get("/master")
async def _(request: web.Request, url: str):
resp = await aiohttp.ClientSession(URL).get(url)
return resp.content.iter_chunked(config.REQUEST_BUFFER) # type: ignore
app.mount(router)

async def clearCache():
Expand Down
21 changes: 0 additions & 21 deletions container/main.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,3 @@
import importlib
import subprocess

def install_module(module_name, module = None):
module = module or module_name
try:
importlib.import_module(module_name)
except ImportError:
print(f"正在安装模块 '{module_name}'...")
subprocess.check_call(["pip", "install", module])
print(f"模块 '{module_name}' 安装成功")

def init():
install_module('socketio')
install_module('aiohttp')
install_module("hmac")
install_module("pyzstd")
install_module("avro", "avro-python3")

init()

if __name__ == "__main__":
import web
web.init()
30 changes: 23 additions & 7 deletions container/web.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import base64
from dataclasses import dataclass
import datetime
import inspect
Expand Down Expand Up @@ -70,12 +71,15 @@ def post(self, path):

class Resource:
def __init__(self, url: str, path: Path, show_dir: bool = False) -> None:
if not path.is_dir():
if not path.exists():
raise RuntimeError(f"The path {path} is not dir.")
self.path = path
self.dir = str(path.absolute()).replace("\\", "/").removesuffix("/")
self.url = f"/" + url.lstrip("/")
self.show_dir = show_dir
async def __call__(self, url: str, request: 'Request') -> Any:
async def __call__(self, request: 'Request') -> Any:
if self.path.is_file():
return self.dir
path = (self.dir + request.path.removeprefix(self.url))
filepath = Path(self.dir + request.path.removeprefix(self.url))
if filepath.is_dir() and self.show_dir:
Expand Down Expand Up @@ -107,7 +111,7 @@ async def __call__(self, url: str, request: 'Request') -> Any:
return content
elif filepath.is_file():
return filepath
return "Not Found"
return Response("Not Found", status_code=404)

class Application:
def __init__(self) -> None:
Expand Down Expand Up @@ -180,7 +184,7 @@ async def handle(self, request: 'Request', client: Client):
else:
for resource in self._resources:
if request.url.startswith(resource.url):
result = await resource(request.url, request)
result = await resource(request)
break
if result == None:
accept = await request.get_headers("Accept", ) or ""
Expand Down Expand Up @@ -504,15 +508,22 @@ async def handle(data, client: Client):
import web
server: Optional[asyncio.Server] = None
cert = None
cur_ssl = False
def get_ssl():
global cur_ssl
return cur_ssl

def load_cert():
global cert
global cert, cur_ssl
if Path(".ssl/cert.pem").exists() and Path(".ssl/key.pem").exists():
cert = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
cert.check_hostname = False
cert.load_cert_chain(Path(".ssl/cert.pem"), Path(".ssl/key.pem"))
if server:
server.close()
cur_ssl = True
else:
cur_ssl = False

async def _handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
client = Client(reader, writer)
Expand All @@ -529,16 +540,21 @@ async def _handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
async def main():
global cert, server
load_cert()
import cluster
await cluster.init()
while 1:
try:
server = await asyncio.start_server(_handle, host='0.0.0.0', port=config.PORT, ssl=cert)
print(f"Server listen on {config.PORT}{' with ssl' if cert else ''}!")
import cluster
await cluster.init()
await server.serve_forever()
except:
if server:
server.close()
traceback.print_exc()

@app.get("/favicon.ico")
async def _():
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=")

def init():
asyncio.run(main())
19 changes: 0 additions & 19 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,8 @@
import importlib
import io
import json
from pathlib import Path
import queue
import subprocess
import threading
from typing import Optional


def install_module(module_name, module = None):
module = module or module_name
try:
importlib.import_module(module_name)
except ImportError:
print(f"正在安装模块 '{module_name}'...")
subprocess.check_call(["pip", "install", module])
print(f"模块 '{module_name}' 安装成功")

def init():
install_module('watchdog')

init()

import sys
import time
from watchdog.observers import Observer
Expand Down