tamar-file-hub-client 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. file_hub_client/__init__.py +88 -0
  2. file_hub_client/client.py +414 -0
  3. file_hub_client/enums/__init__.py +12 -0
  4. file_hub_client/enums/export_format.py +16 -0
  5. file_hub_client/enums/role.py +7 -0
  6. file_hub_client/enums/upload_mode.py +11 -0
  7. file_hub_client/errors/__init__.py +30 -0
  8. file_hub_client/errors/exceptions.py +93 -0
  9. file_hub_client/py.typed +1 -0
  10. file_hub_client/rpc/__init__.py +10 -0
  11. file_hub_client/rpc/async_client.py +312 -0
  12. file_hub_client/rpc/gen/__init__.py +1 -0
  13. file_hub_client/rpc/gen/file_service_pb2.py +74 -0
  14. file_hub_client/rpc/gen/file_service_pb2_grpc.py +533 -0
  15. file_hub_client/rpc/gen/folder_service_pb2.py +53 -0
  16. file_hub_client/rpc/gen/folder_service_pb2_grpc.py +269 -0
  17. file_hub_client/rpc/generate_grpc.py +76 -0
  18. file_hub_client/rpc/protos/file_service.proto +147 -0
  19. file_hub_client/rpc/protos/folder_service.proto +65 -0
  20. file_hub_client/rpc/sync_client.py +313 -0
  21. file_hub_client/schemas/__init__.py +43 -0
  22. file_hub_client/schemas/context.py +160 -0
  23. file_hub_client/schemas/file.py +89 -0
  24. file_hub_client/schemas/folder.py +29 -0
  25. file_hub_client/services/__init__.py +17 -0
  26. file_hub_client/services/file/__init__.py +14 -0
  27. file_hub_client/services/file/async_blob_service.py +482 -0
  28. file_hub_client/services/file/async_file_service.py +257 -0
  29. file_hub_client/services/file/base_file_service.py +103 -0
  30. file_hub_client/services/file/sync_blob_service.py +478 -0
  31. file_hub_client/services/file/sync_file_service.py +255 -0
  32. file_hub_client/services/folder/__init__.py +10 -0
  33. file_hub_client/services/folder/async_folder_service.py +206 -0
  34. file_hub_client/services/folder/sync_folder_service.py +205 -0
  35. file_hub_client/utils/__init__.py +48 -0
  36. file_hub_client/utils/converter.py +108 -0
  37. file_hub_client/utils/download_helper.py +355 -0
  38. file_hub_client/utils/file_utils.py +105 -0
  39. file_hub_client/utils/retry.py +69 -0
  40. file_hub_client/utils/upload_helper.py +527 -0
  41. tamar_file_hub_client-0.0.1.dist-info/METADATA +874 -0
  42. tamar_file_hub_client-0.0.1.dist-info/RECORD +44 -0
  43. tamar_file_hub_client-0.0.1.dist-info/WHEEL +5 -0
  44. tamar_file_hub_client-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,88 @@
1
+ """
2
+ 文件管理系统客户端SDK
3
+
4
+ 一个基于gRPC的文件管理系统Python客户端SDK,支持:
5
+ - 文件和文件夹的增删改查
6
+ - 多种上传模式(普通上传、断点续传、流式上传、客户端直传)
7
+ - 传统文件类型和自定义文件类型
8
+ - 文件导出(将自定义文件类型导出为传统格式)
9
+ - 直接操作对象存储
10
+ - 同时支持同步和异步API
11
+ """
12
+
13
+ from .client import (
14
+ AsyncTamarFileHubClient,
15
+ TamarFileHubClient,
16
+ tamar_client, # 默认的同步客户端单例
17
+ async_tamar_client, # 默认的异步客户端单例
18
+ get_client, # 获取同步客户端单例的函数
19
+ get_async_client, # 获取异步客户端单例的函数
20
+ )
21
+
22
+ from .enums import Role, UploadMode, ExportFormat
23
+ from .errors import (
24
+ FileHubError,
25
+ FileNotFoundError,
26
+ FolderNotFoundError,
27
+ UploadError,
28
+ DownloadError,
29
+ ExportError,
30
+ StorageError,
31
+ ValidationError,
32
+ ConnectionError,
33
+ TimeoutError,
34
+ PermissionError,
35
+ )
36
+ from .schemas import (
37
+ File,
38
+ UploadUrlResponse,
39
+ ShareLinkRequest,
40
+ FileVisitRequest,
41
+ FileListRequest,
42
+ FileListResponse,
43
+ FolderInfo,
44
+ FolderListResponse,
45
+ UserContext,
46
+ RequestContext,
47
+ FullContext,
48
+ )
49
+
50
+ __all__ = [
51
+ # 客户端
52
+ "AsyncTamarFileHubClient",
53
+ "TamarFileHubClient",
54
+ "tamar_client", # 默认同步客户端单例
55
+ "async_tamar_client", # 默认异步客户端单例
56
+ "get_client",
57
+ "get_async_client",
58
+
59
+ # 文件相关模型
60
+ "File",
61
+ "UploadUrlResponse",
62
+ "ShareLinkRequest",
63
+ "FileVisitRequest",
64
+ "FileListRequest",
65
+ "FileListResponse",
66
+
67
+ # 文件夹相关模型
68
+ "FolderInfo",
69
+ "FolderListResponse",
70
+
71
+ # 枚举
72
+ "Role",
73
+ "UploadMode",
74
+ "ExportFormat",
75
+
76
+ # 异常
77
+ "FileHubError",
78
+ "FileNotFoundError",
79
+ "FolderNotFoundError",
80
+ "UploadError",
81
+ "DownloadError",
82
+ "ExportError",
83
+ "StorageError",
84
+ "ValidationError",
85
+ "ConnectionError",
86
+ "TimeoutError",
87
+ "PermissionError",
88
+ ]
@@ -0,0 +1,414 @@
1
+ """
2
+ 文件管理系统客户端
3
+
4
+ 提供与文件管理系统交互的客户端接口
5
+ """
6
+ import os
7
+ import threading
8
+ from asyncio import Lock
9
+ from typing import Optional, Dict
10
+
11
+ from .enums import Role
12
+ from .rpc.async_client import AsyncGrpcClient
13
+ from .rpc.sync_client import SyncGrpcClient
14
+ from .services import (
15
+ AsyncBlobService,
16
+ AsyncFileService,
17
+ AsyncFolderService,
18
+ SyncBlobService,
19
+ SyncFileService,
20
+ SyncFolderService,
21
+ )
22
+ from .schemas.context import UserContext, RequestContext
23
+
24
+
25
+ class AsyncTamarFileHubClient:
26
+ """异步文件管理系统客户端"""
27
+
28
+ def __init__(
29
+ self,
30
+ host: Optional[str] = None,
31
+ port: Optional[int] = None,
32
+ secure: Optional[bool] = None,
33
+ credentials: Optional[dict] = None,
34
+ auto_connect: bool = True,
35
+ retry_count: Optional[int] = None,
36
+ retry_delay: Optional[float] = None,
37
+ default_metadata: Optional[Dict[str, str]] = None,
38
+ user_context: Optional[UserContext] = None,
39
+ request_context: Optional[RequestContext] = None,
40
+ ):
41
+ """
42
+ 初始化客户端
43
+
44
+ Args:
45
+ host: 服务器地址(默认从环境变量 FILE_HUB_HOST 读取,否则使用 localhost)
46
+ port: 服务器端口(默认从环境变量 FILE_HUB_PORT 读取,否则使用 50051)
47
+ secure: 是否使用TLS(默认从环境变量 FILE_HUB_SECURE 读取,否则使用 False)
48
+ credentials: 认证凭据
49
+ auto_connect: 是否自动连接(默认 True)
50
+ retry_count: 连接重试次数(默认从环境变量 FILE_HUB_RETRY_COUNT 读取,否则使用 3)
51
+ retry_delay: 重试延迟秒数(默认从环境变量 FILE_HUB_RETRY_DELAY 读取,否则使用 1.0)
52
+ default_metadata: 默认的元数据(如 org_id, user_id 等)
53
+ user_context: 用户上下文
54
+ request_context: 请求上下文
55
+
56
+ 环境变量:
57
+ FILE_HUB_HOST: gRPC 服务器地址
58
+ FILE_HUB_PORT: gRPC 服务器端口
59
+ FILE_HUB_SECURE: 是否启用 TLS(true/false)
60
+ FILE_HUB_API_KEY: API 密钥(如果需要)
61
+ FILE_HUB_RETRY_COUNT: 连接重试次数
62
+ FILE_HUB_RETRY_DELAY: 重试延迟(秒)
63
+ """
64
+ # 从环境变量或参数获取配置
65
+ self._host = host or os.getenv('FILE_HUB_HOST', 'localhost')
66
+ self._port = port or int(os.getenv('FILE_HUB_PORT', '50051'))
67
+ self._secure = secure if secure is not None else os.getenv('FILE_HUB_SECURE', 'false').lower() == 'true'
68
+ self._retry_count = retry_count or int(os.getenv('FILE_HUB_RETRY_COUNT', '3'))
69
+ self._retry_delay = retry_delay or float(os.getenv('FILE_HUB_RETRY_DELAY', '1.0'))
70
+ self._connect_lock = Lock()
71
+
72
+ # 处理认证凭据
73
+ if credentials is None and os.getenv('FILE_HUB_API_KEY'):
74
+ credentials = {'api_key': os.getenv('FILE_HUB_API_KEY')}
75
+
76
+ # 处理默认元数据
77
+ if default_metadata is None:
78
+ default_metadata = {}
79
+
80
+ self._client = AsyncGrpcClient(
81
+ self._host,
82
+ self._port,
83
+ self._secure,
84
+ credentials,
85
+ retry_count=self._retry_count,
86
+ retry_delay=self._retry_delay,
87
+ default_metadata=default_metadata,
88
+ user_context=user_context,
89
+ request_context=request_context,
90
+ )
91
+ self._blob_service = None
92
+ self._file_service = None
93
+ self._folder_service = None
94
+ self._auto_connect = auto_connect
95
+ self._connected = False
96
+
97
+ async def _ensure_connected(self):
98
+ """确保客户端已连接"""
99
+ if not self._connected and self._auto_connect:
100
+ await self.connect()
101
+
102
+ @property
103
+ def blobs(self) -> AsyncBlobService:
104
+ """获取文件服务"""
105
+ if self._blob_service is None:
106
+ self._blob_service = AsyncBlobService(self._client)
107
+ return self._blob_service
108
+
109
+ @property
110
+ def files(self) -> AsyncFileService:
111
+ """获取文件服务"""
112
+ if self._file_service is None:
113
+ self._file_service = AsyncFileService(self._client)
114
+ return self._file_service
115
+
116
+ @property
117
+ def folders(self) -> AsyncFolderService:
118
+ """获取文件夹服务"""
119
+ if self._folder_service is None:
120
+ self._folder_service = AsyncFolderService(self._client)
121
+ return self._folder_service
122
+
123
+ def set_user_context(self, org_id: str, user_id: str, role: Role = Role.ACCOUNT, actor_id: Optional[str] = None):
124
+ """
125
+ 设置用户上下文信息
126
+
127
+ Args:
128
+ org_id: 组织ID
129
+ user_id: 用户ID
130
+ role: 用户角色(默认为 ACCOUNT)
131
+ actor_id: 操作者ID(如果不同于 user_id)
132
+ """
133
+ self._client.set_user_context(org_id, user_id, role, actor_id)
134
+
135
+ def get_user_context(self) -> Optional[UserContext]:
136
+ """获取当前用户上下文"""
137
+ return self._client.get_user_context()
138
+
139
+ def clear_user_context(self):
140
+ """清除用户上下文信息"""
141
+ self._client.clear_user_context()
142
+
143
+ def set_request_context(self, request_context: RequestContext):
144
+ """设置请求上下文"""
145
+ self._client.set_request_context(request_context)
146
+
147
+ def get_request_context(self) -> RequestContext:
148
+ """获取当前请求上下文"""
149
+ return self._client.get_request_context()
150
+
151
+ def update_request_context(self, **kwargs):
152
+ """
153
+ 更新请求上下文的部分字段
154
+
155
+ Args:
156
+ client_ip: 客户端IP地址
157
+ client_version: 客户端版本
158
+ client_type: 客户端类型
159
+ user_agent: User-Agent信息
160
+ extra: 额外的元数据字典
161
+ """
162
+ self._client.update_request_context(**kwargs)
163
+
164
+ def update_metadata(self, **kwargs):
165
+ """
166
+ 更新默认元数据
167
+
168
+ Args:
169
+ **kwargs: 要更新的元数据键值对
170
+ """
171
+ self._client.update_default_metadata(**kwargs)
172
+
173
+ async def connect(self):
174
+ """连接到服务器"""
175
+ if not self._connected:
176
+ async with self._connect_lock:
177
+ if not self._connected:
178
+ await self._client.connect()
179
+ self._connected = True
180
+
181
+ async def close(self):
182
+ """关闭连接"""
183
+ if self._connected:
184
+ await self._client.close()
185
+ self._connected = False
186
+
187
+ async def __aenter__(self) -> "AsyncTamarFileHubClient":
188
+ await self._ensure_connected()
189
+ return self
190
+
191
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
192
+ await self.close()
193
+
194
+
195
+ class TamarFileHubClient:
196
+ """同步文件管理系统客户端"""
197
+
198
+ def __init__(
199
+ self,
200
+ host: Optional[str] = None,
201
+ port: Optional[int] = None,
202
+ secure: Optional[bool] = None,
203
+ credentials: Optional[dict] = None,
204
+ auto_connect: bool = True,
205
+ retry_count: Optional[int] = None,
206
+ retry_delay: Optional[float] = None,
207
+ default_metadata: Optional[Dict[str, str]] = None,
208
+ user_context: Optional[UserContext] = None,
209
+ request_context: Optional[RequestContext] = None,
210
+ ):
211
+ """
212
+ 初始化客户端
213
+
214
+ Args:
215
+ host: 服务器地址(默认从环境变量 FILE_HUB_HOST 读取,否则使用 localhost)
216
+ port: 服务器端口(默认从环境变量 FILE_HUB_PORT 读取,否则使用 50051)
217
+ secure: 是否使用TLS(默认从环境变量 FILE_HUB_SECURE 读取,否则使用 False)
218
+ credentials: 认证凭据
219
+ auto_connect: 是否自动连接(默认 True)
220
+ retry_count: 连接重试次数(默认从环境变量 FILE_HUB_RETRY_COUNT 读取,否则使用 3)
221
+ retry_delay: 重试延迟秒数(默认从环境变量 FILE_HUB_RETRY_DELAY 读取,否则使用 1.0)
222
+ default_metadata: 默认的元数据(如 org_id, user_id 等)
223
+ user_context: 用户上下文
224
+ request_context: 请求上下文
225
+
226
+ 环境变量:
227
+ FILE_HUB_HOST: gRPC 服务器地址
228
+ FILE_HUB_PORT: gRPC 服务器端口
229
+ FILE_HUB_SECURE: 是否启用 TLS(true/false)
230
+ FILE_HUB_API_KEY: API 密钥(如果需要)
231
+ FILE_HUB_RETRY_COUNT: 连接重试次数
232
+ FILE_HUB_RETRY_DELAY: 重试延迟(秒)
233
+ """
234
+ # 从环境变量或参数获取配置
235
+ self._host = host or os.getenv('FILE_HUB_HOST', 'localhost')
236
+ self._port = port or int(os.getenv('FILE_HUB_PORT', '50051'))
237
+ self._secure = secure if secure is not None else os.getenv('FILE_HUB_SECURE', 'false').lower() == 'true'
238
+ self._retry_count = retry_count or int(os.getenv('FILE_HUB_RETRY_COUNT', '3'))
239
+ self._retry_delay = retry_delay or float(os.getenv('FILE_HUB_RETRY_DELAY', '1.0'))
240
+ self._connect_lock = threading.Lock()
241
+
242
+ # 处理认证凭据
243
+ if credentials is None and os.getenv('FILE_HUB_API_KEY'):
244
+ credentials = {'api_key': os.getenv('FILE_HUB_API_KEY')}
245
+
246
+ # 处理默认元数据
247
+ if default_metadata is None:
248
+ default_metadata = {}
249
+
250
+ self._client = SyncGrpcClient(
251
+ self._host,
252
+ self._port,
253
+ self._secure,
254
+ credentials,
255
+ retry_count=self._retry_count,
256
+ retry_delay=self._retry_delay,
257
+ default_metadata=default_metadata,
258
+ user_context=user_context,
259
+ request_context=request_context,
260
+ )
261
+ self._blob_service = None
262
+ self._file_service = None
263
+ self._folder_service = None
264
+ self._auto_connect = auto_connect
265
+ self._connected = False
266
+
267
+ def _ensure_connected(self):
268
+ """确保客户端已连接"""
269
+ if not self._connected and self._auto_connect:
270
+ self.connect()
271
+
272
+ @property
273
+ def blobs(self) -> SyncBlobService:
274
+ """获取文件服务"""
275
+ self._ensure_connected()
276
+ if self._blob_service is None:
277
+ self._blob_service = SyncBlobService(self._client)
278
+ return self._blob_service
279
+
280
+ @property
281
+ def files(self) -> SyncFileService:
282
+ """获取文件服务"""
283
+ self._ensure_connected()
284
+ if self._file_service is None:
285
+ self._file_service = SyncFileService(self._client)
286
+ return self._file_service
287
+
288
+ @property
289
+ def folders(self) -> SyncFolderService:
290
+ """获取文件夹服务"""
291
+ self._ensure_connected()
292
+ if self._folder_service is None:
293
+ self._folder_service = SyncFolderService(self._client)
294
+ return self._folder_service
295
+
296
+ def set_user_context(self, org_id: str, user_id: str, role: Role = Role.ACCOUNT, actor_id: Optional[str] = None):
297
+ """
298
+ 设置用户上下文信息
299
+
300
+ Args:
301
+ org_id: 组织ID
302
+ user_id: 用户ID
303
+ role: 用户角色(默认为 ACCOUNT)
304
+ actor_id: 操作者ID(如果不同于 user_id)
305
+ """
306
+ self._client.set_user_context(org_id, user_id, role, actor_id)
307
+
308
+ def get_user_context(self) -> Optional[UserContext]:
309
+ """获取当前用户上下文"""
310
+ return self._client.get_user_context()
311
+
312
+ def clear_user_context(self):
313
+ """清除用户上下文信息"""
314
+ self._client.clear_user_context()
315
+
316
+ def set_request_context(self, request_context: RequestContext):
317
+ """设置请求上下文"""
318
+ self._client.set_request_context(request_context)
319
+
320
+ def get_request_context(self) -> RequestContext:
321
+ """获取当前请求上下文"""
322
+ return self._client.get_request_context()
323
+
324
+ def update_request_context(self, **kwargs):
325
+ """
326
+ 更新请求上下文的部分字段
327
+
328
+ Args:
329
+ client_ip: 客户端IP地址
330
+ client_version: 客户端版本
331
+ client_type: 客户端类型
332
+ user_agent: User-Agent信息
333
+ extra: 额外的元数据字典
334
+ """
335
+ self._client.update_request_context(**kwargs)
336
+
337
+ def update_metadata(self, **kwargs):
338
+ """
339
+ 更新默认元数据
340
+
341
+ Args:
342
+ **kwargs: 要更新的元数据键值对
343
+ """
344
+ self._client.update_default_metadata(**kwargs)
345
+
346
+ def connect(self):
347
+ """连接到服务器"""
348
+ if not self._connected:
349
+ with self._connect_lock:
350
+ if not self._connected:
351
+ self._client.connect()
352
+ self._connected = True
353
+
354
+ def close(self):
355
+ """关闭连接"""
356
+ if self._connected:
357
+ self._client.close()
358
+ self._connected = False
359
+
360
+ def __enter__(self) -> "TamarFileHubClient":
361
+ self.connect()
362
+ return self
363
+
364
+ def __exit__(self, exc_type, exc_val, exc_tb):
365
+ self.close()
366
+
367
+ def __del__(self):
368
+ """析构函数,确保连接被关闭"""
369
+ try:
370
+ self.close()
371
+ except:
372
+ pass
373
+
374
+
375
+ # 创建默认的单例客户端实例
376
+ _default_client = None
377
+ _default_async_client = None
378
+
379
+
380
+ def get_client(**kwargs) -> TamarFileHubClient:
381
+ """
382
+ 获取默认的同步客户端实例(单例)
383
+
384
+ Args:
385
+ **kwargs: 客户端初始化参数,仅在第一次调用时生效
386
+
387
+ Returns:
388
+ TamarFileHubClient: 同步客户端实例
389
+ """
390
+ global _default_client
391
+ if _default_client is None:
392
+ _default_client = TamarFileHubClient(**kwargs)
393
+ return _default_client
394
+
395
+
396
+ def get_async_client(**kwargs) -> AsyncTamarFileHubClient:
397
+ """
398
+ 获取默认的异步客户端实例(单例)
399
+
400
+ Args:
401
+ **kwargs: 客户端初始化参数,仅在第一次调用时生效
402
+
403
+ Returns:
404
+ AsyncTamarFileHubClient: 异步客户端实例
405
+ """
406
+ global _default_async_client
407
+ if _default_async_client is None:
408
+ _default_async_client = AsyncTamarFileHubClient(**kwargs)
409
+ return _default_async_client
410
+
411
+
412
+ # 默认客户端实例(自动从环境变量读取配置)
413
+ tamar_client = get_client()
414
+ async_tamar_client = get_async_client()
@@ -0,0 +1,12 @@
1
+ """
2
+ 枚举类型定义
3
+ """
4
+ from .role import Role
5
+ from .upload_mode import UploadMode
6
+ from .export_format import ExportFormat
7
+
8
+ __all__ = [
9
+ "UploadMode",
10
+ "ExportFormat",
11
+ "Role",
12
+ ]
@@ -0,0 +1,16 @@
1
+ """
2
+ 导出格式枚举
3
+ """
4
+ from enum import Enum
5
+
6
+
7
+ class ExportFormat(Enum):
8
+ """导出格式(用于自定义文件类型)"""
9
+ PDF = "pdf"
10
+ DOCX = "docx"
11
+ XLSX = "xlsx"
12
+ PPTX = "pptx"
13
+ HTML = "html"
14
+ MARKDOWN = "markdown"
15
+ JSON = "json"
16
+ CSV = "csv"
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Role(str, Enum):
5
+ ACCOUNT = "account"
6
+ AGENT = "agent"
7
+ SYSTEM = "system"
@@ -0,0 +1,11 @@
1
+ """
2
+ 上传模式枚举
3
+ """
4
+ from enum import Enum
5
+
6
+
7
+ class UploadMode(str, Enum):
8
+ """上传模式"""
9
+ NORMAL = "normal" # 普通上传
10
+ STREAM = "stream" # 流式上传
11
+ RESUMABLE = "resumable" # 断点续传
@@ -0,0 +1,30 @@
1
+ """
2
+ 错误和异常定义
3
+ """
4
+ from .exceptions import (
5
+ FileHubError,
6
+ FileNotFoundError,
7
+ FolderNotFoundError,
8
+ PermissionError,
9
+ StorageError,
10
+ UploadError,
11
+ DownloadError,
12
+ ExportError,
13
+ ValidationError,
14
+ ConnectionError,
15
+ TimeoutError,
16
+ )
17
+
18
+ __all__ = [
19
+ "FileHubError",
20
+ "FileNotFoundError",
21
+ "FolderNotFoundError",
22
+ "PermissionError",
23
+ "StorageError",
24
+ "UploadError",
25
+ "DownloadError",
26
+ "ExportError",
27
+ "ValidationError",
28
+ "ConnectionError",
29
+ "TimeoutError",
30
+ ]
@@ -0,0 +1,93 @@
1
+ """
2
+ 异常类定义
3
+ """
4
+ from typing import Optional, Any
5
+
6
+
7
+ class FileHubError(Exception):
8
+ """文件管理系统基础异常"""
9
+
10
+ def __init__(self, message: str, code: Optional[str] = None, details: Optional[Any] = None):
11
+ super().__init__(message)
12
+ self.message = message
13
+ self.code = code
14
+ self.details = details
15
+
16
+
17
+ class FileNotFoundError(FileHubError):
18
+ """文件不存在异常"""
19
+
20
+ def __init__(self, file_id: str):
21
+ super().__init__(f"文件不存在: {file_id}", code="FILE_NOT_FOUND")
22
+ self.file_id = file_id
23
+
24
+
25
+ class FolderNotFoundError(FileHubError):
26
+ """文件夹不存在异常"""
27
+
28
+ def __init__(self, folder_id: str):
29
+ super().__init__(f"文件夹不存在: {folder_id}", code="FOLDER_NOT_FOUND")
30
+ self.folder_id = folder_id
31
+
32
+
33
+ class PermissionError(FileHubError):
34
+ """权限不足异常"""
35
+
36
+ def __init__(self, message: str):
37
+ super().__init__(message, code="PERMISSION_DENIED")
38
+
39
+
40
+ class StorageError(FileHubError):
41
+ """存储操作异常"""
42
+
43
+ def __init__(self, message: str, operation: Optional[str] = None):
44
+ super().__init__(message, code="STORAGE_ERROR")
45
+ self.operation = operation
46
+
47
+
48
+ class UploadError(FileHubError):
49
+ """上传异常"""
50
+
51
+ def __init__(self, message: str, upload_id: Optional[str] = None):
52
+ super().__init__(message, code="UPLOAD_ERROR")
53
+ self.upload_id = upload_id
54
+
55
+
56
+ class DownloadError(FileHubError):
57
+ """下载异常"""
58
+
59
+ def __init__(self, message: str, file_id: Optional[str] = None):
60
+ super().__init__(message, code="DOWNLOAD_ERROR")
61
+ self.file_id = file_id
62
+
63
+
64
+ class ExportError(FileHubError):
65
+ """导出异常"""
66
+
67
+ def __init__(self, message: str, file_id: Optional[str] = None, format: Optional[str] = None):
68
+ super().__init__(message, code="EXPORT_ERROR")
69
+ self.file_id = file_id
70
+ self.format = format
71
+
72
+
73
+ class ValidationError(FileHubError):
74
+ """验证异常"""
75
+
76
+ def __init__(self, message: str, field: Optional[str] = None):
77
+ super().__init__(message, code="VALIDATION_ERROR")
78
+ self.field = field
79
+
80
+
81
+ class ConnectionError(FileHubError):
82
+ """连接异常"""
83
+
84
+ def __init__(self, message: str):
85
+ super().__init__(message, code="CONNECTION_ERROR")
86
+
87
+
88
+ class TimeoutError(FileHubError):
89
+ """超时异常"""
90
+
91
+ def __init__(self, message: str, timeout: Optional[float] = None):
92
+ super().__init__(message, code="TIMEOUT_ERROR")
93
+ self.timeout = timeout
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,10 @@
1
+ """
2
+ RPC 模块 - 提供 gRPC 客户端基础类
3
+ """
4
+ from .async_client import AsyncGrpcClient
5
+ from .sync_client import SyncGrpcClient
6
+
7
+ __all__ = [
8
+ "AsyncGrpcClient",
9
+ "SyncGrpcClient",
10
+ ]