Skip to content

Commit cf8e9d0

Browse files
committed
fix: 重构 cluster.py,优化部分逻辑
feat: 准备下个版本支持多数据库类型 feat: 更新 socketio 的 debug fix: 修复统计的 UserAgent 和 IP 地址的覆盖为默认值 feat: 更新 dashboard 的登陆面板(暂未支持实现) feat: 版本更新至 1.1.0
1 parent a9df781 commit cf8e9d0

File tree

14 files changed

+1180
-1266
lines changed

14 files changed

+1180
-1266
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v1.0.25
1+
v1.1.0

bmclapi_dashboard/static/js/index.min.js

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,14 +1497,15 @@ class SocketData {
14971497
this.$opened = false
14981498
this.$key = 1
14991499
this.$callback = {}
1500+
this.$creating = false
15001501
this.create_ws()
15011502
}
15021503
}
15031504
send_http(namespace, data) {
15041505
return new Promise(async (resolve, reject) => {
15051506
const resp = await fetch(`${this.$url}?namespace=${encodeURIComponent(namespace)}`, {
15061507
method: "POST",
1507-
data: data
1508+
body: JSON.stringify(data)
15081509
})
15091510
var resp_data = [null, null]
15101511
if (resp.ok) {
@@ -1522,9 +1523,9 @@ class SocketData {
15221523
resolve(resp_data)
15231524
})
15241525
}
1525-
create_ws() {
1526+
async create_ws() {
15261527
if (!this.$support) throw "Unable to send websocket data."
1527-
if (this.$ws == null) this.$ws = new WebSocketClient("ws" + (this.$url.slice(4)), {
1528+
if (this.$ws == null && !this.$creating) this.$ws = new WebSocketClient("ws" + (this.$url.slice(4)), {
15281529
"onmessage": (msg) => {
15291530
var data = JSON.parse(msg.data)
15301531
this.recv(
@@ -1546,6 +1547,7 @@ class SocketData {
15461547
}
15471548
this.$cache = {}
15481549
window.dispatchEvent(new Event("mainsocket_connect"))
1550+
this.$creating = false
15491551
},
15501552
"onclose": () => {
15511553
this.$opened = false
@@ -2394,14 +2396,16 @@ class Authentication {
23942396
this._main = []
23952397
this._input = {
23962398
username: app.createElement("input"),
2397-
password: app.createElement("input"),
2399+
password: app.createElement("input").setAttribute("type", "password"),
23982400
captcha: {
23992401
image: app.createElement("img"),
24002402
input: app.createElement("input")
24012403
},
24022404
label: app.createElement("p"),
2403-
auth: app.createElement("button").setI18N("dashboard.auth.login"),
2404-
forever: app.createElement("button").setAttribute("type", "checkbox")
2405+
auth: app.createElement("button").class("submit").setI18N("dashboard.auth.login").event("click", async () => {
2406+
await this.login("a", "a", false)
2407+
}),
2408+
forever: app.createElement("input").setAttribute("type", "checkbox")
24052409
}
24062410
this._captcha = app.createElement("div")
24072411
this._container = app.createElement("div").class("panel-auth").append(
@@ -2410,7 +2414,10 @@ class Authentication {
24102414
this._captcha,
24112415
this._input.label,
24122416
this._input.auth,
2413-
this._input.forever,
2417+
/*app.createElement("div").class("flex", "panel-auth-root").append(
2418+
app.createElement("span").setText("Forever"),
2419+
this._input.forever,
2420+
),*/
24142421
)
24152422
this._Styles = {
24162423
".panel-auth": `
@@ -2419,6 +2426,10 @@ class Authentication {
24192426
justify-content: center;
24202427
align-items: stretch;
24212428
`,
2429+
'.panel-auth-root': [
2430+
'margin: 8px',
2431+
'padding: 8px'
2432+
],
24222433
'.panel-auth input, .panel-auth button': [
24232434
'margin: 4px',
24242435
'padding: 8px'
@@ -2443,7 +2454,7 @@ class Authentication {
24432454
margin: 0px;
24442455
color: var(--color);
24452456
-webkit-tap-highlight-color: transparent;
2446-
width: 100%;
2457+
width: 98%;
24472458
padding: 8.5px 0px 8.5px 14px;`
24482459
],
24492460
'.panel-auth .label-input label': [
@@ -2481,14 +2492,13 @@ class Authentication {
24812492
border-width: 1px;
24822493
overflow: hidden;
24832494
color: var(--color);
2484-
border-color: var(--shadow);`
2495+
border-color: var(--dark-color);`
24852496
],
24862497
'.panel-auth .label-input:hover fieldset': [
24872498
'border-color: var(--main-shadow)'
24882499
],
24892500
'.panel-auth .label-input.active fieldset': [
24902501
'border-color: var(--none-color-shadow)',
2491-
'border-width: 1.25px;'
24922502
],
24932503
'.panel-auth .label-input legend': [
24942504
`float: unset;
@@ -2516,6 +2526,27 @@ class Authentication {
25162526
`font-size: 0.75em;
25172527
visibility: visible;
25182528
white-space: nowrap;`
2529+
],
2530+
'.panel-auth .submit': [
2531+
`background-color: transparent;
2532+
border: none;
2533+
border-radius: 100px;
2534+
color: var(--color);
2535+
margin: 8px;
2536+
padding: 8px;
2537+
transition: background-color 0.3s ease, color 0.3s ease;
2538+
`
2539+
],
2540+
'.panel-auth .submit::before': [
2541+
`filter: blur(10px);`
2542+
],
2543+
'.panel-auth .submit:hover': [
2544+
`background-color: var(--main-shadow);
2545+
transition: background-color 0.3s ease, color 0.3s ease;`
2546+
],
2547+
'.panel-auth .submit:active': [
2548+
`background-color: var(--main-color);
2549+
transition: background-color 0.3s ease, color 0.3s ease;`
25192550
]
25202551
}
25212552
this.refreshToken = $config.get("refreshToken") || null
@@ -2563,14 +2594,16 @@ class Authentication {
25632594
async login(username, password, forever = false) {
25642595
var [err, ack] = await $MainSocket.send("auth", {
25652596
"username": username,
2566-
"password": atob(password)
2567-
})
2597+
"password": btoa(password)
2598+
}, true)
25682599
if (ack && ack.success) {
25692600
this.username = ack.username
25702601
this.avatar = ack.avatar
25712602
this.token = ack.token
25722603
this.refreshToken = ack.refreshToken
2604+
return true
25732605
}
2606+
return false
25742607
}
25752608
open() {
25762609
modal.title_i18n("dashboard.auth").open().setConfirm(false).body(
@@ -3796,9 +3829,7 @@ app.$Menu.add("dashboard", new class {
37963829
window.addEventListener("lang", refresh)
37973830
await $MainSocket.send("status", (new Date().valueOf())).then((data) => {
37983831
var [err, ack] = data
3799-
var ping = (new Date().valueOf()) - ack.timestamp || ack.time.current * 1000
3800-
console.log(ack)
3801-
this.uptime = ack.uptime - ping / 1000 + ((new Date().valueOf()) - ack.time.current * 1000) / 1000
3832+
this.uptime = ack.uptime + (ack.time.current - (new Date().valueOf() / 1000.0))
38023833
this.status = ack
38033834
})
38043835
await $MainSocket.send("statistics", (this.storages[this.switch_storage.selected - 1])).then((data) => {
@@ -3817,7 +3848,7 @@ app.$Menu.add("dashboard", new class {
38173848
window.addEventListener("mainsocket_status", (data) => {
38183849
var [err, ack] = data.detail
38193850
this.status = ack
3820-
this.uptime = ack.uptime + ((new Date().valueOf()) - ack.time.current * 1000) / 1000
3851+
this.uptime = ack.uptime + (ack.time.current - (new Date().valueOf()) / 1000.0)
38213852
this.setStatus()
38223853
})
38233854
} else {
@@ -3826,7 +3857,7 @@ app.$Menu.add("dashboard", new class {
38263857
$MainSocket.send("status", (new Date().valueOf())).then((data) => {
38273858
var [err, ack] = data
38283859
var ping = (new Date().valueOf()) - ack.timestamp || ack.time.current * 1000
3829-
this.uptime = ack.uptime - ping / 1000 + ((new Date().valueOf()) - ack.time.current * 1000) / 1000
3860+
this.uptime = ack.uptime + (ack.time.current - (new Date().valueOf()) / 1000.0)
38303861
this.status = ack
38313862
this.setStatus()
38323863
})
@@ -3835,6 +3866,13 @@ app.$Menu.add("dashboard", new class {
38353866
window.addEventListener("mainsocket_disconnect", (data) => {
38363867
this.uptime = null
38373868
})
3869+
window.addEventListener("mainsocket_connect", () => {
3870+
$MainSocket.send("status", (new Date().valueOf())).then((data) => {
3871+
var [err, ack] = data
3872+
this.uptime = ack.uptime + (ack.time.current - (new Date().valueOf() / 1000.0))
3873+
this.status = ack
3874+
})
3875+
})
38383876
this.initBasic()
38393877
this.switch.select(0)
38403878
}

core/__init__.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import time
44
from .env import env as env
55
import atexit
6-
from .logger import logger
6+
from .logger import logger, socketio_logger
77
from .scheduler import init as scheduler_init
88
from .scheduler import exit as scheduler_exit
99
from .utils import WaitLock
@@ -28,13 +28,13 @@ def init():
2828
if wait_exit.locked:
2929
wait_exit.release()
3030

31-
3231
async def async_init():
3332
# first init
3433
await scheduler_init()
3534
# load modules
3635
from .network import init as network_init
37-
from .network import close as network_exit
36+
from .network import exit as network_exit
37+
from .database import init as database_init
3838
from .cluster import init as cluster_init
3939
from .cluster import exit as cluster_exit
4040
from .statistics import init as stats_init
@@ -43,6 +43,7 @@ async def async_init():
4343
from .system import init as system_init
4444
import plugins
4545

46+
database_init()
4647
update_init()
4748
scheduler.delay(network_init)
4849
stats_init()
@@ -56,12 +57,12 @@ async def async_init():
5657

5758
await wait_exit.wait()
5859
env["EXIT"] = True
59-
network_exit()
6060
await cluster_exit()
6161
for plugin in plugins.get_enable_plugins():
6262
await plugin.disable()
63-
scheduler_exit()
63+
network_exit()
6464
stats_exit()
65+
scheduler_exit()
6566

6667

6768
def exit():

core/api.py

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import abc
22
import asyncio
3+
from collections import defaultdict, deque
34
from dataclasses import dataclass
45
from enum import Enum
56
import hashlib
67
import io
78
from pathlib import Path
89
import time
9-
from typing import Optional
10+
from typing import Callable, Optional, TypeVar
1011
import pyzstd as zstd
1112
import aiofiles
1213

@@ -40,7 +41,7 @@ class DownloadReason(Enum):
4041
class BMCLAPIFile:
4142
path: str
4243
hash: str
43-
size: int
44+
size: Optional[int] = None
4445
mtime: int = 0
4546

4647
def __hash__(self):
@@ -88,7 +89,7 @@ def set_data(self, data: io.BytesIO | str | Path):
8889
self.data = data
8990
self.type = FileContentType.PATH
9091

91-
def get_data(self):
92+
def get_data(self) -> io.BytesIO:
9293
if self.compressed:
9394
return io.BytesIO(zstd.decompress(self.data.getbuffer()))
9495
else:
@@ -97,7 +98,7 @@ def is_url(self):
9798
return self.type == FileContentType.URL
9899
def is_path(self):
99100
return self.type == FileContentType.PATH
100-
def get_path(self) -> Path:
101+
def get_path(self) -> Path | str:
101102
return self.data
102103
@dataclass
103104
class StatsCache:
@@ -116,6 +117,13 @@ def __init__(self, name, type: str, width: int) -> None:
116117
self.cache_timer = scheduler.repeat(
117118
self.clear_cache, delay=CHECK_CACHE, interval=CHECK_CACHE
118119
)
120+
121+
def __repr__(self) -> str:
122+
return f"{self.__class__.__name__}(name='{self.name}', type='{self.type}', width='{self.width}', disabled={self.disabled})"
123+
124+
def __str__(self) -> str:
125+
return f"{self.__class__.__name__}(name='{self.name}', type='{self.type}', width='{self.width}', disabled={self.disabled})"
126+
119127
def get_name(self):
120128
return self.name
121129

@@ -169,7 +177,7 @@ def get_cache_stats(self) -> StatsCache:
169177
return stat
170178

171179
@abc.abstractmethod
172-
async def get(self, file: str, start: int = 0, end: Optional[int] = None) -> File:
180+
async def get(self, file: str) -> File:
173181
"""
174182
get file metadata.
175183
return File
@@ -245,6 +253,60 @@ class ResponseRedirects:
245253
status: int
246254
url: str
247255

256+
@dataclass
257+
class StoragesInfo:
258+
total: int = 0
259+
file: int = 0
260+
webdav: int = 0
261+
262+
@dataclass
263+
class StorageWidth:
264+
storage: Storage
265+
width: int = 0
266+
267+
@dataclass
268+
class StorageData:
269+
storage: Storage
270+
hash: str
271+
exists: bool = False
272+
273+
class WeightedStorage:
274+
def __init__(self):
275+
self.queue: deque[StorageWidth] = deque()
276+
277+
def add(self, storage: StorageWidth):
278+
self.queue.appendleft(storage)
279+
280+
async def get(self, hash: str) -> Optional[StorageData]:
281+
async def check(cur: StorageWidth, hash_data: StorageData) -> bool:
282+
if (cur.width > cur.storage.width or cur.storage.disabled) and not hash_data.exists:
283+
cur.width = 0
284+
return False
285+
return True
286+
cur = self.queue[0]
287+
storage_data = StorageData(cur.storage, hash, await cur.storage.exists(hash))
288+
if await check(cur, storage_data):
289+
cur.width += 1
290+
return storage_data
291+
else:
292+
self.queue.rotate(-1)
293+
for _ in range(len(self.queue) - 1):
294+
self.queue.rotate(-1)
295+
storage = self.queue[0]
296+
storage_data = StorageData(storage.storage, hash, await storage.storage.exists(hash))
297+
if await check(storage, storage_data):
298+
storage.width += 1
299+
return storage_data
300+
return storage_data
301+
302+
@dataclass
303+
class DownloadStatistics:
304+
downloaded: int = 0
305+
failed: int = 0
306+
size: int = 0
307+
total: int = 0
308+
total_size: int = 0
309+
248310
def get_hash(org):
249311
if len(org) == 32:
250312
return hashlib.md5()
@@ -258,7 +320,7 @@ def get_hash_content(org, content: io.BytesIO):
258320
else:
259321
h = hashlib.sha1()
260322
h.update(content.getbuffer())
261-
return org == h.hexdigest()
323+
return h.hexdigest()
262324

263325

264326
async def get_file_hash(org: str, path: Path):

0 commit comments

Comments
 (0)