zalobot-python 0.1.0__tar.gz → 0.1.2__tar.gz
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.
- {zalobot_python-0.1.0 → zalobot_python-0.1.2}/PKG-INFO +1 -1
- {zalobot_python-0.1.0 → zalobot_python-0.1.2}/pyproject.toml +1 -1
- {zalobot_python-0.1.0 → zalobot_python-0.1.2}/src/zalobot_python/__init__.py +9 -2
- {zalobot_python-0.1.0 → zalobot_python-0.1.2}/src/zalobot_python/models.py +11 -5
- {zalobot_python-0.1.0 → zalobot_python-0.1.2}/src/zalobot_python/zalobot.py +28 -13
- {zalobot_python-0.1.0 → zalobot_python-0.1.2}/README.md +0 -0
- {zalobot_python-0.1.0 → zalobot_python-0.1.2}/src/zalobot_python/config.py +0 -0
- {zalobot_python-0.1.0 → zalobot_python-0.1.2}/src/zalobot_python/py.typed +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
from .zalobot import ZaloBot
|
|
1
|
+
from .zalobot import ZaloBot, WebhookHandler
|
|
2
2
|
from .models import (
|
|
3
|
+
SuccessfulResponse,
|
|
4
|
+
ErrorResponse,
|
|
5
|
+
ZaloAPIResponse,
|
|
3
6
|
BotInfo,
|
|
4
7
|
WebhookInfo,
|
|
5
8
|
MessageInfo,
|
|
@@ -8,11 +11,15 @@ from .models import (
|
|
|
8
11
|
Chat,
|
|
9
12
|
Message,
|
|
10
13
|
Event,
|
|
11
|
-
ZaloAPIError
|
|
14
|
+
ZaloAPIError,
|
|
12
15
|
)
|
|
13
16
|
|
|
14
17
|
__all__ = [
|
|
18
|
+
"SuccessfulResponse",
|
|
19
|
+
"ErrorResponse",
|
|
20
|
+
"ZaloAPIResponse",
|
|
15
21
|
"ZaloBot",
|
|
22
|
+
"WebhookHandler",
|
|
16
23
|
"BotInfo",
|
|
17
24
|
"WebhookInfo",
|
|
18
25
|
"MessageInfo",
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
from enum import StrEnum
|
|
2
|
-
from typing import Literal, TypeVar, override
|
|
2
|
+
from typing import Literal, TypeVar, override, Annotated
|
|
3
3
|
from pydantic import BaseModel, Field
|
|
4
4
|
|
|
5
5
|
class Result(BaseModel):
|
|
6
|
-
"""Represents the result field in the API successful response"""
|
|
6
|
+
"""Represents the result field in the Zalo API successful response"""
|
|
7
7
|
pass
|
|
8
8
|
|
|
9
9
|
T = TypeVar("T", bound=Result)
|
|
10
10
|
class SuccessfulResponse[T](BaseModel):
|
|
11
|
+
"""Represents the successful response of the Zalo API"""
|
|
11
12
|
ok: Literal[True] = True
|
|
12
13
|
result: T = Field(description="The result when the API call is successful.")
|
|
13
14
|
|
|
14
15
|
class ErrorResponse(BaseModel):
|
|
16
|
+
"""Represents the error response of Zalo API"""
|
|
15
17
|
ok: Literal[False] = False
|
|
16
18
|
description: str = Field(description="The description of the error")
|
|
17
19
|
error_code: int = Field(description="The error code")
|
|
18
20
|
|
|
19
|
-
type
|
|
21
|
+
type ZaloAPIResponse[T] = Annotated[
|
|
22
|
+
SuccessfulResponse[T] | ErrorResponse,
|
|
23
|
+
"Represents the response of the Zalo API"
|
|
24
|
+
]
|
|
20
25
|
|
|
21
26
|
class ZaloAPIError(BaseException):
|
|
27
|
+
"""Exception when using the Zalo API"""
|
|
22
28
|
def __init__(self, error_code: int, description: str):
|
|
23
29
|
self.error_code: int = error_code
|
|
24
30
|
self.description: str = description
|
|
@@ -43,20 +49,20 @@ class MessageInfo(Result):
|
|
|
43
49
|
message_id: str
|
|
44
50
|
date: int
|
|
45
51
|
|
|
46
|
-
|
|
47
52
|
class EventName(StrEnum):
|
|
48
53
|
TEXT_RECEIVED = "message.text.received"
|
|
49
54
|
IMAGE_RECEIVED = "message.image.received"
|
|
50
55
|
STICKER_RECEIVED = "message.sticker.received"
|
|
51
56
|
UNSUPPORTED_RECEIVED = "message.unsupported.received"
|
|
52
57
|
|
|
53
|
-
|
|
54
58
|
class From(BaseModel):
|
|
59
|
+
"""Sender information"""
|
|
55
60
|
id: str
|
|
56
61
|
display_name: str
|
|
57
62
|
is_bot: bool
|
|
58
63
|
|
|
59
64
|
class Chat(BaseModel):
|
|
65
|
+
"""Current chat information"""
|
|
60
66
|
id: str
|
|
61
67
|
chat_type: str
|
|
62
68
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from typing import Any, Literal
|
|
1
|
+
from typing import Any, Literal, Protocol
|
|
2
2
|
import httpx
|
|
3
3
|
|
|
4
4
|
from .models import (
|
|
5
|
-
|
|
5
|
+
ZaloAPIResponse,
|
|
6
6
|
SuccessfulResponse,
|
|
7
7
|
ErrorResponse,
|
|
8
8
|
ZaloAPIError,
|
|
@@ -13,13 +13,12 @@ from .models import (
|
|
|
13
13
|
)
|
|
14
14
|
from .config import ZaloAPIConfig
|
|
15
15
|
|
|
16
|
-
|
|
17
16
|
async def fetch[T](
|
|
18
17
|
url: str,
|
|
19
18
|
*,
|
|
20
19
|
method: Literal["GET", "POST"] = "GET",
|
|
21
20
|
body: dict[str, Any] | None = None,
|
|
22
|
-
) ->
|
|
21
|
+
) -> ZaloAPIResponse[T]:
|
|
23
22
|
async with httpx.AsyncClient() as client:
|
|
24
23
|
|
|
25
24
|
if method == "GET":
|
|
@@ -35,15 +34,19 @@ async def fetch[T](
|
|
|
35
34
|
|
|
36
35
|
return ErrorResponse(**response_json)
|
|
37
36
|
|
|
37
|
+
class WebhookHandler(Protocol):
|
|
38
|
+
async def __call__(self, update_event: Event, bot: ZaloBot) -> None: ...
|
|
39
|
+
|
|
38
40
|
class ZaloBot:
|
|
39
41
|
def __init__(self, BOT_TOKEN: str):
|
|
40
42
|
self._BOT_TOKEN: str = BOT_TOKEN
|
|
41
43
|
self._base_url: str = f"{ZaloAPIConfig.BASE_URL}/bot{BOT_TOKEN}"
|
|
42
|
-
|
|
44
|
+
self._webhook_handlers: list[WebhookHandler] = []
|
|
45
|
+
|
|
43
46
|
async def getMe(self) -> BotInfo:
|
|
44
47
|
url = f"{self._base_url}/getMe"
|
|
45
48
|
|
|
46
|
-
res:
|
|
49
|
+
res: ZaloAPIResponse[BotInfo] = await fetch(url)
|
|
47
50
|
|
|
48
51
|
if isinstance(res, ErrorResponse):
|
|
49
52
|
raise ZaloAPIError(
|
|
@@ -54,7 +57,6 @@ class ZaloBot:
|
|
|
54
57
|
|
|
55
58
|
return res.result
|
|
56
59
|
|
|
57
|
-
|
|
58
60
|
async def getUpdates(self, timeout: int = 30) -> Event:
|
|
59
61
|
url = f"{self._base_url}/getUpdates"
|
|
60
62
|
|
|
@@ -62,7 +64,7 @@ class ZaloBot:
|
|
|
62
64
|
"timeout": timeout
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
res:
|
|
67
|
+
res: ZaloAPIResponse[Event] = await fetch(url, method="POST", body=payload)
|
|
66
68
|
|
|
67
69
|
if isinstance(res, ErrorResponse):
|
|
68
70
|
raise ZaloAPIError(
|
|
@@ -72,7 +74,11 @@ class ZaloBot:
|
|
|
72
74
|
|
|
73
75
|
return res.result
|
|
74
76
|
|
|
75
|
-
async def setWebhook(
|
|
77
|
+
async def setWebhook(
|
|
78
|
+
self,
|
|
79
|
+
url: str,
|
|
80
|
+
secret_token: str,
|
|
81
|
+
) -> WebhookInfo:
|
|
76
82
|
url = f"{self._base_url}/setWebhook"
|
|
77
83
|
|
|
78
84
|
payload = {
|
|
@@ -80,7 +86,7 @@ class ZaloBot:
|
|
|
80
86
|
"secret_token": secret_token
|
|
81
87
|
}
|
|
82
88
|
|
|
83
|
-
res:
|
|
89
|
+
res: ZaloAPIResponse[WebhookInfo] = await fetch(url, method="POST", body=payload)
|
|
84
90
|
|
|
85
91
|
if isinstance(res, ErrorResponse):
|
|
86
92
|
raise ZaloAPIError(
|
|
@@ -93,7 +99,7 @@ class ZaloBot:
|
|
|
93
99
|
async def deleteWebhook(self) -> WebhookInfo:
|
|
94
100
|
url = f"{self._base_url}/deleteWebhook"
|
|
95
101
|
|
|
96
|
-
res:
|
|
102
|
+
res: ZaloAPIResponse[WebhookInfo] = await fetch(url)
|
|
97
103
|
|
|
98
104
|
if isinstance(res, ErrorResponse):
|
|
99
105
|
raise ZaloAPIError(
|
|
@@ -106,7 +112,7 @@ class ZaloBot:
|
|
|
106
112
|
async def getWebhookInfo(self) -> WebhookInfo:
|
|
107
113
|
url = f"{self._base_url}/getWebhookInfo"
|
|
108
114
|
|
|
109
|
-
res:
|
|
115
|
+
res: ZaloAPIResponse[WebhookInfo] = await fetch(url)
|
|
110
116
|
|
|
111
117
|
if isinstance(res, ErrorResponse):
|
|
112
118
|
raise ZaloAPIError(
|
|
@@ -116,6 +122,15 @@ class ZaloBot:
|
|
|
116
122
|
|
|
117
123
|
return res.result
|
|
118
124
|
|
|
125
|
+
def on_webhook_update(self, handler: WebhookHandler) -> None:
|
|
126
|
+
"""Registers a handler to handle on webhook event update"""
|
|
127
|
+
self._webhook_handlers.append(handler)
|
|
128
|
+
|
|
129
|
+
async def dispatch_webhook_handlers(self, update_event: Event) -> None:
|
|
130
|
+
"""Run all handlers given a webhook event"""
|
|
131
|
+
for handler in self._webhook_handlers:
|
|
132
|
+
await handler(update_event, self)
|
|
133
|
+
|
|
119
134
|
async def sendMessage(self, chat_id: str, text: str) -> MessageInfo:
|
|
120
135
|
url = f"{self._base_url}/sendMessage"
|
|
121
136
|
|
|
@@ -123,7 +138,7 @@ class ZaloBot:
|
|
|
123
138
|
"chat_id": chat_id,
|
|
124
139
|
"text": text
|
|
125
140
|
}
|
|
126
|
-
res:
|
|
141
|
+
res: ZaloAPIResponse[MessageInfo] = await fetch(url, method="POST", body=payload)
|
|
127
142
|
|
|
128
143
|
if isinstance(res, ErrorResponse):
|
|
129
144
|
raise ZaloAPIError(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|