Skip to content

Commit 91b0b26

Browse files
committed
fix: 修复 web 容易被关闭的情况
1 parent b5223bb commit 91b0b26

File tree

6 files changed

+138
-80
lines changed

6 files changed

+138
-80
lines changed

assets/js/index.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
} from './common.js'
1717

1818
import './config.js'
19-
19+
const UTC_OFFSET = 3600 * 8
2020
class Menu extends Element {
2121
constructor() {
2222
super("div").classes("menu-side")
@@ -192,7 +192,6 @@ class Menu extends Element {
192192
this.route_handler_lock?.()
193193
}
194194
}
195-
196195
class Channel {
197196
constructor() {
198197
this.url = window.location.protocol + "//" + window.location.host + "/api";
@@ -309,7 +308,6 @@ class Channel {
309308
return window.__CONFIG__.support.websocket;
310309
}
311310
}
312-
313311
class SwitchElement extends Element {
314312
constructor() {
315313
super("div").classes("switch-container");
@@ -481,7 +479,6 @@ class SwitchElement extends Element {
481479
}
482480
}
483481
}
484-
485482
class FlexElement extends Element {
486483
constructor() {
487484
super("div").classes("flex-container")
@@ -707,7 +704,6 @@ class TemplateEchartElement extends Element {
707704
return this
708705
}
709706
}
710-
711707
const $configuration = new Configuration();
712708
const $ElementManager = new ElementManager();
713709
const $style = new Style($configuration);
@@ -1385,10 +1381,11 @@ async function load() {
13851381
Object.keys(resp).sort((a, b) => parseInt(a) - parseInt(b)).map(v => [v, resp[v]])
13861382
)
13871383
} else {
1384+
console.log(resp)
13881385
var server_time = $dashboard_locals.info_runtime
13891386
// return int((t - ((t + UTC) % 86400) - 86400 * day) / 3600)
13901387
var datetime = server_time.current_time - server_time.diff / 1000.0 + (+new Date() - server_time.resp_timestamp) / 1000.0;
1391-
const previous = (datetime + (datetime % 86400) - 86400 * 29);
1388+
const previous = (datetime + ((datetime + UTC_OFFSET) % 86400) - 86400 * 30);
13921389
const res = {}
13931390
for (let i = 0; i < 30; i++) {
13941391
var d = Tools.formatDate(new Date((previous + i * 86400) * 1000.0))

core/cache.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,21 @@ def __init__(self, value: T, expires: Optional[float] = None) -> None:
2323

2424
# Time out cache
2525
class TimeoutCache(MutableMapping[K, T]):
26-
def __init__(self):
26+
def __init__(self, default_timeout: Optional[float] = None):
2727
self.cache: collections.OrderedDict[K, CacheValue] = collections.OrderedDict()
2828
self.background = BackgroundScheduler()
29+
self.default_timeout = default_timeout
30+
self.background.start()
2931

3032
def set(self, key: K, value: T, timeout: Optional[float] = None) -> None:
3133
self._delete_job(key)
3234
self.cache[key] = CacheValue(
3335
value,
3436
timeout
3537
)
38+
timeout = timeout or self.default_timeout
3639
if timeout is not None:
37-
self.cache[key].job = self.background.add_job(self.delete, 'interval', seconds=timeout, args=[key])
40+
self.cache[key].job = self.background.add_job(self.delete, 'interval', seconds=timeout, args=[key, True])
3841

3942
def _delete_job(self, key: K):
4043
current = self.cache.get(key, None)
@@ -52,7 +55,7 @@ def get(self, key: K, _def: Any = EMPTY) -> Any:
5255
return _def
5356
return current.value
5457

55-
def delete(self, key: K) -> None:
58+
def delete(self, key: K, task: bool = False) -> None:
5659
self._delete_job(key)
5760
self.cache.pop(key, None)
5861

core/config.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"port": -1,
2727
"public_port": 6543,
2828
"x_forwarded_for": 0,
29-
"backlog": 1024
29+
"backlog": 1024,
30+
"sockets": 8
3031
},
3132
"clusters": [
3233
{
@@ -174,10 +175,17 @@ def backlog(self):
174175
if not isinstance(backlog, int):
175176
backlog = 100
176177
return min(backlog, 100)
178+
179+
@property
180+
def web_sockets(self):
181+
sockets = Config.get("web.sockets", 8)
182+
if not isinstance(sockets, int):
183+
sockets = 8
184+
return min(sockets, 1)
177185

178186
const = Const()
179187

180-
VERSION = "3.3.10"
188+
VERSION = "3.3.11"
181189
API_VERSION = "1.13.1"
182190
USER_AGENT = f"openbmclapi/{API_VERSION} python-openbmclapi/{VERSION}"
183191
PYTHON_VERSION = ".".join(map(str, (sys.version_info.major, sys.version_info.minor, sys.version_info.micro)))

core/storages/__init__.py

Lines changed: 88 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import abc
22
import asyncio
3-
from collections import deque
3+
from collections import defaultdict, deque
44
from dataclasses import dataclass, field
55
import hashlib
66
import inspect
@@ -109,17 +109,19 @@ def __rtruediv__(self, __o: Any) -> 'FilePath':
109109

110110
class iStorage(metaclass=abc.ABCMeta):
111111
type: str = "_interface"
112-
def __init__(self, path: str, weight: int = 0, list_concurrent: int = 32):
112+
def __init__(
113+
self,
114+
path: str,
115+
weight: int = 0,
116+
list_concurrent: int = 32,
117+
name: Optional[str] = None
118+
):
113119
self.path = FilePath(path)
114120
self.weight = weight
115121
self.list_concurrent = list_concurrent
116122
self.current_weight = 0
123+
self._name = name
117124

118-
@staticmethod
119-
@abc.abstractmethod
120-
def from_config(config: dict[str, Any]):
121-
raise NotImplementedError("from_config not implemented")
122-
123125
@property
124126
@abc.abstractmethod
125127
def unique_id(self):
@@ -165,16 +167,13 @@ def get_path(self, file: CollectionFile):
165167
class LocalStorage(iStorage):
166168
type = "local"
167169

168-
def __init__(self, path: str, weight: int = 0, list_concurrent: int = 32):
169-
super().__init__(path, weight, list_concurrent)
170+
def __init__(self, path: str, weight: int = 0, list_concurrent: int = 32, name: Optional[str] = None):
171+
super().__init__(path, weight, list_concurrent, name)
170172
self.async_executor = ThreadPoolExecutor(max_workers=list_concurrent)
171173

172174
@staticmethod
173175
def from_config(config: dict[str, Any]):
174-
path = config["path"]
175-
weight = config.get("weight", 0)
176-
list_concurrent = config.get("list_concurrent", 32)
177-
return LocalStorage(path, weight, list_concurrent)
176+
return LocalStorage(config["path"], config.get("weight", 0), config.get("list_concurrent", 32), config.get("name"))
178177

179178
@property
180179
def unique_id(self):
@@ -239,13 +238,22 @@ async def get_mtime(self, file: CollectionFile) -> float:
239238
return os.path.getmtime(Path(str(path)))
240239

241240
class iNetworkStorage(iStorage):
242-
243-
def __init__(self, path: str, username: str, password: str, endpoint: str, weight: int = 0, list_concurrent: int = 32):
244-
super().__init__(path, weight, list_concurrent)
241+
def __init__(
242+
self,
243+
path: str,
244+
username: str,
245+
password: str,
246+
endpoint: str,
247+
weight: int = 0,
248+
list_concurrent: int = 32,
249+
name: Optional[str] = None,
250+
cache_timeout: float = 60,
251+
):
252+
super().__init__(path, weight, list_concurrent, name)
245253
self.username = username
246254
self.password = password
247255
self.endpoint = endpoint.rstrip("/")
248-
self.cache = cache.TimeoutCache()
256+
self.cache = cache.TimeoutCache(cache_timeout)
249257

250258
@property
251259
def unique_id(self):
@@ -280,8 +288,20 @@ def __init__(self, result: AlistResult):
280288
class AlistStorage(iNetworkStorage):
281289
type = "alist"
282290

283-
def __init__(self, path: str, username: str, password: str, endpoint: str, weight: int = 0, list_concurrent: int = 32, retries: int = 3, public_webdav_endpoint: str = ""):
284-
super().__init__(path, username, password, endpoint, weight, list_concurrent)
291+
def __init__(
292+
self,
293+
path: str,
294+
username: str,
295+
password: str,
296+
endpoint: str,
297+
weight: int = 0,
298+
list_concurrent: int = 32,
299+
name: Optional[str] = None,
300+
cache_timeout: float = 60,
301+
retries: int = 3,
302+
public_webdav_endpoint: str = ""
303+
):
304+
super().__init__(path, username, password, endpoint, weight, list_concurrent, name, cache_timeout)
285305
self.retries = retries
286306
self.last_token: Optional[AlistToken] = None
287307
self.session = aiohttp.ClientSession(
@@ -293,18 +313,6 @@ def __init__(self, path: str, username: str, password: str, endpoint: str, weigh
293313
urlobject = urlparse.urlparse(public_webdav_endpoint)
294314
self._public_webdav_endpoint = f"{urlobject.scheme}://{urlparse.quote(self.username)}:{urlparse.quote(self.password)}@{urlobject.netloc}{urlobject.path}"
295315

296-
@staticmethod
297-
def from_config(config: dict[str, Any]):
298-
path = config["path"]
299-
username = config["username"]
300-
password = config["password"]
301-
endpoint = config["endpoint"]
302-
weight = config.get("weight", 0)
303-
list_concurrent = config.get("list_concurrent", 32)
304-
retries = config.get("retries", 3)
305-
public_webdav_endpoint = config.get("public_webdav_endpoint", "")
306-
return AlistStorage(path, username, password, endpoint, weight, list_concurrent, retries, public_webdav_endpoint)
307-
308316
async def _get_token(self):
309317
if self.last_token is None or self.last_token.expires < time.monotonic():
310318
async with self.session.post(f"{self.endpoint}/api/auth/login", json={"username": self.username, "password": self.password}) as resp:
@@ -516,8 +524,20 @@ def data_size(self) -> int:
516524

517525
class WebDavStorage(iNetworkStorage):
518526
type = "webdav"
519-
def __init__(self, path: str, username: str, password: str, endpoint: str, weight: int = 0, list_concurrent: int = 32, public_endpoint: str = "", retries: int = 3):
520-
super().__init__(path, username, password, endpoint, weight, list_concurrent)
527+
def __init__(
528+
self,
529+
path: str,
530+
username: str,
531+
password: str,
532+
endpoint: str,
533+
weight: int = 0,
534+
list_concurrent: int = 32,
535+
name: Optional[str] = None,
536+
cache_timeout: int = 60,
537+
public_endpoint: str = "",
538+
retries: int = 3
539+
):
540+
super().__init__(path, username, password, endpoint, weight, list_concurrent, name, cache_timeout)
521541
self.client = webdav3_client.Client({
522542
"webdav_hostname": endpoint,
523543
"webdav_login": username,
@@ -536,18 +556,6 @@ def __init__(self, path: str, username: str, password: str, endpoint: str, weigh
536556
self.base_url = f"{urlobject.scheme}://{urlparse.quote(self.username)}:{urlparse.quote(self.password)}@{urlobject.hostname}:{urlobject.port}{urlobject.path}"
537557
self.retries = retries
538558

539-
@staticmethod
540-
def from_config(config: dict[str, Any]):
541-
path = config["path"]
542-
username = config["username"]
543-
password = config["password"]
544-
endpoint = config["endpoint"]
545-
weight = config.get("weight", 0)
546-
list_concurrent = config.get("list_concurrent", 32)
547-
public_endpoint = config.get("public_endpoint", "")
548-
retries = config.get("retries", 3)
549-
return WebDavStorage(path, username, password, endpoint, weight, list_concurrent, public_endpoint, retries)
550-
551559
async def list_files(self, pbar: WrapperTQDM) -> set[File]:
552560
async def get_files(root_id: int) -> list[WebDavFileInfo]:
553561
root = self.path / DOWNLOAD_DIR / f"{root_id:02x}"
@@ -670,16 +678,32 @@ async def write_file(self, file: MeasureFile | File, content: io.BytesIO):
670678
return True
671679

672680

681+
@dataclass
682+
class Parameter:
683+
name: str
684+
type: type
685+
default: Any = inspect._empty
686+
673687
def init_storage(config: Any) -> Optional[iStorage]:
674688
if not isinstance(config, dict) or "type" not in config or config["type"] not in abstract_storages:
675689
return None
676690
try:
677-
return abstract_storages[config["type"]].from_config(config)
691+
abstract_storage = abstract_storages[config["type"]]
692+
args = abstract_storage_args[abstract_storage]
693+
params = {}
694+
for arg in args:
695+
if arg.name in config:
696+
params[arg.name] = config[arg.name]
697+
elif arg.default != inspect._empty:
698+
params[arg.name] = arg.default
699+
700+
return abstract_storage(**params)
678701
except:
679702
logger.traceback()
680703
return None
681704

682705
abstract_storages: dict[str, type[iStorage]] = {}
706+
abstract_storage_args: defaultdict[type[iStorage], list[Parameter]] = defaultdict(list)
683707

684708
T = TypeVar("T")
685709

@@ -695,6 +719,24 @@ async def init():
695719
if istorage.type == iStorage.type:
696720
continue
697721
abstract_storages[istorage.type] = istorage
722+
arg = inspect.getfullargspec(istorage.__init__)
723+
args = arg.args[1:]
724+
# defaults 默认的长度和位置都是从后往前数的,
725+
# 填充一些空的在前面
726+
defaults = [
727+
inspect._empty for _ in range(len(args) - len(arg.defaults or []))
728+
]
729+
defaults.extend(arg.defaults or [])
730+
for idx, arg_name in enumerate(args):
731+
if arg_name == "self":
732+
continue
733+
abstract_storage_args[istorage].append(
734+
Parameter(
735+
name=arg_name,
736+
type=arg.annotations.get(arg_name, Any),
737+
default=defaults[idx]
738+
)
739+
)
698740

699741
logger.debug("Storage init complete")
700742
logger.debug(f"Found {len(abstract_storages)} storage types: {', '.join(abstract_storages.keys())}")

0 commit comments

Comments
 (0)