mirror of
https://github.com/langgenius/dify.git
synced 2026-04-19 18:27:27 +08:00
feat: support STORAGE_PATH_PREFIX for global storage key namespacing
Add STORAGE_PATH_PREFIX config field and apply prefix in Storage wrapper for all operations (save, load, download, exists, delete, scan). Scan strips prefix from results to prevent double-prefixing. Aliyun OSS disables its own folder prefix when STORAGE_PATH_PREFIX is set.
This commit is contained in:
@ -74,6 +74,11 @@ class StorageConfig(BaseSettings):
|
||||
default="opendal",
|
||||
)
|
||||
|
||||
STORAGE_PATH_PREFIX: str = Field(
|
||||
description="Global path prefix prepended to all storage object keys.",
|
||||
default="",
|
||||
)
|
||||
|
||||
STORAGE_LOCAL_PATH: str = Field(
|
||||
description="Path for local storage when STORAGE_TYPE is set to 'local'.",
|
||||
default="storage",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import logging
|
||||
import posixpath
|
||||
from collections.abc import Callable, Generator
|
||||
from typing import Literal, Union, overload
|
||||
|
||||
@ -17,6 +18,15 @@ class Storage:
|
||||
storage_factory = self.get_storage_factory(dify_config.STORAGE_TYPE)
|
||||
with app.app_context():
|
||||
self.storage_runner = storage_factory()
|
||||
prefix = dify_config.STORAGE_PATH_PREFIX.strip("/") if dify_config.STORAGE_PATH_PREFIX else ""
|
||||
if prefix and ".." in prefix.split("/"):
|
||||
raise ValueError(f"STORAGE_PATH_PREFIX must not contain '..': {dify_config.STORAGE_PATH_PREFIX}")
|
||||
self._path_prefix = prefix
|
||||
|
||||
def _prefix(self, filename: str) -> str:
|
||||
if not self._path_prefix:
|
||||
return filename
|
||||
return posixpath.join(self._path_prefix, filename)
|
||||
|
||||
@staticmethod
|
||||
def get_storage_factory(storage_type: str) -> Callable[[], BaseStorage]:
|
||||
@ -86,7 +96,7 @@ class Storage:
|
||||
raise ValueError(f"unsupported storage type {storage_type}")
|
||||
|
||||
def save(self, filename: str, data: bytes):
|
||||
self.storage_runner.save(filename, data)
|
||||
self.storage_runner.save(self._prefix(filename), data)
|
||||
|
||||
@overload
|
||||
def load(self, filename: str, /, *, stream: Literal[False] = False) -> bytes: ...
|
||||
@ -105,22 +115,26 @@ class Storage:
|
||||
return self.load_once(filename)
|
||||
|
||||
def load_once(self, filename: str) -> bytes:
|
||||
return self.storage_runner.load_once(filename)
|
||||
return self.storage_runner.load_once(self._prefix(filename))
|
||||
|
||||
def load_stream(self, filename: str) -> Generator:
|
||||
return self.storage_runner.load_stream(filename)
|
||||
return self.storage_runner.load_stream(self._prefix(filename))
|
||||
|
||||
def download(self, filename, target_filepath):
|
||||
self.storage_runner.download(filename, target_filepath)
|
||||
self.storage_runner.download(self._prefix(filename), target_filepath)
|
||||
|
||||
def exists(self, filename):
|
||||
return self.storage_runner.exists(filename)
|
||||
return self.storage_runner.exists(self._prefix(filename))
|
||||
|
||||
def delete(self, filename: str):
|
||||
return self.storage_runner.delete(filename)
|
||||
return self.storage_runner.delete(self._prefix(filename))
|
||||
|
||||
def scan(self, path: str, files: bool = True, directories: bool = False) -> list[str]:
|
||||
return self.storage_runner.scan(path, files=files, directories=directories)
|
||||
results = self.storage_runner.scan(self._prefix(path), files=files, directories=directories)
|
||||
if not self._path_prefix:
|
||||
return results
|
||||
prefix_with_slash = self._path_prefix + "/"
|
||||
return [r[len(prefix_with_slash):] if r.startswith(prefix_with_slash) else r for r in results]
|
||||
|
||||
|
||||
storage = Storage()
|
||||
|
||||
@ -13,7 +13,7 @@ class AliyunOssStorage(BaseStorage):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.bucket_name = dify_config.ALIYUN_OSS_BUCKET_NAME
|
||||
self.folder = dify_config.ALIYUN_OSS_PATH
|
||||
self.folder = None if dify_config.STORAGE_PATH_PREFIX else dify_config.ALIYUN_OSS_PATH
|
||||
oss_auth_method = aliyun_s3.Auth
|
||||
region = None
|
||||
if dify_config.ALIYUN_OSS_AUTH_VERSION == "v4":
|
||||
|
||||
Reference in New Issue
Block a user