ErisPulse 1.2.9__py3-none-any.whl → 2.1.0__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.
ErisPulse/db.py DELETED
@@ -1,769 +0,0 @@
1
- """
2
- # 环境配置
3
-
4
- 提供键值存储、事务支持、快照和恢复功能,用于管理框架配置数据。基于SQLite实现持久化存储,支持复杂数据类型和原子操作。
5
-
6
- ## API 文档
7
-
8
- ### 基本操作
9
- #### get(key: str, default: Any = None) -> Any
10
- 获取配置项的值。
11
- - 参数:
12
- - key: 配置项键名
13
- - default: 如果键不存在时返回的默认值
14
- - 返回:
15
- - Any: 配置项的值,如果是JSON格式则自动解析为Python对象
16
- - 示例:
17
- ```python
18
- # 获取基本配置
19
- timeout = sdk.env.get("network.timeout", 30)
20
-
21
- # 获取结构化数据
22
- user_settings = sdk.env.get("user.settings", {})
23
- if "theme" in user_settings:
24
- apply_theme(user_settings["theme"])
25
-
26
- # 条件获取
27
- debug_mode = sdk.env.get("app.debug", False)
28
- if debug_mode:
29
- enable_debug_features()
30
- ```
31
-
32
- #### set(key: str, value: Any) -> bool
33
- 设置配置项的值。
34
- - 参数:
35
- - key: 配置项键名
36
- - value: 配置项的值,复杂类型会自动序列化为JSON
37
- - 返回:
38
- - bool: 操作是否成功
39
- - 示例:
40
- ```python
41
- # 设置基本配置
42
- sdk.env.set("app.name", "MyApplication")
43
-
44
- # 设置结构化数据
45
- sdk.env.set("server.config", {
46
- "host": "localhost",
47
- "port": 8080,
48
- "workers": 4
49
- })
50
-
51
- # 更新现有配置
52
- current_settings = sdk.env.get("user.settings", {})
53
- current_settings["last_login"] = datetime.now().isoformat()
54
- sdk.env.set("user.settings", current_settings)
55
- ```
56
-
57
- #### delete(key: str) -> bool
58
- 删除配置项。
59
- - 参数:
60
- - key: 要删除的配置项键名
61
- - 返回:
62
- - bool: 操作是否成功
63
- - 示例:
64
- ```python
65
- # 删除临时配置
66
- sdk.env.delete("temp.session")
67
-
68
- # 条件删除
69
- if not is_feature_enabled():
70
- sdk.env.delete("feature.config")
71
-
72
- # 清理旧配置
73
- for key in sdk.env.get_all_keys():
74
- if key.startswith("deprecated."):
75
- sdk.env.delete(key)
76
- ```
77
-
78
- #### get_all_keys() -> list[str]
79
- 获取所有配置项的键名。
80
- - 参数: 无
81
- - 返回:
82
- - list[str]: 所有配置项的键名列表
83
- - 示例:
84
- ```python
85
- # 列出所有配置
86
- all_keys = sdk.env.get_all_keys()
87
- print(f"当前有 {len(all_keys)} 个配置项")
88
-
89
- # 按前缀过滤
90
- user_keys = [k for k in sdk.env.get_all_keys() if k.startswith("user.")]
91
- print(f"用户相关配置: {user_keys}")
92
-
93
- # 导出配置摘要
94
- config_summary = {}
95
- for key in sdk.env.get_all_keys():
96
- parts = key.split(".")
97
- if len(parts) > 1:
98
- category = parts[0]
99
- if category not in config_summary:
100
- config_summary[category] = 0
101
- config_summary[category] += 1
102
- print("配置分类统计:", config_summary)
103
- ```
104
-
105
- ### 批量操作
106
- #### get_multi(keys: list) -> dict
107
- 批量获取多个配置项的值。
108
- - 参数:
109
- - keys: 要获取的配置项键名列表
110
- - 返回:
111
- - dict: 键值对字典,只包含存在的键
112
- - 示例:
113
- ```python
114
- # 批量获取配置
115
- settings = sdk.env.get_multi([
116
- "app.name",
117
- "app.version",
118
- "app.debug"
119
- ])
120
- print(f"应用: {settings.get('app.name')} v{settings.get('app.version')}")
121
-
122
- # 获取相关配置组
123
- db_keys = ["database.host", "database.port", "database.user", "database.password"]
124
- db_config = sdk.env.get_multi(db_keys)
125
- connection = create_db_connection(**db_config)
126
-
127
- # 配置存在性检查
128
- required_keys = ["api.key", "api.endpoint", "api.version"]
129
- config = sdk.env.get_multi(required_keys)
130
- missing = [k for k in required_keys if k not in config]
131
- if missing:
132
- raise ValueError(f"缺少必要配置: {missing}")
133
- ```
134
-
135
- #### set_multi(items: dict) -> bool
136
- 批量设置多个配置项的值。
137
- - 参数:
138
- - items: 要设置的键值对字典
139
- - 返回:
140
- - bool: 操作是否成功
141
- - 示例:
142
- ```python
143
- # 批量设置基本配置
144
- sdk.env.set_multi({
145
- "app.name": "MyApp",
146
- "app.version": "1.0.0",
147
- "app.debug": True
148
- })
149
-
150
- # 更新系统设置
151
- sdk.env.set_multi({
152
- "system.max_connections": 100,
153
- "system.timeout": 30,
154
- "system.retry_count": 3
155
- })
156
-
157
- # 从外部配置导入
158
- import json
159
- with open("config.json", "r") as f:
160
- external_config = json.load(f)
161
-
162
- # 转换为扁平结构
163
- flat_config = {}
164
- for section, values in external_config.items():
165
- for key, value in values.items():
166
- flat_config[f"{section}.{key}"] = value
167
-
168
- sdk.env.set_multi(flat_config)
169
- ```
170
-
171
- #### delete_multi(keys: list) -> bool
172
- 批量删除多个配置项。
173
- - 参数:
174
- - keys: 要删除的配置项键名列表
175
- - 返回:
176
- - bool: 操作是否成功
177
- - 示例:
178
- ```python
179
- # 批量删除临时配置
180
- temp_keys = [k for k in sdk.env.get_all_keys() if k.startswith("temp.")]
181
- sdk.env.delete_multi(temp_keys)
182
-
183
- # 删除特定模块的所有配置
184
- module_keys = [k for k in sdk.env.get_all_keys() if k.startswith("module_name.")]
185
- sdk.env.delete_multi(module_keys)
186
-
187
- # 清理测试数据
188
- test_keys = ["test.user", "test.data", "test.results"]
189
- sdk.env.delete_multi(test_keys)
190
- ```
191
-
192
- ### 事务管理
193
- #### transaction() -> contextmanager
194
- 创建事务上下文,确保多个操作的原子性。
195
- - 参数: 无
196
- - 返回:
197
- - contextmanager: 事务上下文管理器
198
- - 示例:
199
- ```python
200
- # 基本事务
201
- with sdk.env.transaction():
202
- sdk.env.set("user.id", user_id)
203
- sdk.env.set("user.name", user_name)
204
- sdk.env.set("user.email", user_email)
205
-
206
- # 带有条件检查的事务
207
- def update_user_safely(user_id, new_data):
208
- with sdk.env.transaction():
209
- current = sdk.env.get(f"user.{user_id}", None)
210
- if not current:
211
- return False
212
-
213
- for key, value in new_data.items():
214
- sdk.env.set(f"user.{user_id}.{key}", value)
215
-
216
- sdk.env.set(f"user.{user_id}.updated_at", time.time())
217
- return True
218
-
219
- # 复杂业务逻辑事务
220
- def transfer_credits(from_user, to_user, amount):
221
- with sdk.env.transaction():
222
- # 检查余额
223
- from_balance = sdk.env.get(f"user.{from_user}.credits", 0)
224
- if from_balance < amount:
225
- raise ValueError("余额不足")
226
-
227
- # 更新余额
228
- sdk.env.set(f"user.{from_user}.credits", from_balance - amount)
229
-
230
- to_balance = sdk.env.get(f"user.{to_user}.credits", 0)
231
- sdk.env.set(f"user.{to_user}.credits", to_balance + amount)
232
-
233
- # 记录交易
234
- transaction_id = str(uuid.uuid4())
235
- sdk.env.set(f"transaction.{transaction_id}", {
236
- "from": from_user,
237
- "to": to_user,
238
- "amount": amount,
239
- "timestamp": time.time()
240
- })
241
- ```
242
-
243
- ### 快照管理
244
- #### snapshot(name: str = None) -> str
245
- 创建数据库快照。
246
- - 参数:
247
- - name: 快照名称,默认使用当前时间戳
248
- - 返回:
249
- - str: 快照文件路径
250
- - 示例:
251
- ```python
252
- # 创建命名快照
253
- sdk.env.snapshot("before_migration")
254
-
255
- # 创建定期备份
256
- def create_daily_backup():
257
- date_str = datetime.now().strftime("%Y%m%d")
258
- return sdk.env.snapshot(f"daily_{date_str}")
259
-
260
- # 在重要操作前创建快照
261
- def safe_operation():
262
- snapshot_path = sdk.env.snapshot("pre_operation")
263
- try:
264
- perform_risky_operation()
265
- except Exception as e:
266
- sdk.logger.error(f"操作失败: {e}")
267
- sdk.env.restore(snapshot_path)
268
- return False
269
- return True
270
- ```
271
-
272
- #### restore(snapshot_name: str) -> bool
273
- 从快照恢复数据库。
274
- - 参数:
275
- - snapshot_name: 快照名称或路径
276
- - 返回:
277
- - bool: 恢复是否成功
278
- - 示例:
279
- ```python
280
- # 恢复到指定快照
281
- success = sdk.env.restore("before_migration")
282
- if success:
283
- print("成功恢复到之前的状态")
284
- else:
285
- print("恢复失败")
286
-
287
- # 回滚到最近的每日备份
288
- def rollback_to_last_daily():
289
- snapshots = sdk.env.list_snapshots()
290
- daily_snapshots = [s for s in snapshots if s[0].startswith("daily_")]
291
- if daily_snapshots:
292
- latest = daily_snapshots[0] # 列表已按时间排序
293
- return sdk.env.restore(latest[0])
294
- return False
295
-
296
- # 灾难恢复
297
- def disaster_recovery():
298
- snapshots = sdk.env.list_snapshots()
299
- if not snapshots:
300
- print("没有可用的快照")
301
- return False
302
-
303
- print("可用快照:")
304
- for i, (name, date, size) in enumerate(snapshots):
305
- print(f"{i+1}. {name} - {date} ({size/1024:.1f} KB)")
306
-
307
- choice = input("选择要恢复的快照编号: ")
308
- try:
309
- index = int(choice) - 1
310
- if 0 <= index < len(snapshots):
311
- return sdk.env.restore(snapshots[index][0])
312
- except ValueError:
313
- pass
314
- return False
315
- ```
316
-
317
- #### list_snapshots() -> list
318
- 列出所有可用的快照。
319
- - 参数: 无
320
- - 返回:
321
- - list: 快照信息列表,每项包含(名称, 创建时间, 大小)
322
- - 示例:
323
- ```python
324
- # 列出所有快照
325
- snapshots = sdk.env.list_snapshots()
326
- print(f"共有 {len(snapshots)} 个快照")
327
-
328
- # 显示快照详情
329
- for name, date, size in snapshots:
330
- print(f"名称: {name}")
331
- print(f"创建时间: {date}")
332
- print(f"大小: {size/1024:.2f} KB")
333
- print("-" * 30)
334
-
335
- # 查找特定快照
336
- def find_snapshot(prefix):
337
- snapshots = sdk.env.list_snapshots()
338
- return [s for s in snapshots if s[0].startswith(prefix)]
339
- ```
340
-
341
- #### delete_snapshot(name: str) -> bool
342
- 删除指定的快照。
343
- - 参数:
344
- - name: 要删除的快照名称
345
- - 返回:
346
- - bool: 删除是否成功
347
- - 示例:
348
- ```python
349
- # 删除指定快照
350
- sdk.env.delete_snapshot("old_backup")
351
-
352
- # 清理过期快照
353
- def cleanup_old_snapshots(days=30):
354
- snapshots = sdk.env.list_snapshots()
355
- cutoff = datetime.now() - timedelta(days=days)
356
- for name, date, _ in snapshots:
357
- if date < cutoff:
358
- sdk.env.delete_snapshot(name)
359
- print(f"已删除过期快照: {name}")
360
-
361
- # 保留最新的N个快照
362
- def retain_latest_snapshots(count=5):
363
- snapshots = sdk.env.list_snapshots()
364
- if len(snapshots) > count:
365
- for name, _, _ in snapshots[count:]:
366
- sdk.env.delete_snapshot(name)
367
- ```
368
-
369
- ## 最佳实践
370
-
371
- 1. 配置组织
372
- ```python
373
- # 使用层次结构组织配置
374
- sdk.env.set("app.server.host", "localhost")
375
- sdk.env.set("app.server.port", 8080)
376
- sdk.env.set("app.database.url", "postgresql://localhost/mydb")
377
-
378
- # 使用命名空间避免冲突
379
- sdk.env.set("module1.config.timeout", 30)
380
- sdk.env.set("module2.config.timeout", 60)
381
- ```
382
-
383
- 2. 事务使用
384
- ```python
385
- # 确保数据一致性
386
- def update_configuration(config_data):
387
- with sdk.env.transaction():
388
- # 验证
389
- for key, value in config_data.items():
390
- if not validate_config(key, value):
391
- raise ValueError(f"无效的配置: {key}")
392
-
393
- # 更新
394
- for key, value in config_data.items():
395
- sdk.env.set(key, value)
396
-
397
- # 记录更新
398
- sdk.env.set("config.last_updated", time.time())
399
- ```
400
-
401
- 3. 快照管理
402
- ```python
403
- # 定期创建快照
404
- def schedule_backups():
405
- # 每日快照
406
- if not sdk.env.snapshot(f"daily_{datetime.now().strftime('%Y%m%d')}"):
407
- sdk.logger.error("每日快照创建失败")
408
-
409
- # 清理旧快照
410
- cleanup_old_snapshots(days=30)
411
-
412
- # 自动备份重要操作
413
- def safe_bulk_update(updates):
414
- snapshot_name = f"pre_update_{time.time()}"
415
- sdk.env.snapshot(snapshot_name)
416
-
417
- try:
418
- with sdk.env.transaction():
419
- for key, value in updates.items():
420
- sdk.env.set(key, value)
421
- except Exception as e:
422
- sdk.logger.error(f"批量更新失败: {e}")
423
- sdk.env.restore(snapshot_name)
424
- raise
425
- ```
426
-
427
- """
428
-
429
- import os
430
- import json
431
- import sqlite3
432
- import importlib.util
433
- import shutil
434
- import time
435
- import threading
436
- from pathlib import Path
437
- from datetime import datetime
438
- from functools import lru_cache
439
- from typing import List, Dict, Optional, Any, Set, Tuple, Union, Type, FrozenSet
440
- from .raiserr import raiserr
441
-
442
- class EnvManager:
443
- _instance = None
444
- db_path = os.path.join(os.path.dirname(__file__), "config.db")
445
- SNAPSHOT_DIR = os.path.join(os.path.dirname(__file__), "snapshots")
446
-
447
- def __new__(cls, *args, **kwargs):
448
- if not cls._instance:
449
- cls._instance = super().__new__(cls)
450
- return cls._instance
451
-
452
- def __init__(self):
453
- if not hasattr(self, "_initialized"):
454
- # 确保关键属性在初始化时都有默认值
455
- self._last_snapshot_time = time.time()
456
- self._snapshot_interval = 3600
457
- self._init_db()
458
- self._initialized = True
459
-
460
- def _init_db(self):
461
- os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
462
- os.makedirs(self.SNAPSHOT_DIR, exist_ok=True)
463
- conn = sqlite3.connect(self.db_path)
464
-
465
- # 启用WAL模式提高并发性能
466
- conn.execute("PRAGMA journal_mode=WAL")
467
- conn.execute("PRAGMA synchronous=NORMAL")
468
-
469
- cursor = conn.cursor()
470
- cursor.execute("""
471
- CREATE TABLE IF NOT EXISTS config (
472
- key TEXT PRIMARY KEY,
473
- value TEXT NOT NULL
474
- )
475
- """)
476
- conn.commit()
477
- conn.close()
478
-
479
- # 初始化自动快照调度器
480
- self._last_snapshot_time = time.time() # 初始化为当前时间
481
- self._snapshot_interval = 3600 # 默认每小时自动快照
482
-
483
- def get(self, key, default=None) -> Any:
484
- try:
485
- with sqlite3.connect(self.db_path) as conn:
486
- cursor = conn.cursor()
487
- cursor.execute("SELECT value FROM config WHERE key = ?", (key,))
488
- result = cursor.fetchone()
489
- if result:
490
- try:
491
- return json.loads(result[0])
492
- except json.JSONDecodeError:
493
- return result[0]
494
- return default
495
- except sqlite3.OperationalError as e:
496
- if "no such table" in str(e):
497
- self._init_db()
498
- return self.get(key, default)
499
- else:
500
- from . import sdk
501
- sdk.logger.error(f"数据库操作错误: {e}")
502
-
503
- def get_all_keys(self) -> list:
504
- with sqlite3.connect(self.db_path) as conn:
505
- cursor = conn.cursor()
506
- cursor.execute("SELECT key FROM config")
507
- return [row[0] for row in cursor.fetchall()]
508
-
509
- def set(self, key, value) -> bool:
510
- try:
511
- serialized_value = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
512
- with self.transaction():
513
- conn = sqlite3.connect(self.db_path)
514
- cursor = conn.cursor()
515
- cursor.execute("INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)", (key, serialized_value))
516
- conn.commit()
517
- conn.close()
518
-
519
- self._check_auto_snapshot()
520
- return True
521
- except Exception as e:
522
- return False
523
-
524
- def set_multi(self, items):
525
- try:
526
- with self.transaction():
527
- conn = sqlite3.connect(self.db_path)
528
- cursor = conn.cursor()
529
- for key, value in items.items():
530
- serialized_value = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
531
- cursor.execute("INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)",
532
- (key, serialized_value))
533
- conn.commit()
534
- conn.close()
535
-
536
- self._check_auto_snapshot()
537
- return True
538
- except Exception as e:
539
- return False
540
-
541
- def delete(self, key) -> bool:
542
- try:
543
- with self.transaction():
544
- conn = sqlite3.connect(self.db_path)
545
- cursor = conn.cursor()
546
- cursor.execute("DELETE FROM config WHERE key = ?", (key,))
547
- conn.commit()
548
- conn.close()
549
-
550
- self._check_auto_snapshot()
551
- return True
552
- except Exception as e:
553
- return False
554
- def delete_multi(self, keys) -> bool:
555
- try:
556
- with self.transaction():
557
- conn = sqlite3.connect(self.db_path)
558
- cursor = conn.cursor()
559
- cursor.executemany("DELETE FROM config WHERE key = ?", [(k,) for k in keys])
560
- conn.commit()
561
- conn.close()
562
-
563
- self._check_auto_snapshot()
564
- return True
565
- except Exception as e:
566
- return False
567
- def get_multi(self, keys) -> dict:
568
- conn = sqlite3.connect(self.db_path)
569
- cursor = conn.cursor()
570
- placeholders = ','.join(['?'] * len(keys))
571
- cursor.execute(f"SELECT key, value FROM config WHERE key IN ({placeholders})", keys)
572
- results = {row[0]: json.loads(row[1]) if row[1].startswith(('{', '[')) else row[1]
573
- for row in cursor.fetchall()}
574
- conn.close()
575
- return results
576
-
577
- def transaction(self):
578
- return self._Transaction(self)
579
-
580
- class _Transaction:
581
- def __init__(self, env_manager):
582
- self.env_manager = env_manager
583
- self.conn = None
584
- self.cursor = None
585
-
586
- def __enter__(self):
587
- self.conn = sqlite3.connect(self.env_manager.db_path)
588
- self.cursor = self.conn.cursor()
589
- self.cursor.execute("BEGIN TRANSACTION")
590
- return self
591
-
592
- def __exit__(self, exc_type, exc_val, exc_tb):
593
- if exc_type is None:
594
- self.conn.commit()
595
- else:
596
- self.conn.rollback()
597
- from .logger import logger
598
- logger.error(f"事务执行失败: {exc_val}")
599
- self.conn.close()
600
-
601
- def _check_auto_snapshot(self):
602
- from .logger import logger
603
-
604
- if not hasattr(self, '_last_snapshot_time') or self._last_snapshot_time is None:
605
- self._last_snapshot_time = time.time()
606
-
607
- if not hasattr(self, '_snapshot_interval') or self._snapshot_interval is None:
608
- self._snapshot_interval = 3600
609
-
610
- current_time = time.time()
611
-
612
- try:
613
- time_diff = current_time - self._last_snapshot_time
614
- if not isinstance(time_diff, (int, float)):
615
- raiserr.register(
616
- "ErisPulseEnvTimeDiffTypeError",
617
- doc = "时间差应为数值类型",
618
- )
619
- raiserr.ErisPulseEnvTimeDiffTypeError(
620
- f"时间差应为数值类型,实际为: {type(time_diff)}"
621
- )
622
-
623
- if not isinstance(self._snapshot_interval, (int, float)):
624
- raiserr.register(
625
- "ErisPulseEnvSnapshotIntervalTypeError",
626
- doc = "快照间隔应为数值类型",
627
- )
628
- raiserr.ErisPulseEnvSnapshotIntervalTypeError(
629
- f"快照间隔应为数值类型,实际为: {type(self._snapshot_interval)}"
630
- )
631
-
632
- if time_diff > self._snapshot_interval:
633
- self._last_snapshot_time = current_time
634
- self.snapshot(f"auto_{datetime.now().strftime('%Y%m%d_%H%M%S')}")
635
-
636
- except Exception as e:
637
- logger.error(f"自动快照检查失败: {e}")
638
- self._last_snapshot_time = current_time
639
- self._snapshot_interval = 3600
640
-
641
- def set_snapshot_interval(self, seconds):
642
- self._snapshot_interval = seconds
643
-
644
- def clear(self) -> bool:
645
- try:
646
- conn = sqlite3.connect(self.db_path)
647
- cursor = conn.cursor()
648
- cursor.execute("DELETE FROM config")
649
- conn.commit()
650
- conn.close()
651
- return True
652
- except Exception as e:
653
- return False
654
- def load_env_file(self) -> bool:
655
- try:
656
- env_file = Path("env.py")
657
- if env_file.exists():
658
- spec = importlib.util.spec_from_file_location("env_module", env_file)
659
- env_module = importlib.util.module_from_spec(spec)
660
- spec.loader.exec_module(env_module)
661
- for key, value in vars(env_module).items():
662
- if not key.startswith("__") and isinstance(value, (dict, list, str, int, float, bool)):
663
- self.set(key, value)
664
- return True
665
- except Exception as e:
666
- return False
667
- def __getattr__(self, key):
668
- try:
669
- return self.get(key)
670
- except KeyError:
671
- from .logger import logger
672
- logger.error(f"配置项 {key} 不存在")
673
-
674
- def __setattr__(self, key, value):
675
- try:
676
- self.set(key, value)
677
- except Exception as e:
678
- from .logger import logger
679
- logger.error(f"设置配置项 {key} 失败: {e}")
680
-
681
- def snapshot(self, name=None) -> str:
682
- if not name:
683
- name = datetime.now().strftime("%Y%m%d_%H%M%S")
684
- snapshot_path = os.path.join(self.SNAPSHOT_DIR, f"{name}.db")
685
-
686
- try:
687
- # 快照目录
688
- os.makedirs(self.SNAPSHOT_DIR, exist_ok=True)
689
-
690
- # 安全关闭连接
691
- if hasattr(self, "_conn") and self._conn is not None:
692
- try:
693
- self._conn.close()
694
- except Exception as e:
695
- from .logger import logger
696
- logger.warning(f"关闭数据库连接时出错: {e}")
697
-
698
- # 创建快照
699
- shutil.copy2(self.db_path, snapshot_path)
700
- from .logger import logger
701
- logger.info(f"数据库快照已创建: {snapshot_path}")
702
- return snapshot_path
703
- except Exception as e:
704
- from .logger import logger
705
- logger.error(f"创建快照失败: {e}")
706
- raise
707
-
708
- def restore(self, snapshot_name) -> bool:
709
- snapshot_path = os.path.join(self.SNAPSHOT_DIR, f"{snapshot_name}.db") \
710
- if not snapshot_name.endswith('.db') else snapshot_name
711
-
712
- if not os.path.exists(snapshot_path):
713
- from .logger import logger
714
- logger.error(f"快照文件不存在: {snapshot_path}")
715
- return False
716
-
717
- try:
718
- # 安全关闭连接
719
- if hasattr(self, "_conn") and self._conn is not None:
720
- try:
721
- self._conn.close()
722
- except Exception as e:
723
- from .logger import logger
724
- logger.warning(f"关闭数据库连接时出错: {e}")
725
-
726
- # 执行恢复操作
727
- shutil.copy2(snapshot_path, self.db_path)
728
- self._init_db() # 恢复后重新初始化数据库连接
729
- from .logger import logger
730
- logger.info(f"数据库已从快照恢复: {snapshot_path}")
731
- return True
732
- except Exception as e:
733
- from .logger import logger
734
- logger.error(f"恢复快照失败: {e}")
735
- return False
736
-
737
- def list_snapshots(self) -> list:
738
- snapshots = []
739
- for f in os.listdir(self.SNAPSHOT_DIR):
740
- if f.endswith('.db'):
741
- path = os.path.join(self.SNAPSHOT_DIR, f)
742
- stat = os.stat(path)
743
- snapshots.append((
744
- f[:-3], # 去掉.db后缀
745
- datetime.fromtimestamp(stat.st_ctime),
746
- stat.st_size
747
- ))
748
- return sorted(snapshots, key=lambda x: x[1], reverse=True)
749
-
750
- def delete_snapshot(self, snapshot_name) -> bool:
751
- snapshot_path = os.path.join(self.SNAPSHOT_DIR, f"{snapshot_name}.db") \
752
- if not snapshot_name.endswith('.db') else snapshot_name
753
-
754
- if not os.path.exists(snapshot_path):
755
- from .logger import logger
756
- logger.error(f"快照文件不存在: {snapshot_path}")
757
- return False
758
-
759
- try:
760
- os.remove(snapshot_path)
761
- from .logger import logger
762
- logger.info(f"快照已删除: {snapshot_path}")
763
- return True
764
- except Exception as e:
765
- from .logger import logger
766
- logger.error(f"删除快照失败: {e}")
767
- return False
768
-
769
- env = EnvManager()