From 0ff1b41c41275d9d7cef5c0b7a23c64fbbe875b9 Mon Sep 17 00:00:00 2001 From: lettimepassby <86416409@qq.com> Date: Wed, 8 Jul 2026 16:04:20 +0800 Subject: [PATCH] perf: locate replay in terminal's configured storage first when playing --- apps/common/storage/base.py | 60 +++++++++++++++++++++-------------- apps/common/storage/replay.py | 35 +++++++++++++++++--- 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/apps/common/storage/base.py b/apps/common/storage/base.py index 326990052..fba7b4458 100644 --- a/apps/common/storage/base.py +++ b/apps/common/storage/base.py @@ -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() diff --git a/apps/common/storage/replay.py b/apps/common/storage/replay.py index f76d59fde..942fe8555 100644 --- a/apps/common/storage/replay.py +++ b/apps/common/storage/replay.py @@ -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)