perf: locate replay in terminal's configured storage first when playing

This commit is contained in:
lettimepassby
2026-07-08 16:04:20 +08:00
committed by Eric_Lee
parent dfe1f11c92
commit 0ff1b41c41
2 changed files with 67 additions and 28 deletions

View File

@@ -10,7 +10,7 @@ from terminal.models import ReplayStorage
logger = get_logger(__name__)
def get_multi_object_storage():
def get_multi_object_storage(name=None):
replay_storages = ReplayStorage.objects.all()
configs = {}
for storage in replay_storages:
@@ -21,6 +21,9 @@ def get_multi_object_storage():
configs[storage.name] = storage.config
if settings.SERVER_REPLAY_STORAGE:
configs['SERVER_REPLAY_STORAGE'] = settings.SERVER_REPLAY_STORAGE
# 指定存储名时仅构造该存储, 用于优先直连文件所在的存储, 避免遍历探测
if name is not None:
configs = {name: configs[name]} if name in configs else {}
if not configs:
return None
storage = jms_storage.get_multi_object_storage(configs)
@@ -40,31 +43,42 @@ class BaseStorageHandler(object):
def find_local(self):
raise NotImplementedError
def get_preferred_storage_name(self):
# 文件优先查找的存储名, 返回 None 表示直接遍历所有存储
return None
def download(self):
storage = get_multi_object_storage()
if not storage:
# 优先只查文件所属的存储, 未指定或未命中时回退遍历所有存储
preferred = self.get_preferred_storage_name()
storage_names = [preferred, None] if preferred else [None]
msg, found_storage = '', False
for name in storage_names:
storage = get_multi_object_storage(name)
if not storage:
continue
found_storage = True
remote_path, local_path = self.get_file_path(storage=storage)
if not remote_path:
msg = f'Not found {self.NAME} file'
continue
# 保存到storage的路径
target_path = os.path.join(default_storage.base_location, local_path)
target_dir = os.path.dirname(target_path)
if not os.path.isdir(target_dir):
make_dirs(target_dir, exist_ok=True)
ok, err = storage.download(remote_path, target_path)
if ok:
url = default_storage.url(local_path)
return local_path, url
msg = f'Failed download {self.NAME} file: {err}'
if not found_storage:
msg = f"Not found {self.NAME} file, and not remote storage set"
return None, msg
remote_path, local_path = self.get_file_path(storage=storage)
if not remote_path:
msg = f'Not found {self.NAME} file'
logger.error(msg)
return None, msg
# 保存到storage的路径
target_path = os.path.join(default_storage.base_location, local_path)
target_dir = os.path.dirname(target_path)
if not os.path.isdir(target_dir):
make_dirs(target_dir, exist_ok=True)
ok, err = storage.download(remote_path, target_path)
if not ok:
msg = f'Failed download {self.NAME} file: {err}'
logger.error(msg)
return None, msg
url = default_storage.url(local_path)
return local_path, url
logger.error(msg)
return None, msg
def get_file_path_url(self):
local_path, url = self.find_local()

View File

@@ -14,9 +14,24 @@ from .base import BaseStorageHandler, get_multi_object_storage
logger = get_logger(__name__)
def get_session_preferred_storage_name(session):
"""
会话所属终端(组件)配置的录像存储名, 录像大概率上传在该存储上, 优先在其中查找
terminal 可能已被删除 (on_delete=DO_NOTHING), 取不到时返回 None 表示无优先存储
"""
try:
terminal = session.terminal
except Exception:
return None
return terminal.replay_storage if terminal else None
class ReplayStorageHandler(BaseStorageHandler):
NAME = 'REPLAY'
def get_preferred_storage_name(self):
return get_session_preferred_storage_name(self.obj)
def get_file_path(self, **kwargs):
storage = kwargs['storage']
# 获取外部存储路径名
@@ -55,10 +70,6 @@ class SessionPartReplayStorageHandler(object):
return None, '{} not found.'.format(part_filename)
def download_part_file(self, part_filename):
storage = get_multi_object_storage()
if not storage:
msg = "Not found {} file, and not remote storage set".format(part_filename)
return None, msg
local_path = self.obj.get_replay_part_file_local_storage_path(part_filename)
remote_path = self.obj.get_replay_part_file_relative_path(part_filename)
@@ -69,7 +80,21 @@ class SessionPartReplayStorageHandler(object):
if not os.path.isdir(target_dir):
make_dirs(target_dir, exist_ok=True)
ok, err = storage.download(remote_path, target_tmp_path)
# 优先只查所属终端配置的存储, 未配置或未命中时回退遍历所有存储
preferred = get_session_preferred_storage_name(self.obj)
storage_names = [preferred, None] if preferred else [None]
ok, err, found_storage = False, None, False
for name in storage_names:
storage = get_multi_object_storage(name)
if not storage:
continue
found_storage = True
ok, err = storage.download(remote_path, target_tmp_path)
if ok:
break
if not found_storage:
msg = "Not found {} file, and not remote storage set".format(part_filename)
return None, msg
if not ok:
msg = 'Failed download {} file: {}'.format(part_filename, err)
logger.error(msg)