ErisPulse 2.3.4.dev2__py3-none-any.whl → 2.3.4.dev114514__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 (40) hide show
  1. ErisPulse/Core/Bases/module.py +1 -53
  2. ErisPulse/Core/Bases/module.pyi +0 -43
  3. ErisPulse/Core/Event/command.py +1 -6
  4. ErisPulse/Core/_self_config.py +1 -1
  5. ErisPulse/Core/adapter.py +10 -70
  6. ErisPulse/Core/adapter.pyi +1 -18
  7. ErisPulse/Core/exceptions.py +2 -4
  8. ErisPulse/Core/lifecycle.py +0 -9
  9. ErisPulse/Core/logger.py +15 -21
  10. ErisPulse/Core/logger.pyi +1 -2
  11. ErisPulse/Core/module.py +9 -57
  12. ErisPulse/Core/module.pyi +1 -12
  13. ErisPulse/Core/router.py +5 -13
  14. ErisPulse/Core/storage.py +256 -94
  15. ErisPulse/Core/storage.pyi +66 -13
  16. ErisPulse/__init__.py +1237 -35
  17. ErisPulse/__init__.pyi +290 -3
  18. ErisPulse/sdk_protocol.py +143 -0
  19. ErisPulse/sdk_protocol.pyi +97 -0
  20. {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/METADATA +1 -1
  21. {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/RECORD +24 -38
  22. ErisPulse/Core/Bases/manager.py +0 -136
  23. ErisPulse/Core/Bases/manager.pyi +0 -108
  24. ErisPulse/loaders/__init__.py +0 -22
  25. ErisPulse/loaders/__init__.pyi +0 -21
  26. ErisPulse/loaders/adapter_loader.py +0 -187
  27. ErisPulse/loaders/adapter_loader.pyi +0 -82
  28. ErisPulse/loaders/base_loader.py +0 -162
  29. ErisPulse/loaders/base_loader.pyi +0 -23
  30. ErisPulse/loaders/initializer.py +0 -150
  31. ErisPulse/loaders/initializer.pyi +0 -60
  32. ErisPulse/loaders/module_loader.py +0 -618
  33. ErisPulse/loaders/module_loader.pyi +0 -179
  34. ErisPulse/loaders/strategy.py +0 -129
  35. ErisPulse/loaders/strategy.pyi +0 -90
  36. ErisPulse/sdk.py +0 -435
  37. ErisPulse/sdk.pyi +0 -158
  38. {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/WHEEL +0 -0
  39. {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/entry_points.txt +0 -0
  40. {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/licenses/LICENSE +0 -0
ErisPulse/Core/storage.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  ErisPulse 存储管理模块
3
3
 
4
- 提供键值存储和事务支持,用于管理框架运行时数据。
4
+ 提供键值存储、事务支持、快照和恢复功能,用于管理框架运行时数据。
5
5
  基于SQLite实现持久化存储,支持复杂数据类型和原子操作。
6
6
 
7
7
  支持两种数据库模式:
@@ -17,21 +17,23 @@ use_global_db = true
17
17
  {!--< tips >!--}
18
18
  1. 支持JSON序列化存储复杂数据类型
19
19
  2. 提供事务支持确保数据一致性
20
+ 3. 自动快照功能防止数据丢失
20
21
  {!--< /tips >!--}
21
22
  """
22
23
 
23
24
  import os
24
25
  import json
25
26
  import sqlite3
26
- import threading
27
- from typing import List, Dict, Optional, Any, Type
28
- from contextlib import contextmanager
27
+ import shutil
28
+ import time
29
+ from datetime import datetime
30
+ from typing import List, Dict, Optional, Any, Tuple, Type
29
31
 
30
32
  class StorageManager:
31
33
  """
32
34
  存储管理器
33
35
 
34
- 单例模式实现,提供键值存储的增删改查和事务管理
36
+ 单例模式实现,提供键值存储的增删改查、事务和快照管理
35
37
 
36
38
  支持两种数据库模式:
37
39
  1. 项目数据库(默认):位于项目目录下的 config/config.db
@@ -46,6 +48,7 @@ class StorageManager:
46
48
  {!--< tips >!--}
47
49
  1. 使用get/set方法操作存储项
48
50
  2. 使用transaction上下文管理事务
51
+ 3. 使用snapshot/restore管理数据快照
49
52
  {!--< /tips >!--}
50
53
  """
51
54
 
@@ -54,8 +57,7 @@ class StorageManager:
54
57
  DEFAULT_PROJECT_DB_PATH = os.path.join(os.getcwd(), "config", "config.db")
55
58
  # 包内全局数据库路径
56
59
  GLOBAL_DB_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "../data/config.db"))
57
- # 线程本地存储,用于跟踪活动事务的连接
58
- _local = threading.local()
60
+ SNAPSHOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../data/snapshots"))
59
61
 
60
62
  def __new__(cls, *args, **kwargs):
61
63
  if not cls._instance:
@@ -71,41 +73,20 @@ class StorageManager:
71
73
  self._ensure_directories()
72
74
 
73
75
  # 根据配置决定使用哪个数据库
74
- from ._self_config import get_storage_config
75
- storage_config = get_storage_config()
76
-
77
- use_global_db = storage_config.get("use_global_db", False)
76
+ from .config import config
77
+ use_global_db = config.getConfig("ErisPulse.storage.use_global_db", False)
78
78
 
79
79
  if use_global_db and os.path.exists(self.GLOBAL_DB_PATH):
80
80
  self.db_path = self.GLOBAL_DB_PATH
81
81
  else:
82
82
  self.db_path = self.DEFAULT_PROJECT_DB_PATH
83
83
 
84
+ self._last_snapshot_time = time.time()
85
+ self._snapshot_interval = 3600
86
+
84
87
  self._init_db()
85
88
  self._initialized = True
86
89
 
87
- @contextmanager
88
- def _get_connection(self):
89
- """
90
- 获取数据库连接(支持事务)
91
-
92
- 如果在事务中,返回事务的连接
93
- 否则创建新连接
94
- """
95
- # 检查是否在线程本地存储中有活动事务连接
96
- if hasattr(self._local, 'transaction_conn') and self._local.transaction_conn is not None:
97
- conn = self._local.transaction_conn
98
- should_close = False
99
- else:
100
- conn = sqlite3.connect(self.db_path)
101
- should_close = True
102
-
103
- try:
104
- yield conn
105
- finally:
106
- if should_close:
107
- conn.close()
108
-
109
90
  def _ensure_directories(self) -> None:
110
91
  """
111
92
  确保必要的目录存在
@@ -115,6 +96,12 @@ class StorageManager:
115
96
  os.makedirs(os.path.dirname(self.DEFAULT_PROJECT_DB_PATH), exist_ok=True)
116
97
  except Exception:
117
98
  pass # 如果无法创建项目目录,则跳过
99
+
100
+ # 确保快照目录存在
101
+ try:
102
+ os.makedirs(self.SNAPSHOT_DIR, exist_ok=True)
103
+ except Exception:
104
+ pass # 如果无法创建快照目录,则跳过
118
105
 
119
106
  def _init_db(self) -> None:
120
107
  """
@@ -153,6 +140,10 @@ class StorageManager:
153
140
  except Exception as e:
154
141
  logger.error(f"初始化数据库时发生未知错误: {e}")
155
142
  raise
143
+
144
+ # 初始化自动快照调度器
145
+ self._last_snapshot_time = time.time() # 初始化为当前时间
146
+ self._snapshot_interval = 3600 # 默认每小时自动快照
156
147
 
157
148
  def get(self, key: str, default: Any = None) -> Any:
158
149
  """
@@ -235,14 +226,15 @@ class StorageManager:
235
226
  return False
236
227
 
237
228
  try:
238
- serialized_value = json.dumps(value)
239
- with self._get_connection() as conn:
229
+ serialized_value = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
230
+ with self.transaction():
231
+ conn = sqlite3.connect(self.db_path)
240
232
  cursor = conn.cursor()
241
233
  cursor.execute("INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)", (key, serialized_value))
242
- # 如果不在事务中,提交更改
243
- if not (hasattr(self._local, 'transaction_conn') and self._local.transaction_conn is not None):
244
- conn.commit()
234
+ conn.commit()
235
+ conn.close()
245
236
 
237
+ self._check_auto_snapshot()
246
238
  return True
247
239
  except Exception as e:
248
240
  from .logger import logger
@@ -268,16 +260,17 @@ class StorageManager:
268
260
  return False
269
261
 
270
262
  try:
271
- with self._get_connection() as conn:
263
+ with self.transaction():
264
+ conn = sqlite3.connect(self.db_path)
272
265
  cursor = conn.cursor()
273
266
  for key, value in items.items():
274
- serialized_value = json.dumps(value)
267
+ serialized_value = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
275
268
  cursor.execute("INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)",
276
269
  (key, serialized_value))
277
- # 如果不在事务中,提交更改
278
- if not (hasattr(self._local, 'transaction_conn') and self._local.transaction_conn is not None):
279
- conn.commit()
270
+ conn.commit()
271
+ conn.close()
280
272
 
273
+ self._check_auto_snapshot()
281
274
  return True
282
275
  except Exception:
283
276
  return False
@@ -323,13 +316,14 @@ class StorageManager:
323
316
  return False
324
317
 
325
318
  try:
326
- with self._get_connection() as conn:
319
+ with self.transaction():
320
+ conn = sqlite3.connect(self.db_path)
327
321
  cursor = conn.cursor()
328
322
  cursor.execute("DELETE FROM config WHERE key = ?", (key,))
329
- # 如果不在事务中,提交更改
330
- if not (hasattr(self._local, 'transaction_conn') and self._local.transaction_conn is not None):
331
- conn.commit()
323
+ conn.commit()
324
+ conn.close()
332
325
 
326
+ self._check_auto_snapshot()
333
327
  return True
334
328
  except Exception:
335
329
  return False
@@ -349,13 +343,14 @@ class StorageManager:
349
343
  return False
350
344
 
351
345
  try:
352
- with self._get_connection() as conn:
346
+ with self.transaction():
347
+ conn = sqlite3.connect(self.db_path)
353
348
  cursor = conn.cursor()
354
349
  cursor.executemany("DELETE FROM config WHERE key = ?", [(k,) for k in keys])
355
- # 如果不在事务中,提交更改
356
- if not (hasattr(self._local, 'transaction_conn') and self._local.transaction_conn is not None):
357
- conn.commit()
350
+ conn.commit()
351
+ conn.close()
358
352
 
353
+ self._check_auto_snapshot()
359
354
  return True
360
355
  except Exception:
361
356
  return False
@@ -379,12 +374,8 @@ class StorageManager:
379
374
  cursor = conn.cursor()
380
375
  placeholders = ','.join(['?'] * len(keys))
381
376
  cursor.execute(f"SELECT key, value FROM config WHERE key IN ({placeholders})", keys)
382
- results = {}
383
- for row in cursor.fetchall():
384
- try:
385
- results[row[0]] = json.loads(row[1])
386
- except json.JSONDecodeError:
387
- results[row[0]] = row[1]
377
+ results = {row[0]: json.loads(row[1]) if row[1].startswith(('{', '[')) else row[1]
378
+ for row in cursor.fetchall()}
388
379
  conn.close()
389
380
  return results
390
381
  except Exception as e:
@@ -412,15 +403,6 @@ class StorageManager:
412
403
  def __exit__(self, *args):
413
404
  pass
414
405
  return EmptyTransaction()
415
-
416
- # 如果已经在事务中(嵌套事务),返回一个空事务,复用现有连接
417
- if hasattr(self._local, 'transaction_conn') and self._local.transaction_conn is not None:
418
- class NestedTransaction:
419
- def __enter__(self):
420
- return self
421
- def __exit__(self, *args):
422
- pass
423
- return NestedTransaction()
424
406
 
425
407
  return self._Transaction(self)
426
408
 
@@ -444,18 +426,12 @@ class StorageManager:
444
426
  self.conn = sqlite3.connect(self.storage_manager.db_path)
445
427
  self.cursor = self.conn.cursor()
446
428
  self.cursor.execute("BEGIN TRANSACTION")
447
- # 将连接存储到线程本地存储,供其他方法复用
448
- self.storage_manager._local.transaction_conn = self.conn
449
429
  return self
450
430
 
451
431
  def __exit__(self, exc_type: Type[Exception], exc_val: Exception, exc_tb: Any) -> None:
452
432
  """
453
433
  退出事务上下文
454
434
  """
455
- # 清除线程本地存储中的连接引用
456
- if hasattr(self.storage_manager._local, 'transaction_conn'):
457
- self.storage_manager._local.transaction_conn = None
458
-
459
435
  if self.conn is not None:
460
436
  try:
461
437
  if exc_type is None:
@@ -470,6 +446,58 @@ class StorageManager:
470
446
  if hasattr(self.conn, 'close'):
471
447
  self.conn.close()
472
448
 
449
+ def _check_auto_snapshot(self) -> None:
450
+ """
451
+ {!--< internal-use >!--}
452
+ 检查并执行自动快照
453
+ """
454
+ # 避免在初始化过程中调用此方法导致问题
455
+ if not hasattr(self, '_initialized') or not self._initialized:
456
+ return
457
+
458
+ from .logger import logger
459
+
460
+ if not hasattr(self, '_last_snapshot_time') or self._last_snapshot_time is None:
461
+ self._last_snapshot_time = time.time()
462
+
463
+ if not hasattr(self, '_snapshot_interval') or self._snapshot_interval is None:
464
+ self._snapshot_interval = 3600
465
+
466
+ current_time = time.time()
467
+
468
+ try:
469
+ time_diff = current_time - self._last_snapshot_time
470
+ if not isinstance(time_diff, (int, float)):
471
+ raise ValueError("时间差应为数值类型")
472
+
473
+ if not isinstance(self._snapshot_interval, (int, float)):
474
+ raise ValueError("快照间隔应为数值类型")
475
+
476
+ if time_diff > self._snapshot_interval:
477
+ self._last_snapshot_time = current_time
478
+ self.snapshot(f"auto_{datetime.now().strftime('%Y%m%d_%H%M%S')}")
479
+
480
+ except Exception as e:
481
+ logger.error(f"自动快照检查失败: {e}")
482
+ self._last_snapshot_time = current_time
483
+ self._snapshot_interval = 3600
484
+
485
+ def set_snapshot_interval(self, seconds: int) -> None:
486
+ """
487
+ 设置自动快照间隔
488
+
489
+ :param seconds: 间隔秒数
490
+
491
+ :example:
492
+ >>> # 每30分钟自动快照
493
+ >>> storage.set_snapshot_interval(1800)
494
+ """
495
+ # 避免在初始化过程中调用此方法导致问题
496
+ if not hasattr(self, '_initialized') or not self._initialized:
497
+ return
498
+
499
+ self._snapshot_interval = seconds
500
+
473
501
  def clear(self) -> bool:
474
502
  """
475
503
  清空所有存储项
@@ -484,13 +512,11 @@ class StorageManager:
484
512
  return False
485
513
 
486
514
  try:
487
- with self._get_connection() as conn:
488
- cursor = conn.cursor()
489
- cursor.execute("DELETE FROM config")
490
- # 如果不在事务中,提交更改
491
- if not (hasattr(self._local, 'transaction_conn') and self._local.transaction_conn is not None):
492
- conn.commit()
493
-
515
+ conn = sqlite3.connect(self.db_path)
516
+ cursor = conn.cursor()
517
+ cursor.execute("DELETE FROM config")
518
+ conn.commit()
519
+ conn.close()
494
520
  return True
495
521
  except Exception:
496
522
  return False
@@ -514,24 +540,11 @@ class StorageManager:
514
540
  # 避免在初始化过程中调用此方法导致问题
515
541
  if not hasattr(self, '_initialized') or not self._initialized:
516
542
  raise AttributeError(f"存储尚未初始化完成: {key}")
517
-
518
- # 检查键是否存在
543
+
519
544
  try:
520
- with sqlite3.connect(self.db_path) as conn:
521
- cursor = conn.cursor()
522
- cursor.execute("SELECT value FROM config WHERE key = ?", (key,))
523
- result = cursor.fetchone()
545
+ return self.get(key)
524
546
  except Exception:
525
547
  raise AttributeError(f"存储项 {key} 不存在或访问出错")
526
-
527
- if result is None:
528
- raise AttributeError(f"存储项 {key} 不存在")
529
-
530
- # 解析并返回值
531
- try:
532
- return json.loads(result[0])
533
- except json.JSONDecodeError:
534
- return result[0]
535
548
 
536
549
  def __setattr__(self, key: str, value: Any) -> None:
537
550
  """
@@ -559,8 +572,157 @@ class StorageManager:
559
572
  from .logger import logger
560
573
  logger.error(f"设置存储项 {key} 失败: {e}")
561
574
 
575
+ def snapshot(self, name: Optional[str] = None) -> str:
576
+ """
577
+ 创建数据库快照
578
+
579
+ :param name: 快照名称(可选)
580
+ :return: 快照文件路径
581
+
582
+ :example:
583
+ >>> # 创建命名快照
584
+ >>> snapshot_path = storage.snapshot("before_update")
585
+ >>> # 创建时间戳快照
586
+ >>> snapshot_path = storage.snapshot()
587
+ """
588
+ # 避免在初始化过程中调用此方法导致问题
589
+ if not hasattr(self, '_initialized') or not self._initialized:
590
+ raise RuntimeError("存储尚未初始化完成")
591
+
592
+ if not name:
593
+ name = datetime.now().strftime("%Y%m%d_%H%M%S")
594
+ snapshot_path = os.path.join(self.SNAPSHOT_DIR, f"{name}.db")
595
+
596
+ try:
597
+ # 快照目录
598
+ os.makedirs(self.SNAPSHOT_DIR, exist_ok=True)
599
+
600
+ # 安全关闭连接
601
+ if hasattr(self, "_conn") and self._conn is not None:
602
+ try:
603
+ self._conn.close()
604
+ except Exception as e:
605
+ from .logger import logger
606
+ logger.warning(f"关闭数据库连接时出错: {e}")
607
+
608
+ # 创建快照
609
+ shutil.copy2(self.db_path, snapshot_path)
610
+ from .logger import logger
611
+ logger.info(f"数据库快照已创建: {snapshot_path}")
612
+ return snapshot_path
613
+ except Exception as e:
614
+ from .logger import logger
615
+ logger.error(f"创建快照失败: {e}")
616
+ raise
617
+
618
+ def restore(self, snapshot_name: str) -> bool:
619
+ """
620
+ 从快照恢复数据库
621
+
622
+ :param snapshot_name: 快照名称或路径
623
+ :return: 恢复是否成功
624
+
625
+ :example:
626
+ >>> storage.restore("before_update")
627
+ """
628
+ # 避免在初始化过程中调用此方法导致问题
629
+ if not hasattr(self, '_initialized') or not self._initialized:
630
+ return False
631
+
632
+ snapshot_path = os.path.join(self.SNAPSHOT_DIR, f"{snapshot_name}.db") \
633
+ if not snapshot_name.endswith('.db') else snapshot_name
634
+
635
+ if not os.path.exists(snapshot_path):
636
+ from .logger import logger
637
+ logger.error(f"快照文件不存在: {snapshot_path}")
638
+ return False
639
+
640
+ try:
641
+ # 安全关闭连接
642
+ if hasattr(self, "_conn") and self._conn is not None:
643
+ try:
644
+ self._conn.close()
645
+ except Exception as e:
646
+ from .logger import logger
647
+ logger.warning(f"关闭数据库连接时出错: {e}")
648
+
649
+ # 执行恢复操作
650
+ shutil.copy2(snapshot_path, self.db_path)
651
+ self._init_db() # 恢复后重新初始化数据库连接
652
+ from .logger import logger
653
+ logger.info(f"数据库已从快照恢复: {snapshot_path}")
654
+ return True
655
+ except Exception as e:
656
+ from .logger import logger
657
+ logger.error(f"恢复快照失败: {e}")
658
+ return False
659
+
660
+ def list_snapshots(self) -> List[Tuple[str, datetime, int]]:
661
+ """
662
+ 列出所有可用的快照
663
+
664
+ :return: 快照信息列表(名称, 创建时间, 大小)
665
+
666
+ :example:
667
+ >>> for name, date, size in storage.list_snapshots():
668
+ >>> print(f"{name} - {date} ({size} bytes)")
669
+ """
670
+ # 避免在初始化过程中调用此方法导致问题
671
+ if not hasattr(self, '_initialized') or not self._initialized:
672
+ return []
673
+
674
+ try:
675
+ snapshots = []
676
+ for f in os.listdir(self.SNAPSHOT_DIR):
677
+ if f.endswith('.db'):
678
+ path = os.path.join(self.SNAPSHOT_DIR, f)
679
+ stat = os.stat(path)
680
+ snapshots.append((
681
+ f[:-3], # 去掉.db后缀
682
+ datetime.fromtimestamp(stat.st_ctime),
683
+ stat.st_size
684
+ ))
685
+ return sorted(snapshots, key=lambda x: x[1], reverse=True)
686
+ except Exception as e:
687
+ from .logger import logger
688
+ logger.error(f"列出快照时发生错误: {e}")
689
+ return []
690
+
691
+ def delete_snapshot(self, snapshot_name: str) -> bool:
692
+ """
693
+ 删除指定的快照
694
+
695
+ :param snapshot_name: 快照名称
696
+ :return: 删除是否成功
697
+
698
+ :example:
699
+ >>> storage.delete_snapshot("old_backup")
700
+ """
701
+ # 避免在初始化过程中调用此方法导致问题
702
+ if not hasattr(self, '_initialized') or not self._initialized:
703
+ return False
704
+
705
+ snapshot_path = os.path.join(self.SNAPSHOT_DIR, f"{snapshot_name}.db") \
706
+ if not snapshot_name.endswith('.db') else snapshot_name
707
+
708
+ if not os.path.exists(snapshot_path):
709
+ from .logger import logger
710
+ logger.error(f"快照文件不存在: {snapshot_path}")
711
+ return False
712
+
713
+ try:
714
+ os.remove(snapshot_path)
715
+ from .logger import logger
716
+ logger.info(f"快照已删除: {snapshot_path}")
717
+ return True
718
+ except Exception as e:
719
+ from .logger import logger
720
+ logger.error(f"删除快照失败: {e}")
721
+ return False
722
+
562
723
  storage = StorageManager()
563
724
 
564
725
  __all__ = [
565
726
  "storage"
566
727
  ]
728
+
@@ -7,7 +7,7 @@
7
7
  """
8
8
  ErisPulse 存储管理模块
9
9
 
10
- 提供键值存储和事务支持,用于管理框架运行时数据。
10
+ 提供键值存储、事务支持、快照和恢复功能,用于管理框架运行时数据。
11
11
  基于SQLite实现持久化存储,支持复杂数据类型和原子操作。
12
12
 
13
13
  支持两种数据库模式:
@@ -23,21 +23,23 @@ use_global_db = true
23
23
  {!--< tips >!--}
24
24
  1. 支持JSON序列化存储复杂数据类型
25
25
  2. 提供事务支持确保数据一致性
26
+ 3. 自动快照功能防止数据丢失
26
27
  {!--< /tips >!--}
27
28
  """
28
29
 
29
30
  import os
30
31
  import json
31
32
  import sqlite3
32
- import threading
33
- from typing import List, Dict, Optional, Any, Type
34
- from contextlib import contextmanager
33
+ import shutil
34
+ import time
35
+ from datetime import datetime
36
+ from typing import List, Dict, Optional, Any, Tuple, Type
35
37
 
36
38
  class StorageManager:
37
39
  """
38
40
  存储管理器
39
41
 
40
- 单例模式实现,提供键值存储的增删改查和事务管理
42
+ 单例模式实现,提供键值存储的增删改查、事务和快照管理
41
43
 
42
44
  支持两种数据库模式:
43
45
  1. 项目数据库(默认):位于项目目录下的 config/config.db
@@ -52,20 +54,13 @@ class StorageManager:
52
54
  {!--< tips >!--}
53
55
  1. 使用get/set方法操作存储项
54
56
  2. 使用transaction上下文管理事务
57
+ 3. 使用snapshot/restore管理数据快照
55
58
  {!--< /tips >!--}
56
59
  """
57
60
  def __new__(cls: object, *args: ..., **kwargs: ...) -> ...:
58
61
  ...
59
62
  def __init__(self: None) -> ...:
60
63
  ...
61
- def _get_connection(self: object) -> ...:
62
- """
63
- 获取数据库连接(支持事务)
64
-
65
- 如果在事务中,返回事务的连接
66
- 否则创建新连接
67
- """
68
- ...
69
64
  def _ensure_directories(self: object) -> None:
70
65
  """
71
66
  确保必要的目录存在
@@ -184,6 +179,17 @@ class StorageManager:
184
179
  >>> storage.set("key2", "value2")
185
180
  """
186
181
  ...
182
+ def set_snapshot_interval(self: object, seconds: int) -> None:
183
+ """
184
+ 设置自动快照间隔
185
+
186
+ :param seconds: 间隔秒数
187
+
188
+ :example:
189
+ >>> # 每30分钟自动快照
190
+ >>> storage.set_snapshot_interval(1800)
191
+ """
192
+ ...
187
193
  def clear(self: object) -> bool:
188
194
  """
189
195
  清空所有存储项
@@ -218,3 +224,50 @@ class StorageManager:
218
224
  >>> storage.app_name = "MyApp"
219
225
  """
220
226
  ...
227
+ def snapshot(self: object, name: Optional[str] = ...) -> str:
228
+ """
229
+ 创建数据库快照
230
+
231
+ :param name: 快照名称(可选)
232
+ :return: 快照文件路径
233
+
234
+ :example:
235
+ >>> # 创建命名快照
236
+ >>> snapshot_path = storage.snapshot("before_update")
237
+ >>> # 创建时间戳快照
238
+ >>> snapshot_path = storage.snapshot()
239
+ """
240
+ ...
241
+ def restore(self: object, snapshot_name: str) -> bool:
242
+ """
243
+ 从快照恢复数据库
244
+
245
+ :param snapshot_name: 快照名称或路径
246
+ :return: 恢复是否成功
247
+
248
+ :example:
249
+ >>> storage.restore("before_update")
250
+ """
251
+ ...
252
+ def list_snapshots(self: object) -> List[Tuple[(str, datetime, int)]]:
253
+ """
254
+ 列出所有可用的快照
255
+
256
+ :return: 快照信息列表(名称, 创建时间, 大小)
257
+
258
+ :example:
259
+ >>> for name, date, size in storage.list_snapshots():
260
+ >>> print(f"{name} - {date} ({size} bytes)")
261
+ """
262
+ ...
263
+ def delete_snapshot(self: object, snapshot_name: str) -> bool:
264
+ """
265
+ 删除指定的快照
266
+
267
+ :param snapshot_name: 快照名称
268
+ :return: 删除是否成功
269
+
270
+ :example:
271
+ >>> storage.delete_snapshot("old_backup")
272
+ """
273
+ ...