wappa 0.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.

Potentially problematic release.


This version of wappa might be problematic. Click here for more details.

Files changed (211) hide show
  1. wappa/__init__.py +85 -0
  2. wappa/api/__init__.py +1 -0
  3. wappa/api/controllers/__init__.py +10 -0
  4. wappa/api/controllers/webhook_controller.py +441 -0
  5. wappa/api/dependencies/__init__.py +15 -0
  6. wappa/api/dependencies/whatsapp_dependencies.py +220 -0
  7. wappa/api/dependencies/whatsapp_media_dependencies.py +26 -0
  8. wappa/api/middleware/__init__.py +7 -0
  9. wappa/api/middleware/error_handler.py +158 -0
  10. wappa/api/middleware/owner.py +99 -0
  11. wappa/api/middleware/request_logging.py +184 -0
  12. wappa/api/routes/__init__.py +6 -0
  13. wappa/api/routes/health.py +102 -0
  14. wappa/api/routes/webhooks.py +211 -0
  15. wappa/api/routes/whatsapp/__init__.py +15 -0
  16. wappa/api/routes/whatsapp/whatsapp_interactive.py +429 -0
  17. wappa/api/routes/whatsapp/whatsapp_media.py +440 -0
  18. wappa/api/routes/whatsapp/whatsapp_messages.py +195 -0
  19. wappa/api/routes/whatsapp/whatsapp_specialized.py +516 -0
  20. wappa/api/routes/whatsapp/whatsapp_templates.py +431 -0
  21. wappa/api/routes/whatsapp_combined.py +35 -0
  22. wappa/cli/__init__.py +9 -0
  23. wappa/cli/main.py +199 -0
  24. wappa/core/__init__.py +6 -0
  25. wappa/core/config/__init__.py +5 -0
  26. wappa/core/config/settings.py +161 -0
  27. wappa/core/events/__init__.py +41 -0
  28. wappa/core/events/default_handlers.py +642 -0
  29. wappa/core/events/event_dispatcher.py +244 -0
  30. wappa/core/events/event_handler.py +247 -0
  31. wappa/core/events/webhook_factory.py +219 -0
  32. wappa/core/factory/__init__.py +15 -0
  33. wappa/core/factory/plugin.py +68 -0
  34. wappa/core/factory/wappa_builder.py +326 -0
  35. wappa/core/logging/__init__.py +5 -0
  36. wappa/core/logging/context.py +100 -0
  37. wappa/core/logging/logger.py +343 -0
  38. wappa/core/plugins/__init__.py +34 -0
  39. wappa/core/plugins/auth_plugin.py +169 -0
  40. wappa/core/plugins/cors_plugin.py +128 -0
  41. wappa/core/plugins/custom_middleware_plugin.py +182 -0
  42. wappa/core/plugins/database_plugin.py +235 -0
  43. wappa/core/plugins/rate_limit_plugin.py +183 -0
  44. wappa/core/plugins/redis_plugin.py +224 -0
  45. wappa/core/plugins/wappa_core_plugin.py +261 -0
  46. wappa/core/plugins/webhook_plugin.py +253 -0
  47. wappa/core/types.py +108 -0
  48. wappa/core/wappa_app.py +546 -0
  49. wappa/database/__init__.py +18 -0
  50. wappa/database/adapter.py +107 -0
  51. wappa/database/adapters/__init__.py +17 -0
  52. wappa/database/adapters/mysql_adapter.py +187 -0
  53. wappa/database/adapters/postgresql_adapter.py +169 -0
  54. wappa/database/adapters/sqlite_adapter.py +174 -0
  55. wappa/domain/__init__.py +28 -0
  56. wappa/domain/builders/__init__.py +5 -0
  57. wappa/domain/builders/message_builder.py +189 -0
  58. wappa/domain/entities/__init__.py +5 -0
  59. wappa/domain/enums/messenger_platform.py +123 -0
  60. wappa/domain/factories/__init__.py +6 -0
  61. wappa/domain/factories/media_factory.py +450 -0
  62. wappa/domain/factories/message_factory.py +497 -0
  63. wappa/domain/factories/messenger_factory.py +244 -0
  64. wappa/domain/interfaces/__init__.py +32 -0
  65. wappa/domain/interfaces/base_repository.py +94 -0
  66. wappa/domain/interfaces/cache_factory.py +85 -0
  67. wappa/domain/interfaces/cache_interface.py +199 -0
  68. wappa/domain/interfaces/expiry_repository.py +68 -0
  69. wappa/domain/interfaces/media_interface.py +311 -0
  70. wappa/domain/interfaces/messaging_interface.py +523 -0
  71. wappa/domain/interfaces/pubsub_repository.py +151 -0
  72. wappa/domain/interfaces/repository_factory.py +108 -0
  73. wappa/domain/interfaces/shared_state_repository.py +122 -0
  74. wappa/domain/interfaces/state_repository.py +123 -0
  75. wappa/domain/interfaces/tables_repository.py +215 -0
  76. wappa/domain/interfaces/user_repository.py +114 -0
  77. wappa/domain/interfaces/webhooks/__init__.py +1 -0
  78. wappa/domain/models/media_result.py +110 -0
  79. wappa/domain/models/platforms/__init__.py +15 -0
  80. wappa/domain/models/platforms/platform_config.py +104 -0
  81. wappa/domain/services/__init__.py +11 -0
  82. wappa/domain/services/tenant_credentials_service.py +56 -0
  83. wappa/messaging/__init__.py +7 -0
  84. wappa/messaging/whatsapp/__init__.py +1 -0
  85. wappa/messaging/whatsapp/client/__init__.py +5 -0
  86. wappa/messaging/whatsapp/client/whatsapp_client.py +417 -0
  87. wappa/messaging/whatsapp/handlers/__init__.py +13 -0
  88. wappa/messaging/whatsapp/handlers/whatsapp_interactive_handler.py +653 -0
  89. wappa/messaging/whatsapp/handlers/whatsapp_media_handler.py +579 -0
  90. wappa/messaging/whatsapp/handlers/whatsapp_specialized_handler.py +434 -0
  91. wappa/messaging/whatsapp/handlers/whatsapp_template_handler.py +416 -0
  92. wappa/messaging/whatsapp/messenger/__init__.py +5 -0
  93. wappa/messaging/whatsapp/messenger/whatsapp_messenger.py +904 -0
  94. wappa/messaging/whatsapp/models/__init__.py +61 -0
  95. wappa/messaging/whatsapp/models/basic_models.py +65 -0
  96. wappa/messaging/whatsapp/models/interactive_models.py +287 -0
  97. wappa/messaging/whatsapp/models/media_models.py +215 -0
  98. wappa/messaging/whatsapp/models/specialized_models.py +304 -0
  99. wappa/messaging/whatsapp/models/template_models.py +261 -0
  100. wappa/persistence/cache_factory.py +93 -0
  101. wappa/persistence/json/__init__.py +14 -0
  102. wappa/persistence/json/cache_adapters.py +271 -0
  103. wappa/persistence/json/handlers/__init__.py +1 -0
  104. wappa/persistence/json/handlers/state_handler.py +250 -0
  105. wappa/persistence/json/handlers/table_handler.py +263 -0
  106. wappa/persistence/json/handlers/user_handler.py +213 -0
  107. wappa/persistence/json/handlers/utils/__init__.py +1 -0
  108. wappa/persistence/json/handlers/utils/file_manager.py +153 -0
  109. wappa/persistence/json/handlers/utils/key_factory.py +11 -0
  110. wappa/persistence/json/handlers/utils/serialization.py +121 -0
  111. wappa/persistence/json/json_cache_factory.py +76 -0
  112. wappa/persistence/json/storage_manager.py +285 -0
  113. wappa/persistence/memory/__init__.py +14 -0
  114. wappa/persistence/memory/cache_adapters.py +271 -0
  115. wappa/persistence/memory/handlers/__init__.py +1 -0
  116. wappa/persistence/memory/handlers/state_handler.py +250 -0
  117. wappa/persistence/memory/handlers/table_handler.py +280 -0
  118. wappa/persistence/memory/handlers/user_handler.py +213 -0
  119. wappa/persistence/memory/handlers/utils/__init__.py +1 -0
  120. wappa/persistence/memory/handlers/utils/key_factory.py +11 -0
  121. wappa/persistence/memory/handlers/utils/memory_store.py +317 -0
  122. wappa/persistence/memory/handlers/utils/ttl_manager.py +235 -0
  123. wappa/persistence/memory/memory_cache_factory.py +76 -0
  124. wappa/persistence/memory/storage_manager.py +235 -0
  125. wappa/persistence/redis/README.md +699 -0
  126. wappa/persistence/redis/__init__.py +11 -0
  127. wappa/persistence/redis/cache_adapters.py +285 -0
  128. wappa/persistence/redis/ops.py +880 -0
  129. wappa/persistence/redis/redis_cache_factory.py +71 -0
  130. wappa/persistence/redis/redis_client.py +231 -0
  131. wappa/persistence/redis/redis_handler/__init__.py +26 -0
  132. wappa/persistence/redis/redis_handler/state_handler.py +176 -0
  133. wappa/persistence/redis/redis_handler/table.py +158 -0
  134. wappa/persistence/redis/redis_handler/user.py +138 -0
  135. wappa/persistence/redis/redis_handler/utils/__init__.py +12 -0
  136. wappa/persistence/redis/redis_handler/utils/key_factory.py +32 -0
  137. wappa/persistence/redis/redis_handler/utils/serde.py +146 -0
  138. wappa/persistence/redis/redis_handler/utils/tenant_cache.py +268 -0
  139. wappa/persistence/redis/redis_manager.py +189 -0
  140. wappa/processors/__init__.py +6 -0
  141. wappa/processors/base_processor.py +262 -0
  142. wappa/processors/factory.py +550 -0
  143. wappa/processors/whatsapp_processor.py +810 -0
  144. wappa/schemas/__init__.py +6 -0
  145. wappa/schemas/core/__init__.py +71 -0
  146. wappa/schemas/core/base_message.py +499 -0
  147. wappa/schemas/core/base_status.py +322 -0
  148. wappa/schemas/core/base_webhook.py +312 -0
  149. wappa/schemas/core/types.py +253 -0
  150. wappa/schemas/core/webhook_interfaces/__init__.py +48 -0
  151. wappa/schemas/core/webhook_interfaces/base_components.py +293 -0
  152. wappa/schemas/core/webhook_interfaces/universal_webhooks.py +348 -0
  153. wappa/schemas/factory.py +754 -0
  154. wappa/schemas/webhooks/__init__.py +3 -0
  155. wappa/schemas/whatsapp/__init__.py +6 -0
  156. wappa/schemas/whatsapp/base_models.py +285 -0
  157. wappa/schemas/whatsapp/message_types/__init__.py +93 -0
  158. wappa/schemas/whatsapp/message_types/audio.py +350 -0
  159. wappa/schemas/whatsapp/message_types/button.py +267 -0
  160. wappa/schemas/whatsapp/message_types/contact.py +464 -0
  161. wappa/schemas/whatsapp/message_types/document.py +421 -0
  162. wappa/schemas/whatsapp/message_types/errors.py +195 -0
  163. wappa/schemas/whatsapp/message_types/image.py +424 -0
  164. wappa/schemas/whatsapp/message_types/interactive.py +430 -0
  165. wappa/schemas/whatsapp/message_types/location.py +416 -0
  166. wappa/schemas/whatsapp/message_types/order.py +372 -0
  167. wappa/schemas/whatsapp/message_types/reaction.py +271 -0
  168. wappa/schemas/whatsapp/message_types/sticker.py +328 -0
  169. wappa/schemas/whatsapp/message_types/system.py +317 -0
  170. wappa/schemas/whatsapp/message_types/text.py +411 -0
  171. wappa/schemas/whatsapp/message_types/unsupported.py +273 -0
  172. wappa/schemas/whatsapp/message_types/video.py +344 -0
  173. wappa/schemas/whatsapp/status_models.py +479 -0
  174. wappa/schemas/whatsapp/validators.py +454 -0
  175. wappa/schemas/whatsapp/webhook_container.py +438 -0
  176. wappa/webhooks/__init__.py +17 -0
  177. wappa/webhooks/core/__init__.py +71 -0
  178. wappa/webhooks/core/base_message.py +499 -0
  179. wappa/webhooks/core/base_status.py +322 -0
  180. wappa/webhooks/core/base_webhook.py +312 -0
  181. wappa/webhooks/core/types.py +253 -0
  182. wappa/webhooks/core/webhook_interfaces/__init__.py +48 -0
  183. wappa/webhooks/core/webhook_interfaces/base_components.py +293 -0
  184. wappa/webhooks/core/webhook_interfaces/universal_webhooks.py +441 -0
  185. wappa/webhooks/factory.py +754 -0
  186. wappa/webhooks/whatsapp/__init__.py +6 -0
  187. wappa/webhooks/whatsapp/base_models.py +285 -0
  188. wappa/webhooks/whatsapp/message_types/__init__.py +93 -0
  189. wappa/webhooks/whatsapp/message_types/audio.py +350 -0
  190. wappa/webhooks/whatsapp/message_types/button.py +267 -0
  191. wappa/webhooks/whatsapp/message_types/contact.py +464 -0
  192. wappa/webhooks/whatsapp/message_types/document.py +421 -0
  193. wappa/webhooks/whatsapp/message_types/errors.py +195 -0
  194. wappa/webhooks/whatsapp/message_types/image.py +424 -0
  195. wappa/webhooks/whatsapp/message_types/interactive.py +430 -0
  196. wappa/webhooks/whatsapp/message_types/location.py +416 -0
  197. wappa/webhooks/whatsapp/message_types/order.py +372 -0
  198. wappa/webhooks/whatsapp/message_types/reaction.py +271 -0
  199. wappa/webhooks/whatsapp/message_types/sticker.py +328 -0
  200. wappa/webhooks/whatsapp/message_types/system.py +317 -0
  201. wappa/webhooks/whatsapp/message_types/text.py +411 -0
  202. wappa/webhooks/whatsapp/message_types/unsupported.py +273 -0
  203. wappa/webhooks/whatsapp/message_types/video.py +344 -0
  204. wappa/webhooks/whatsapp/status_models.py +479 -0
  205. wappa/webhooks/whatsapp/validators.py +454 -0
  206. wappa/webhooks/whatsapp/webhook_container.py +438 -0
  207. wappa-0.1.0.dist-info/METADATA +269 -0
  208. wappa-0.1.0.dist-info/RECORD +211 -0
  209. wappa-0.1.0.dist-info/WHEEL +4 -0
  210. wappa-0.1.0.dist-info/entry_points.txt +2 -0
  211. wappa-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,235 @@
1
+ """
2
+ Memory storage manager for coordinating cache operations.
3
+
4
+ Provides high-level interface for memory cache operations with TTL support,
5
+ BaseModel serialization, and thread-safe operations.
6
+ """
7
+
8
+ import logging
9
+ from typing import Any, Optional
10
+
11
+ from pydantic import BaseModel
12
+
13
+ from .handlers.utils.memory_store import get_memory_store
14
+
15
+ logger = logging.getLogger("MemoryStorageManager")
16
+
17
+
18
+ class MemoryStorageManager:
19
+ """High-level memory storage operations manager."""
20
+
21
+ def __init__(self):
22
+ self.memory_store = get_memory_store()
23
+
24
+ def _serialize_data(self, data: Any) -> Any:
25
+ """Serialize data for memory storage (BaseModel -> dict)."""
26
+ if isinstance(data, BaseModel):
27
+ return data.model_dump()
28
+ return data
29
+
30
+ def _deserialize_data(self, data: Any, model: type[BaseModel] | None = None) -> Any:
31
+ """Deserialize data from memory storage."""
32
+ if data is None:
33
+ return None
34
+
35
+ if model is not None and isinstance(data, dict):
36
+ return model.model_validate(data)
37
+
38
+ return data
39
+
40
+ async def get(
41
+ self,
42
+ cache_type: str,
43
+ tenant_id: str,
44
+ user_id: Optional[str],
45
+ key: str,
46
+ model: type[BaseModel] | None = None
47
+ ) -> Any:
48
+ """
49
+ Get value from memory cache.
50
+
51
+ Args:
52
+ cache_type: "users", "tables", or "states"
53
+ tenant_id: Tenant identifier
54
+ user_id: User identifier (required for users/states)
55
+ key: Cache key
56
+ model: Optional BaseModel for deserialization
57
+
58
+ Returns:
59
+ Cached value or None if not found/expired
60
+ """
61
+ try:
62
+ context_key = self._build_context_key(cache_type, tenant_id, user_id)
63
+ data = await self.memory_store.get(cache_type, context_key, key)
64
+ return self._deserialize_data(data, model)
65
+ except Exception as e:
66
+ logger.error(f"Failed to get key '{key}' from {cache_type} cache: {e}")
67
+ return None
68
+
69
+ async def set(
70
+ self,
71
+ cache_type: str,
72
+ tenant_id: str,
73
+ user_id: Optional[str],
74
+ key: str,
75
+ value: Any,
76
+ ttl: Optional[int] = None
77
+ ) -> bool:
78
+ """
79
+ Set value in memory cache.
80
+
81
+ Args:
82
+ cache_type: "users", "tables", or "states"
83
+ tenant_id: Tenant identifier
84
+ user_id: User identifier (required for users/states)
85
+ key: Cache key
86
+ value: Value to cache
87
+ ttl: Time to live in seconds
88
+
89
+ Returns:
90
+ True if successful, False otherwise
91
+ """
92
+ try:
93
+ context_key = self._build_context_key(cache_type, tenant_id, user_id)
94
+ serialized_value = self._serialize_data(value)
95
+ return await self.memory_store.set(cache_type, context_key, key, serialized_value, ttl)
96
+ except Exception as e:
97
+ logger.error(f"Failed to set key '{key}' in {cache_type} cache: {e}")
98
+ return False
99
+
100
+ async def delete(
101
+ self,
102
+ cache_type: str,
103
+ tenant_id: str,
104
+ user_id: Optional[str],
105
+ key: str
106
+ ) -> bool:
107
+ """
108
+ Delete key from memory cache.
109
+
110
+ Args:
111
+ cache_type: "users", "tables", or "states"
112
+ tenant_id: Tenant identifier
113
+ user_id: User identifier (required for users/states)
114
+ key: Cache key to delete
115
+
116
+ Returns:
117
+ True if deleted or didn't exist, False on error
118
+ """
119
+ try:
120
+ context_key = self._build_context_key(cache_type, tenant_id, user_id)
121
+ return await self.memory_store.delete(cache_type, context_key, key)
122
+ except Exception as e:
123
+ logger.error(f"Failed to delete key '{key}' from {cache_type} cache: {e}")
124
+ return False
125
+
126
+ async def exists(
127
+ self,
128
+ cache_type: str,
129
+ tenant_id: str,
130
+ user_id: Optional[str],
131
+ key: str
132
+ ) -> bool:
133
+ """
134
+ Check if key exists in memory cache.
135
+
136
+ Args:
137
+ cache_type: "users", "tables", or "states"
138
+ tenant_id: Tenant identifier
139
+ user_id: User identifier (required for users/states)
140
+ key: Cache key to check
141
+
142
+ Returns:
143
+ True if exists and not expired, False otherwise
144
+ """
145
+ try:
146
+ context_key = self._build_context_key(cache_type, tenant_id, user_id)
147
+ return await self.memory_store.exists(cache_type, context_key, key)
148
+ except Exception as e:
149
+ logger.error(f"Failed to check existence of key '{key}' in {cache_type} cache: {e}")
150
+ return False
151
+
152
+ async def get_ttl(
153
+ self,
154
+ cache_type: str,
155
+ tenant_id: str,
156
+ user_id: Optional[str],
157
+ key: str
158
+ ) -> int:
159
+ """
160
+ Get remaining TTL for key.
161
+
162
+ Returns:
163
+ Remaining TTL in seconds, -1 if no expiry, -2 if doesn't exist
164
+ """
165
+ try:
166
+ context_key = self._build_context_key(cache_type, tenant_id, user_id)
167
+ return await self.memory_store.get_ttl(cache_type, context_key, key)
168
+ except Exception as e:
169
+ logger.error(f"Failed to get TTL for key '{key}' in {cache_type} cache: {e}")
170
+ return -2
171
+
172
+ async def set_ttl(
173
+ self,
174
+ cache_type: str,
175
+ tenant_id: str,
176
+ user_id: Optional[str],
177
+ key: str,
178
+ ttl: int
179
+ ) -> bool:
180
+ """
181
+ Set TTL for key.
182
+
183
+ Args:
184
+ ttl: Time to live in seconds
185
+
186
+ Returns:
187
+ True if successful, False otherwise
188
+ """
189
+ try:
190
+ context_key = self._build_context_key(cache_type, tenant_id, user_id)
191
+ return await self.memory_store.set_ttl(cache_type, context_key, key, ttl)
192
+ except Exception as e:
193
+ logger.error(f"Failed to set TTL for key '{key}' in {cache_type} cache: {e}")
194
+ return False
195
+
196
+ async def get_all_keys(
197
+ self,
198
+ cache_type: str,
199
+ tenant_id: str,
200
+ user_id: Optional[str]
201
+ ) -> dict[str, Any]:
202
+ """
203
+ Get all keys for a context.
204
+
205
+ Args:
206
+ cache_type: "users", "tables", or "states"
207
+ tenant_id: Tenant identifier
208
+ user_id: User identifier (required for users/states)
209
+
210
+ Returns:
211
+ Dictionary of all non-expired key-value pairs
212
+ """
213
+ try:
214
+ context_key = self._build_context_key(cache_type, tenant_id, user_id)
215
+ return await self.memory_store.get_all_keys(cache_type, context_key)
216
+ except Exception as e:
217
+ logger.error(f"Failed to get all keys from {cache_type} cache: {e}")
218
+ return {}
219
+
220
+ def _build_context_key(self, cache_type: str, tenant_id: str, user_id: Optional[str]) -> str:
221
+ """Build context key for isolation."""
222
+ if cache_type == "tables":
223
+ # Tables only use tenant_id for context
224
+ return tenant_id
225
+ elif cache_type in ["users", "states"]:
226
+ # Users and states use tenant_id and user_id
227
+ if not user_id:
228
+ raise ValueError(f"user_id is required for {cache_type} cache")
229
+ return f"{tenant_id}_{user_id}"
230
+ else:
231
+ raise ValueError(f"Invalid cache_type: {cache_type}")
232
+
233
+
234
+ # Global storage manager instance
235
+ storage_manager = MemoryStorageManager()