infomankit 0.3.23__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 (143) hide show
  1. infoman/__init__.py +1 -0
  2. infoman/cli/README.md +378 -0
  3. infoman/cli/__init__.py +7 -0
  4. infoman/cli/commands/__init__.py +3 -0
  5. infoman/cli/commands/init.py +312 -0
  6. infoman/cli/scaffold.py +634 -0
  7. infoman/cli/templates/Makefile.template +132 -0
  8. infoman/cli/templates/app/__init__.py.template +3 -0
  9. infoman/cli/templates/app/app.py.template +4 -0
  10. infoman/cli/templates/app/models_base.py.template +18 -0
  11. infoman/cli/templates/app/models_entity_init.py.template +11 -0
  12. infoman/cli/templates/app/models_schemas_init.py.template +11 -0
  13. infoman/cli/templates/app/repository_init.py.template +11 -0
  14. infoman/cli/templates/app/routers_init.py.template +15 -0
  15. infoman/cli/templates/app/services_init.py.template +11 -0
  16. infoman/cli/templates/app/static_index.html.template +39 -0
  17. infoman/cli/templates/app/static_main.js.template +31 -0
  18. infoman/cli/templates/app/static_style.css.template +111 -0
  19. infoman/cli/templates/app/utils_init.py.template +11 -0
  20. infoman/cli/templates/config/.env.dev.template +43 -0
  21. infoman/cli/templates/config/.env.prod.template +43 -0
  22. infoman/cli/templates/config/README.md.template +28 -0
  23. infoman/cli/templates/docker/.dockerignore.template +60 -0
  24. infoman/cli/templates/docker/Dockerfile.template +47 -0
  25. infoman/cli/templates/docker/README.md.template +240 -0
  26. infoman/cli/templates/docker/docker-compose.yml.template +81 -0
  27. infoman/cli/templates/docker/mysql_custom.cnf.template +42 -0
  28. infoman/cli/templates/docker/mysql_init.sql.template +15 -0
  29. infoman/cli/templates/project/.env.example.template +1 -0
  30. infoman/cli/templates/project/.gitignore.template +60 -0
  31. infoman/cli/templates/project/Makefile.template +38 -0
  32. infoman/cli/templates/project/README.md.template +137 -0
  33. infoman/cli/templates/project/deploy.sh.template +97 -0
  34. infoman/cli/templates/project/main.py.template +10 -0
  35. infoman/cli/templates/project/manage.sh.template +97 -0
  36. infoman/cli/templates/project/pyproject.toml.template +47 -0
  37. infoman/cli/templates/project/service.sh.template +203 -0
  38. infoman/config/__init__.py +25 -0
  39. infoman/config/base.py +67 -0
  40. infoman/config/db_cache.py +237 -0
  41. infoman/config/db_relation.py +181 -0
  42. infoman/config/db_vector.py +39 -0
  43. infoman/config/jwt.py +16 -0
  44. infoman/config/llm.py +16 -0
  45. infoman/config/log.py +627 -0
  46. infoman/config/mq.py +26 -0
  47. infoman/config/settings.py +65 -0
  48. infoman/llm/__init__.py +0 -0
  49. infoman/llm/llm.py +297 -0
  50. infoman/logger/__init__.py +57 -0
  51. infoman/logger/context.py +191 -0
  52. infoman/logger/core.py +358 -0
  53. infoman/logger/filters.py +157 -0
  54. infoman/logger/formatters.py +138 -0
  55. infoman/logger/handlers.py +276 -0
  56. infoman/logger/metrics.py +160 -0
  57. infoman/performance/README.md +583 -0
  58. infoman/performance/__init__.py +19 -0
  59. infoman/performance/cli.py +215 -0
  60. infoman/performance/config.py +166 -0
  61. infoman/performance/reporter.py +519 -0
  62. infoman/performance/runner.py +303 -0
  63. infoman/performance/standards.py +222 -0
  64. infoman/service/__init__.py +8 -0
  65. infoman/service/app.py +67 -0
  66. infoman/service/core/__init__.py +0 -0
  67. infoman/service/core/auth.py +105 -0
  68. infoman/service/core/lifespan.py +132 -0
  69. infoman/service/core/monitor.py +57 -0
  70. infoman/service/core/response.py +37 -0
  71. infoman/service/exception/__init__.py +7 -0
  72. infoman/service/exception/error.py +274 -0
  73. infoman/service/exception/exception.py +25 -0
  74. infoman/service/exception/handler.py +238 -0
  75. infoman/service/infrastructure/__init__.py +8 -0
  76. infoman/service/infrastructure/base.py +212 -0
  77. infoman/service/infrastructure/db_cache/__init__.py +8 -0
  78. infoman/service/infrastructure/db_cache/manager.py +194 -0
  79. infoman/service/infrastructure/db_relation/__init__.py +41 -0
  80. infoman/service/infrastructure/db_relation/manager.py +300 -0
  81. infoman/service/infrastructure/db_relation/manager_pro.py +408 -0
  82. infoman/service/infrastructure/db_relation/mysql.py +52 -0
  83. infoman/service/infrastructure/db_relation/pgsql.py +54 -0
  84. infoman/service/infrastructure/db_relation/sqllite.py +25 -0
  85. infoman/service/infrastructure/db_vector/__init__.py +40 -0
  86. infoman/service/infrastructure/db_vector/manager.py +201 -0
  87. infoman/service/infrastructure/db_vector/qdrant.py +322 -0
  88. infoman/service/infrastructure/mq/__init__.py +15 -0
  89. infoman/service/infrastructure/mq/manager.py +178 -0
  90. infoman/service/infrastructure/mq/nats/__init__.py +0 -0
  91. infoman/service/infrastructure/mq/nats/nats_client.py +57 -0
  92. infoman/service/infrastructure/mq/nats/nats_event_router.py +25 -0
  93. infoman/service/launch.py +284 -0
  94. infoman/service/middleware/__init__.py +7 -0
  95. infoman/service/middleware/base.py +41 -0
  96. infoman/service/middleware/logging.py +51 -0
  97. infoman/service/middleware/rate_limit.py +301 -0
  98. infoman/service/middleware/request_id.py +21 -0
  99. infoman/service/middleware/white_list.py +24 -0
  100. infoman/service/models/__init__.py +8 -0
  101. infoman/service/models/base.py +441 -0
  102. infoman/service/models/type/embed.py +70 -0
  103. infoman/service/routers/__init__.py +18 -0
  104. infoman/service/routers/health_router.py +311 -0
  105. infoman/service/routers/monitor_router.py +44 -0
  106. infoman/service/utils/__init__.py +8 -0
  107. infoman/service/utils/cache/__init__.py +0 -0
  108. infoman/service/utils/cache/cache.py +192 -0
  109. infoman/service/utils/module_loader.py +10 -0
  110. infoman/service/utils/parse.py +10 -0
  111. infoman/service/utils/resolver/__init__.py +8 -0
  112. infoman/service/utils/resolver/base.py +47 -0
  113. infoman/service/utils/resolver/resp.py +102 -0
  114. infoman/service/vector/__init__.py +20 -0
  115. infoman/service/vector/base.py +56 -0
  116. infoman/service/vector/qdrant.py +125 -0
  117. infoman/service/vector/service.py +67 -0
  118. infoman/utils/__init__.py +2 -0
  119. infoman/utils/decorators/__init__.py +8 -0
  120. infoman/utils/decorators/cache.py +137 -0
  121. infoman/utils/decorators/retry.py +99 -0
  122. infoman/utils/decorators/safe_execute.py +99 -0
  123. infoman/utils/decorators/timing.py +99 -0
  124. infoman/utils/encryption/__init__.py +8 -0
  125. infoman/utils/encryption/aes.py +66 -0
  126. infoman/utils/encryption/ecc.py +108 -0
  127. infoman/utils/encryption/rsa.py +112 -0
  128. infoman/utils/file/__init__.py +0 -0
  129. infoman/utils/file/handler.py +22 -0
  130. infoman/utils/hash/__init__.py +0 -0
  131. infoman/utils/hash/hash.py +61 -0
  132. infoman/utils/http/__init__.py +8 -0
  133. infoman/utils/http/client.py +62 -0
  134. infoman/utils/http/info.py +94 -0
  135. infoman/utils/http/result.py +19 -0
  136. infoman/utils/notification/__init__.py +8 -0
  137. infoman/utils/notification/feishu.py +35 -0
  138. infoman/utils/text/__init__.py +8 -0
  139. infoman/utils/text/extractor.py +111 -0
  140. infomankit-0.3.23.dist-info/METADATA +632 -0
  141. infomankit-0.3.23.dist-info/RECORD +143 -0
  142. infomankit-0.3.23.dist-info/WHEEL +4 -0
  143. infomankit-0.3.23.dist-info/entry_points.txt +5 -0
@@ -0,0 +1,99 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+
4
+ """
5
+ # Time :2025/6/22 12:07
6
+ # Author :Maxwell
7
+ # Description:
8
+ """
9
+ import time
10
+ import functools
11
+ from typing import Callable, TypeVar, Any, Optional, Union, Dict, List, Tuple
12
+ from inspect import iscoroutinefunction
13
+ from infoman.logger import logger
14
+
15
+
16
+ T = TypeVar("T")
17
+ F = TypeVar("F", bound=Callable[..., Any])
18
+
19
+
20
+ def safe_execute(
21
+ func: F, default_return: Any = None, log_error: bool = True, reraise: bool = False
22
+ ) -> F:
23
+ """
24
+ 安全执行装饰器 - 捕获函数执行过程中的异常,防止程序崩溃
25
+
26
+ 参数:
27
+ default_return: 发生异常时的默认返回值
28
+ log_error: 是否记录错误日志
29
+ reraise: 是否重新抛出异常
30
+
31
+ 示例:
32
+ @safe_execute
33
+ def my_function():
34
+ # 可能抛出异常的代码
35
+
36
+ @safe_execute(default_return=[], log_error=True)
37
+ async def my_async_function():
38
+ # 可能抛出异常的异步代码
39
+ """
40
+ # 处理直接使用不带参数的装饰器情况
41
+ if callable(func) and not isinstance(func, type):
42
+
43
+ @functools.wraps(func)
44
+ async def async_wrapper(*args, **kwargs):
45
+ try:
46
+ return await func(*args, **kwargs)
47
+ except Exception as e:
48
+ if log_error:
49
+ logger.error(f"Error in {func.__name__}: {e}", exc_info=True)
50
+ if reraise:
51
+ raise
52
+ return default_return
53
+
54
+ @functools.wraps(func)
55
+ def sync_wrapper(*args, **kwargs):
56
+ try:
57
+ return func(*args, **kwargs)
58
+ except Exception as e:
59
+ if log_error:
60
+ logger.error(f"Error in {func.__name__}: {e}", exc_info=True)
61
+ if reraise:
62
+ raise
63
+ return default_return
64
+
65
+ if iscoroutinefunction(func):
66
+ return async_wrapper
67
+ else:
68
+ return sync_wrapper
69
+
70
+ # 处理带参数的装饰器情况
71
+ def decorator(fn: F) -> F:
72
+ @functools.wraps(fn)
73
+ async def async_wrapper(*args, **kwargs):
74
+ try:
75
+ return await fn(*args, **kwargs)
76
+ except Exception as e:
77
+ if log_error:
78
+ logger.error(f"Error in {fn.__name__}: {e}", exc_info=True)
79
+ if reraise:
80
+ raise
81
+ return default_return
82
+
83
+ @functools.wraps(fn)
84
+ def sync_wrapper(*args, **kwargs):
85
+ try:
86
+ return fn(*args, **kwargs)
87
+ except Exception as e:
88
+ if log_error:
89
+ logger.error(f"Error in {fn.__name__}: {e}", exc_info=True)
90
+ if reraise:
91
+ raise
92
+ return default_return
93
+
94
+ if iscoroutinefunction(fn):
95
+ return async_wrapper
96
+ else:
97
+ return sync_wrapper
98
+
99
+ return decorator
@@ -0,0 +1,99 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+
4
+ """
5
+ # Time :2025/6/22 12:08
6
+ # Author :Maxwell
7
+ # Description:
8
+ """
9
+ import time
10
+ import functools
11
+ from contextlib import contextmanager
12
+ from typing import Callable, TypeVar, Any, Optional, Union, Dict, List, Tuple
13
+ from infoman.logger import logger
14
+ from inspect import iscoroutinefunction
15
+
16
+ T = TypeVar("T")
17
+ F = TypeVar("F", bound=Callable[..., Any])
18
+
19
+
20
+ @contextmanager
21
+ def timing_context(mark):
22
+ start_time = time.time()
23
+ try:
24
+ yield
25
+ finally:
26
+ elapsed = time.time() - start_time
27
+ logger.info(f"{mark}: {elapsed:.4f}s")
28
+
29
+
30
+ def timing(
31
+ label: str = "执行时间",
32
+ threshold_ms: Optional[float] = None,
33
+ log_level: str = "info",
34
+ ) -> Callable[[F], F]:
35
+ """
36
+ 计时装饰器 - 测量函数执行时间并记录日志
37
+
38
+ 参数:
39
+ label: 日志标签
40
+ threshold_ms: 时间阈值(毫秒),超过此值才记录日志
41
+ log_level: 日志级别 (debug, info, warning, error, critical)
42
+
43
+ 示例:
44
+ @timing("数据处理")
45
+ def process_data():
46
+ # 处理数据的代码
47
+
48
+ @timing(threshold_ms=100) # 只记录执行时间超过100ms的调用
49
+ async def fetch_data():
50
+ # 获取数据的异步代码
51
+ """
52
+
53
+ def get_logger_method(level_name: str) -> Callable:
54
+ """获取对应日志级别的方法"""
55
+ level_map = {
56
+ "debug": logger.debug,
57
+ "info": logger.info,
58
+ "warning": logger.warning,
59
+ "error": logger.error,
60
+ }
61
+ return level_map.get(level_name.lower(), logger.info)
62
+
63
+ log_method = get_logger_method(log_level)
64
+
65
+ def decorator(func: F) -> F:
66
+ @functools.wraps(func)
67
+ async def async_wrapper(*args, **kwargs):
68
+ start_time = time.perf_counter()
69
+ result = await func(*args, **kwargs)
70
+ elapsed_time = time.perf_counter() - start_time
71
+ elapsed_ms = elapsed_time * 1000
72
+
73
+ if threshold_ms is None or elapsed_ms > threshold_ms:
74
+ log_method(
75
+ f"{label}: {func.__name__}, {elapsed_time:.4f}s ({elapsed_ms:.2f}ms)"
76
+ )
77
+
78
+ return result
79
+
80
+ @functools.wraps(func)
81
+ def sync_wrapper(*args, **kwargs):
82
+ start_time = time.perf_counter()
83
+ result = func(*args, **kwargs)
84
+ elapsed_time = time.perf_counter() - start_time
85
+ elapsed_ms = elapsed_time * 1000
86
+
87
+ if threshold_ms is None or elapsed_ms > threshold_ms:
88
+ log_method(
89
+ f"{label}: {func.__name__}, {elapsed_time:.4f}s ({elapsed_ms:.2f}ms)"
90
+ )
91
+
92
+ return result
93
+
94
+ if iscoroutinefunction(func):
95
+ return async_wrapper
96
+ else:
97
+ return sync_wrapper
98
+
99
+ return decorator
@@ -0,0 +1,8 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+
4
+ """
5
+ # Time :2025/1/4 11:38
6
+ # Author :Maxwell
7
+ # Description:
8
+ """
@@ -0,0 +1,66 @@
1
+ import os
2
+ import base64
3
+
4
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
5
+ from cryptography.hazmat.primitives import padding
6
+ from cryptography.exceptions import InvalidKey, UnsupportedAlgorithm
7
+
8
+
9
+ class AESCipher:
10
+ BLOCK_SIZE = algorithms.AES.block_size
11
+ KEY_SIZE = 32
12
+ IV_SIZE = int(BLOCK_SIZE / 8)
13
+
14
+ def __init__(self, key: bytes = None):
15
+ if key:
16
+ if len(key) != self.KEY_SIZE:
17
+ raise ValueError(f"Key must be {self.KEY_SIZE} bytes long.")
18
+ self.key = key
19
+ else:
20
+ self.key = os.urandom(self.KEY_SIZE)
21
+
22
+ def encrypt(self, plaintext: str) -> str:
23
+ try:
24
+ iv = os.urandom(self.IV_SIZE)
25
+ padder = padding.PKCS7(self.BLOCK_SIZE).padder()
26
+ padded_data = padder.update(plaintext.encode("utf-8")) + padder.finalize()
27
+ cipher = Cipher(algorithms.AES(self.key), modes.CBC(iv))
28
+ encryptor = cipher.encryptor()
29
+ ciphertext = encryptor.update(padded_data) + encryptor.finalize()
30
+ return base64.b64encode(iv + ciphertext).decode("utf-8")
31
+ except ValueError as e:
32
+ raise ValueError(f"Encryption failed: {str(e)}")
33
+ except InvalidKey:
34
+ raise ValueError("Encryption failed: Invalid key.")
35
+ except UnsupportedAlgorithm:
36
+ raise ValueError("Encryption failed: Unsupported algorithm.")
37
+ except Exception as e:
38
+ raise ValueError(f"Encryption failed: {str(e)}")
39
+
40
+ def decrypt(self, ciphertext: str) -> str:
41
+ try:
42
+ encrypted_data = base64.b64decode(ciphertext.encode("utf-8"))
43
+ iv = encrypted_data[: self.IV_SIZE]
44
+ ciphertext = encrypted_data[self.IV_SIZE:]
45
+ cipher = Cipher(algorithms.AES(self.key), modes.CBC(iv))
46
+ decryptor = cipher.decryptor()
47
+ padded_data = decryptor.update(ciphertext) + decryptor.finalize()
48
+ unpadder = padding.PKCS7(self.BLOCK_SIZE).unpadder()
49
+ plaintext = unpadder.update(padded_data) + unpadder.finalize()
50
+ return plaintext.decode("utf-8")
51
+ except ValueError as e:
52
+ raise ValueError(f"Decryption failed: {str(e)}")
53
+ except InvalidKey:
54
+ raise ValueError("Decryption failed: Invalid key.")
55
+ except UnsupportedAlgorithm:
56
+ raise ValueError("Decryption failed: Unsupported algorithm.")
57
+ except Exception as e:
58
+ raise ValueError(f"Decryption failed: {str(e)}")
59
+
60
+ def get_key(self) -> str:
61
+ return base64.b64encode(self.key).decode("utf-8")
62
+
63
+ @classmethod
64
+ def get_key_bytes(cls, base64_bytes: bytes) -> bytes:
65
+ base64_str = base64_bytes.decode("utf-8")
66
+ return base64.b64decode(base64_str)
@@ -0,0 +1,108 @@
1
+ import os
2
+ from cryptography.hazmat.primitives.asymmetric import ec
3
+ from cryptography.hazmat.primitives import serialization, hashes
4
+ from cryptography.hazmat.primitives.kdf.hkdf import HKDF
5
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
6
+ from cryptography.hazmat.primitives import padding
7
+ from cryptography.exceptions import InvalidKey, UnsupportedAlgorithm
8
+
9
+
10
+ class ECCCipher:
11
+ CURVE = ec.SECP521R1()
12
+ HASH_ALGORITHM = hashes.SHA512()
13
+ HASH_LENGTH = 64
14
+ DERIVED_KEY_LENGTH = 64
15
+ AES_KEY_LENGTH = 32
16
+ IV_LENGTH = 16
17
+ INFO = b"ecc-encryption"
18
+
19
+ def __init__(self, private_key=None, public_key=None):
20
+ if private_key and public_key:
21
+ self.private_key = private_key
22
+ self.public_key = public_key
23
+ else:
24
+ self.private_key, self.public_key = self.generate_key_pair()
25
+
26
+ def generate_key_pair(self):
27
+ private_key = ec.generate_private_key(self.CURVE)
28
+ public_key = private_key.public_key()
29
+ return private_key, public_key
30
+
31
+ def encrypt(self, plaintext: bytes, peer_public_key) -> bytes:
32
+ try:
33
+ shared_key = self.private_key.exchange(ec.ECDH(), peer_public_key)
34
+ derived_key = HKDF(
35
+ algorithm=self.HASH_ALGORITHM,
36
+ length=self.DERIVED_KEY_LENGTH,
37
+ salt=None,
38
+ info=self.INFO,
39
+ ).derive(shared_key)
40
+ iv = os.urandom(self.IV_LENGTH)
41
+ cipher = Cipher(
42
+ algorithms.AES(derived_key[: self.AES_KEY_LENGTH]), modes.CBC(iv)
43
+ )
44
+ encryptor = cipher.encryptor()
45
+ padder = padding.PKCS7(algorithms.AES.block_size).padder()
46
+ padded_data = padder.update(plaintext) + padder.finalize()
47
+ ciphertext = encryptor.update(padded_data) + encryptor.finalize()
48
+ return iv + ciphertext
49
+ except ValueError as e:
50
+ raise ValueError(f"Encryption failed: {str(e)}")
51
+ except InvalidKey:
52
+ raise ValueError("Encryption failed: Invalid public key.")
53
+ except UnsupportedAlgorithm:
54
+ raise ValueError("Encryption failed: Unsupported algorithm.")
55
+ except Exception as e:
56
+ raise ValueError(f"Encryption failed: {str(e)}")
57
+
58
+ def decrypt(self, ciphertext: bytes, peer_public_key) -> bytes:
59
+ try:
60
+ iv = ciphertext[: self.IV_LENGTH]
61
+ ciphertext = ciphertext[self.IV_LENGTH :]
62
+ shared_key = self.private_key.exchange(ec.ECDH(), peer_public_key)
63
+ derived_key = HKDF(
64
+ algorithm=self.HASH_ALGORITHM,
65
+ length=self.DERIVED_KEY_LENGTH,
66
+ salt=None,
67
+ info=self.INFO,
68
+ ).derive(shared_key)
69
+ cipher = Cipher(
70
+ algorithms.AES(derived_key[: self.AES_KEY_LENGTH]), modes.CBC(iv)
71
+ )
72
+ decryptor = cipher.decryptor()
73
+ padded_data = decryptor.update(ciphertext) + decryptor.finalize()
74
+ unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
75
+ plaintext = unpadder.update(padded_data) + unpadder.finalize()
76
+ return plaintext
77
+ except ValueError as e:
78
+ raise ValueError(f"Decryption failed: {str(e)}")
79
+ except InvalidKey:
80
+ raise ValueError("Decryption failed: Invalid private key.")
81
+ except UnsupportedAlgorithm:
82
+ raise ValueError("Decryption failed: Unsupported algorithm.")
83
+ except Exception as e:
84
+ raise ValueError(f"Decryption failed: {str(e)}")
85
+
86
+ def serialize_private_key(self) -> bytes:
87
+ return self.private_key.private_bytes(
88
+ encoding=serialization.Encoding.PEM,
89
+ format=serialization.PrivateFormat.PKCS8,
90
+ encryption_algorithm=serialization.NoEncryption(),
91
+ )
92
+
93
+ def serialize_public_key(self) -> bytes:
94
+ return self.public_key.public_bytes(
95
+ encoding=serialization.Encoding.PEM,
96
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
97
+ )
98
+
99
+ @staticmethod
100
+ def deserialize_private_key(private_key_pem: bytes):
101
+ return serialization.load_pem_private_key(
102
+ private_key_pem,
103
+ password=None,
104
+ )
105
+
106
+ @staticmethod
107
+ def deserialize_public_key(public_key_pem: bytes):
108
+ return serialization.load_pem_public_key(public_key_pem)
@@ -0,0 +1,112 @@
1
+ import time
2
+
3
+ from cryptography.hazmat.primitives.asymmetric import rsa, padding
4
+ from cryptography.hazmat.primitives import hashes, serialization
5
+ from cryptography.exceptions import InvalidKey, UnsupportedAlgorithm
6
+ from cryptography.hazmat.backends import default_backend
7
+
8
+
9
+ class RSACipher:
10
+ HASH_ALGORITHM = hashes.SHA512()
11
+ HASH_LENGTH = 64
12
+ PADDING_OVERHEAD = 2 * HASH_LENGTH + 2
13
+ KEY_SIZE = 4096
14
+ MAX_ENCRYPT_LENGTH = (KEY_SIZE // 8) - PADDING_OVERHEAD
15
+
16
+ def __init__(self, private_key=None, public_key=None):
17
+ if private_key:
18
+ self.private_key = private_key
19
+ if public_key:
20
+ self.public_key = public_key
21
+ if not private_key and not public_key:
22
+ self.private_key, self.public_key = self.generate_key_pair()
23
+
24
+ def generate_key_pair(self):
25
+ private_key = rsa.generate_private_key(
26
+ public_exponent=65537,
27
+ key_size=self.KEY_SIZE,
28
+ )
29
+ public_key = private_key.public_key()
30
+ return private_key, public_key
31
+
32
+ def encrypt(self, plaintext: bytes) -> bytes:
33
+ try:
34
+ if len(plaintext) > self.MAX_ENCRYPT_LENGTH:
35
+ raise ValueError(
36
+ f"Plaintext too long. Max length is {self.MAX_ENCRYPT_LENGTH} bytes."
37
+ )
38
+
39
+ return self.public_key.encrypt(
40
+ plaintext,
41
+ padding.OAEP(
42
+ mgf=padding.MGF1(algorithm=self.HASH_ALGORITHM),
43
+ algorithm=self.HASH_ALGORITHM,
44
+ label=None,
45
+ ),
46
+ )
47
+ except ValueError as e:
48
+ raise ValueError(f"Encryption failed: {str(e)}")
49
+ except InvalidKey:
50
+ raise ValueError("Encryption failed: Invalid public key.")
51
+ except UnsupportedAlgorithm:
52
+ raise ValueError("Encryption failed: Unsupported algorithm.")
53
+ except Exception as e:
54
+ raise ValueError(f"Encryption failed: {str(e)}")
55
+
56
+ def decrypt(self, ciphertext: bytes) -> bytes:
57
+ try:
58
+ return self.private_key.decrypt(
59
+ ciphertext,
60
+ padding.OAEP(
61
+ mgf=padding.MGF1(algorithm=self.HASH_ALGORITHM),
62
+ algorithm=self.HASH_ALGORITHM,
63
+ label=None,
64
+ ),
65
+ )
66
+ except ValueError as e:
67
+ raise ValueError(f"Decryption failed: {str(e)}")
68
+ except InvalidKey:
69
+ raise ValueError("Decryption failed: Invalid private key.")
70
+ except UnsupportedAlgorithm:
71
+ raise ValueError("Decryption failed: Unsupported algorithm.")
72
+ except Exception as e:
73
+ raise ValueError(f"Decryption failed: {str(e)}")
74
+
75
+ def serialize_private_key(self) -> bytes:
76
+ return self.private_key.private_bytes(
77
+ encoding=serialization.Encoding.PEM,
78
+ format=serialization.PrivateFormat.PKCS8,
79
+ encryption_algorithm=serialization.NoEncryption(),
80
+ )
81
+
82
+ def serialize_public_key(self) -> bytes:
83
+ return self.public_key.public_bytes(
84
+ encoding=serialization.Encoding.PEM,
85
+ format=serialization.PublicFormat.SubjectPublicKeyInfo,
86
+ )
87
+
88
+ @staticmethod
89
+ def deserialize_private_key(private_key_pem: bytes):
90
+ try:
91
+ return serialization.load_pem_private_key(
92
+ private_key_pem, password=None, backend=default_backend()
93
+ )
94
+ except ValueError as e:
95
+ print(f"Error deserializing private key: {e}")
96
+ raise
97
+ except Exception as e:
98
+ print(f"Unexpected error deserializing private key: {e}")
99
+ raise
100
+
101
+ @staticmethod
102
+ def deserialize_public_key(public_key_pem: bytes):
103
+ try:
104
+ return serialization.load_pem_public_key(
105
+ public_key_pem, backend=default_backend()
106
+ )
107
+ except ValueError as e:
108
+ print(f"Error deserializing public key: {e}")
109
+ raise
110
+ except Exception as e:
111
+ print(f"Unexpected error deserializing public key: {e}")
112
+ raise
File without changes
@@ -0,0 +1,22 @@
1
+ import aiofiles
2
+
3
+
4
+ class AsyncFileHandler:
5
+ def __init__(self, file_path: str):
6
+ self.file_path = file_path
7
+
8
+ async def read_file(self, binary=False):
9
+ mode = "rb" if binary else "r"
10
+ async with aiofiles.open(self.file_path, mode=mode) as file:
11
+ content = await file.read()
12
+ return content
13
+
14
+ async def write_file(self, content, binary=False):
15
+ mode = "wb" if binary else "w"
16
+ async with aiofiles.open(self.file_path, mode=mode) as file:
17
+ await file.write(content)
18
+
19
+ async def append_file(self, content, binary=False):
20
+ mode = "ab" if binary else "a"
21
+ async with aiofiles.open(self.file_path, mode=mode) as file:
22
+ await file.write(content)
File without changes
@@ -0,0 +1,61 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+
4
+ """
5
+ # Time :2025/6/21 19:36
6
+ # Author :Maxwell
7
+ # Description:
8
+ """
9
+ import os
10
+ import hashlib
11
+ import uuid
12
+ import time
13
+ import random
14
+
15
+
16
+ class HashManager(object):
17
+
18
+ @classmethod
19
+ def md5(cls, content: str) -> str:
20
+ if not content:
21
+ content = ""
22
+ md5_hash = hashlib.md5()
23
+ md5_hash.update(content.encode("utf-8"))
24
+ return md5_hash.hexdigest()
25
+
26
+ @classmethod
27
+ def sha256(cls, content: str) -> str:
28
+ if not content:
29
+ content = ""
30
+ sha256_hash = hashlib.sha256()
31
+ sha256_hash.update(content.encode("utf-8"))
32
+ return sha256_hash.hexdigest().upper()
33
+
34
+ @classmethod
35
+ def is_sha256(cls, string):
36
+ if len(string) != 64:
37
+ return False
38
+ try:
39
+ hashlib.sha256(string.encode()).hexdigest()
40
+ return True
41
+ except ValueError:
42
+ return False
43
+
44
+ @classmethod
45
+ def uuid(cls) -> str:
46
+ random_part = random.getrandbits(128)
47
+ unique_str = f"{uuid.uuid1().hex}_{int(time.time())}_{random_part}"
48
+ return hashlib.sha256(unique_str.encode()).hexdigest().upper()
49
+
50
+ @classmethod
51
+ def time_hash(cls) -> str:
52
+ pid = os.getpid()
53
+ time_ns = time.time_ns()
54
+ random_id = random.randint(0, 100_0000_0000)
55
+ return f"{pid}-{time_ns}-{random_id}"
56
+
57
+ @classmethod
58
+ def time_and_random(cls) -> int:
59
+ time_ns = time.time_ns()
60
+ random_id = str(random.randint(0, 99999999)).zfill(8)
61
+ return int(f"{random_id}{time_ns}")
@@ -0,0 +1,8 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+
4
+ """
5
+ # Time :2024/7/29 14:25
6
+ # Author :Maxwell
7
+ # Description:
8
+ """
@@ -0,0 +1,62 @@
1
+ # !/usr/bin/env python
2
+ # -*-coding:utf-8 -*-
3
+
4
+ """
5
+ # Time :2024/7/29 14:25
6
+ # Author :Maxwell
7
+ # Description:
8
+ """
9
+ import aiohttp
10
+ from infoman.utils.http.result import HttpResult
11
+
12
+
13
+ class HttpAsyncClient:
14
+
15
+ @staticmethod
16
+ async def post(url, headers=None, data=None, json=None, files=None) -> HttpResult | None:
17
+ if data:
18
+ form_data = aiohttp.FormData()
19
+ for key, value in data.items():
20
+ form_data.add_field(key, value)
21
+
22
+ if files:
23
+ for key, file in files.items():
24
+ form_data.add_field(
25
+ key,
26
+ file,
27
+ filename="file",
28
+ content_type="application/octet-stream",
29
+ )
30
+
31
+ async with aiohttp.ClientSession() as session:
32
+ async with session.post(
33
+ url, headers=headers, data=form_data
34
+ ) as response:
35
+ succeed = response.status == 200
36
+ content = await response.read()
37
+ text = await response.text()
38
+ message = f"{response.status}:{response.reason}"
39
+ return HttpResult(
40
+ succeed=succeed, content=content, text=text, message=message
41
+ )
42
+
43
+ if json:
44
+ async with aiohttp.ClientSession() as session:
45
+ async with session.post(url, headers=headers, json=json) as response:
46
+ succeed = response.status == 200
47
+ content = await response.read()
48
+ text = await response.text()
49
+ message = f"{response.status}:{response.reason}"
50
+ return HttpResult(
51
+ succeed=succeed, content=content, text=text, message=message
52
+ )
53
+ return None
54
+
55
+ @staticmethod
56
+ async def get_content(url) -> HttpResult:
57
+ async with aiohttp.ClientSession() as session:
58
+ async with session.get(url) as response:
59
+ succeed = response.status == 200
60
+ content = await response.read()
61
+ message = f"{response.status}:{response.reason}"
62
+ return HttpResult(succeed=succeed, content=content, message=message)