notifyhub-client 0.1.0__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.
- notifyhub_client-0.1.0/PKG-INFO +64 -0
- notifyhub_client-0.1.0/README.md +50 -0
- notifyhub_client-0.1.0/pyproject.toml +26 -0
- notifyhub_client-0.1.0/setup.cfg +4 -0
- notifyhub_client-0.1.0/src/notifyhub/__init__.py +38 -0
- notifyhub_client-0.1.0/src/notifyhub/client.py +227 -0
- notifyhub_client-0.1.0/src/notifyhub/notify/__init__.py +0 -0
- notifyhub_client-0.1.0/src/notifyhub/notify/v1/__init__.py +0 -0
- notifyhub_client-0.1.0/src/notifyhub/notify/v1/notify_pb2.py +71 -0
- notifyhub_client-0.1.0/src/notifyhub/notify/v1/notify_pb2_grpc.py +366 -0
- notifyhub_client-0.1.0/src/notifyhub_client.egg-info/PKG-INFO +64 -0
- notifyhub_client-0.1.0/src/notifyhub_client.egg-info/SOURCES.txt +13 -0
- notifyhub_client-0.1.0/src/notifyhub_client.egg-info/dependency_links.txt +1 -0
- notifyhub_client-0.1.0/src/notifyhub_client.egg-info/requires.txt +4 -0
- notifyhub_client-0.1.0/src/notifyhub_client.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: notifyhub-client
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: NotifyHub 多语言通知推送服务 - Python 客户端
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/huangwenfu750/notifyhub
|
|
7
|
+
Project-URL: Repository, https://github.com/huangwenfu750/notifyhub
|
|
8
|
+
Project-URL: Issues, https://github.com/huangwenfu750/notifyhub/issues
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: grpcio>=1.60
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: grpcio-tools>=1.60; extra == "dev"
|
|
14
|
+
|
|
15
|
+
# NotifyHub Python SDK
|
|
16
|
+
|
|
17
|
+
> English: [README.en.md](README.en.md)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install -e sdks/python # 本地安装(发布到 PyPI 前的用法)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from notifyhub import NotifyClient, PublishRequest
|
|
25
|
+
|
|
26
|
+
with NotifyClient("localhost:9987", token="ntf_xxx") as client:
|
|
27
|
+
client.publish("alert", "部署完成", "v1.2.0 上线", params={"env": "prod"})
|
|
28
|
+
print(client.ping())
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
批量发布(一条双向流,单条失败不中断):
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
reqs = [
|
|
35
|
+
PublishRequest(topic="alert.db", title="t1", content="c1"),
|
|
36
|
+
PublishRequest(title="缺 topic 的非法请求"),
|
|
37
|
+
]
|
|
38
|
+
for ack in client.publish_batch(reqs):
|
|
39
|
+
print(ack.accepted, ack.error) # True '' / False 'INVALID_ARGUMENT: topic 不能为空'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
订阅主题:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
sub = client.subscribe(["alert.*"], print)
|
|
46
|
+
...
|
|
47
|
+
sub.cancel()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
用代码注册推送平台:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
client.upsert_platform(
|
|
54
|
+
name="ding-alert", type="dingtalk",
|
|
55
|
+
webhook="https://oapi.dingtalk.com/robot/send?access_token=xxx",
|
|
56
|
+
secret="SECxxx", topics=["alert"],
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
重新生成 stub(改了 proto 之后):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
./scripts/gen-protos.sh python
|
|
64
|
+
```
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# NotifyHub Python SDK
|
|
2
|
+
|
|
3
|
+
> English: [README.en.md](README.en.md)
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install -e sdks/python # 本地安装(发布到 PyPI 前的用法)
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from notifyhub import NotifyClient, PublishRequest
|
|
11
|
+
|
|
12
|
+
with NotifyClient("localhost:9987", token="ntf_xxx") as client:
|
|
13
|
+
client.publish("alert", "部署完成", "v1.2.0 上线", params={"env": "prod"})
|
|
14
|
+
print(client.ping())
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
批量发布(一条双向流,单条失败不中断):
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
reqs = [
|
|
21
|
+
PublishRequest(topic="alert.db", title="t1", content="c1"),
|
|
22
|
+
PublishRequest(title="缺 topic 的非法请求"),
|
|
23
|
+
]
|
|
24
|
+
for ack in client.publish_batch(reqs):
|
|
25
|
+
print(ack.accepted, ack.error) # True '' / False 'INVALID_ARGUMENT: topic 不能为空'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
订阅主题:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
sub = client.subscribe(["alert.*"], print)
|
|
32
|
+
...
|
|
33
|
+
sub.cancel()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
用代码注册推送平台:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
client.upsert_platform(
|
|
40
|
+
name="ding-alert", type="dingtalk",
|
|
41
|
+
webhook="https://oapi.dingtalk.com/robot/send?access_token=xxx",
|
|
42
|
+
secret="SECxxx", topics=["alert"],
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
重新生成 stub(改了 proto 之后):
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
./scripts/gen-protos.sh python
|
|
50
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "notifyhub-client"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "NotifyHub 多语言通知推送服务 - Python 客户端"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
dependencies = ["grpcio>=1.60"]
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
Homepage = "https://github.com/huangwenfu750/notifyhub"
|
|
16
|
+
Repository = "https://github.com/huangwenfu750/notifyhub"
|
|
17
|
+
Issues = "https://github.com/huangwenfu750/notifyhub/issues"
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
dev = ["grpcio-tools>=1.60"]
|
|
21
|
+
|
|
22
|
+
[tool.setuptools.packages.find]
|
|
23
|
+
where = ["src"]
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.package-data]
|
|
26
|
+
notifyhub = ["notify/v1/*.pyi"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""NotifyHub Python 客户端(gRPC 薄封装)。
|
|
2
|
+
|
|
3
|
+
用法::
|
|
4
|
+
|
|
5
|
+
from notifyhub import NotifyClient
|
|
6
|
+
|
|
7
|
+
client = NotifyClient("localhost:9987", token="xxx")
|
|
8
|
+
client.publish("alert", "部署完成", "v1.2.0 上线")
|
|
9
|
+
client.close()
|
|
10
|
+
|
|
11
|
+
批量发布(双向流)::
|
|
12
|
+
|
|
13
|
+
from notifyhub import NotifyClient, PublishRequest
|
|
14
|
+
|
|
15
|
+
reqs = [PublishRequest(topic="a.b", title="t1"),
|
|
16
|
+
PublishRequest(title="非法:缺 topic")]
|
|
17
|
+
for ack in client.publish_batch(reqs):
|
|
18
|
+
print(ack.accepted, ack.error)
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from .client import Event, NotifyClient, NotifyError, PublishAck, Subscription
|
|
22
|
+
from .notify.v1 import notify_pb2
|
|
23
|
+
|
|
24
|
+
Options = notify_pb2.Options
|
|
25
|
+
PublishRequest = notify_pb2.PublishRequest
|
|
26
|
+
PlatformConfig = notify_pb2.PlatformConfig
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"NotifyClient",
|
|
30
|
+
"NotifyError",
|
|
31
|
+
"PublishAck",
|
|
32
|
+
"Event",
|
|
33
|
+
"Subscription",
|
|
34
|
+
"PublishRequest",
|
|
35
|
+
"Options",
|
|
36
|
+
"PlatformConfig",
|
|
37
|
+
]
|
|
38
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""NotifyClient: NotifyHub gRPC 客户端薄封装。
|
|
2
|
+
|
|
3
|
+
发布、订阅、Admin(代码配置推送平台)三类操作;token 通过 metadata 注入。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Callable, Iterable, Optional
|
|
9
|
+
|
|
10
|
+
import grpc
|
|
11
|
+
|
|
12
|
+
from .notify.v1 import notify_pb2 as pb
|
|
13
|
+
from .notify.v1 import notify_pb2_grpc as pb_grpc
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class NotifyError(Exception):
|
|
17
|
+
"""服务端返回的错误(对应 gRPC Status)。"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, code: grpc.StatusCode, details: str):
|
|
20
|
+
self.code = code
|
|
21
|
+
self.details = details
|
|
22
|
+
super().__init__(f"{code.name}: {details}")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Event:
|
|
26
|
+
"""订阅收到的事件。"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, msg: pb.Event):
|
|
29
|
+
self.topic = msg.topic
|
|
30
|
+
self.title = msg.title
|
|
31
|
+
self.content = msg.content
|
|
32
|
+
self.params = dict(msg.params)
|
|
33
|
+
self.event_id = msg.event_id
|
|
34
|
+
self.timestamp = msg.timestamp
|
|
35
|
+
|
|
36
|
+
def __repr__(self) -> str: # pragma: no cover
|
|
37
|
+
return f"Event(topic={self.topic!r}, title={self.title!r}, event_id={self.event_id!r})"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class PublishAck:
|
|
41
|
+
"""发布回执。"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, ack: pb.PublishAck):
|
|
44
|
+
self.event_id = ack.event_id
|
|
45
|
+
self.accepted = ack.accepted
|
|
46
|
+
self.deduplicated = ack.deduplicated
|
|
47
|
+
self.matched_platforms = list(ack.matched_platforms)
|
|
48
|
+
self.error = ack.error
|
|
49
|
+
|
|
50
|
+
def __repr__(self) -> str: # pragma: no cover
|
|
51
|
+
return (f"PublishAck(accepted={self.accepted}, deduplicated={self.deduplicated}, "
|
|
52
|
+
f"matched={self.matched_platforms})")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class Subscription:
|
|
56
|
+
"""订阅句柄:close() 主动退订。"""
|
|
57
|
+
|
|
58
|
+
def __init__(self, call: grpc.Future | object, close: Callable[[], None]):
|
|
59
|
+
self._call = call
|
|
60
|
+
self._close = close
|
|
61
|
+
|
|
62
|
+
def cancel(self) -> None:
|
|
63
|
+
self._close()
|
|
64
|
+
|
|
65
|
+
close = cancel
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _wrap_grpc_error(fn):
|
|
69
|
+
def inner(*args, **kwargs):
|
|
70
|
+
try:
|
|
71
|
+
return fn(*args, **kwargs)
|
|
72
|
+
except grpc.RpcError as e:
|
|
73
|
+
raise NotifyError(e.code(), e.details()) from e
|
|
74
|
+
return inner
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class NotifyClient:
|
|
78
|
+
"""与 NotifyHub 服务端的连接。线程安全,可在多线程间共享。"""
|
|
79
|
+
|
|
80
|
+
def __init__(self, target: str, token: Optional[str] = None):
|
|
81
|
+
"""target 形如 "localhost:9987"。token 为服务端 auth.tokens 中的一项。"""
|
|
82
|
+
self._token = token
|
|
83
|
+
self._raw_channel = grpc.insecure_channel(target)
|
|
84
|
+
if token:
|
|
85
|
+
# 用拦截器把 x-api-token 注入每次调用
|
|
86
|
+
self._channel = grpc.intercept_channel(self._raw_channel, self._make_interceptor(token))
|
|
87
|
+
else:
|
|
88
|
+
self._channel = self._raw_channel
|
|
89
|
+
self._stub = pb_grpc.NotifyStub(self._channel)
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def _make_interceptor(token: str):
|
|
93
|
+
class _Invoker(grpc.UnaryUnaryClientInterceptor,
|
|
94
|
+
grpc.UnaryStreamClientInterceptor,
|
|
95
|
+
grpc.StreamUnaryClientInterceptor,
|
|
96
|
+
grpc.StreamStreamClientInterceptor):
|
|
97
|
+
def intercept_unary_unary(self, continuation, client_call_details, request):
|
|
98
|
+
return continuation(self._with_token(client_call_details), request)
|
|
99
|
+
|
|
100
|
+
def intercept_unary_stream(self, continuation, client_call_details, request):
|
|
101
|
+
return continuation(self._with_token(client_call_details), request)
|
|
102
|
+
|
|
103
|
+
def intercept_stream_unary(self, continuation, client_call_details, request_iterator):
|
|
104
|
+
return continuation(self._with_token(client_call_details), request_iterator)
|
|
105
|
+
|
|
106
|
+
def intercept_stream_stream(self, continuation, client_call_details, request_iterator):
|
|
107
|
+
return continuation(self._with_token(client_call_details), request_iterator)
|
|
108
|
+
|
|
109
|
+
@staticmethod
|
|
110
|
+
def _with_token(client_call_details):
|
|
111
|
+
md = list(client_call_details.metadata or [])
|
|
112
|
+
md.append(("x-api-token", token))
|
|
113
|
+
return client_call_details._replace(metadata=md)
|
|
114
|
+
|
|
115
|
+
return _Invoker()
|
|
116
|
+
|
|
117
|
+
# ---------- 发布 ----------
|
|
118
|
+
|
|
119
|
+
@_wrap_grpc_error
|
|
120
|
+
def publish(self, topic: str, title: str = "", content: str = "",
|
|
121
|
+
params: Optional[dict] = None,
|
|
122
|
+
platforms: Optional[Iterable[str]] = None,
|
|
123
|
+
dedup_key: str = "",
|
|
124
|
+
skip_subscribers: bool = False,
|
|
125
|
+
skip_platforms: bool = False,
|
|
126
|
+
timeout: float = 10.0) -> PublishAck:
|
|
127
|
+
"""发布一条通知:按路由推送平台 + 广播给订阅者。"""
|
|
128
|
+
req = pb.PublishRequest(
|
|
129
|
+
topic=topic, title=title, content=content,
|
|
130
|
+
params=params or {},
|
|
131
|
+
platforms=list(platforms or []),
|
|
132
|
+
options=pb.Options(dedup_key=dedup_key,
|
|
133
|
+
skip_subscribers=skip_subscribers,
|
|
134
|
+
skip_platforms=skip_platforms),
|
|
135
|
+
)
|
|
136
|
+
return PublishAck(self._stub.Publish(req, timeout=timeout))
|
|
137
|
+
|
|
138
|
+
# ---------- 批量发布(双向流) ----------
|
|
139
|
+
|
|
140
|
+
@_wrap_grpc_error
|
|
141
|
+
def publish_batch(self, requests, timeout: float = 10.0) -> list:
|
|
142
|
+
"""批量发布(双向流):逐条发送并收集回执。
|
|
143
|
+
|
|
144
|
+
requests 为 pb.PublishRequest 的可迭代对象;单条错误(topic 为空、平台不存在)
|
|
145
|
+
不中断流,对应回执的 accepted=False 且带 error。
|
|
146
|
+
"""
|
|
147
|
+
return [PublishAck(ack) for ack in self._stub.PublishStream(iter(requests), timeout=timeout)]
|
|
148
|
+
|
|
149
|
+
def publish_stream(self, requests):
|
|
150
|
+
"""底层双向流:返回回执迭代器,由调用方自行消费(适合边生成边发送)。"""
|
|
151
|
+
return self._stub.PublishStream(iter(requests))
|
|
152
|
+
|
|
153
|
+
# ---------- 订阅 ----------
|
|
154
|
+
|
|
155
|
+
def subscribe(self, topics: Iterable[str], on_event: Callable[[Event], None],
|
|
156
|
+
on_error: Optional[Callable[[Exception], None]] = None) -> Subscription:
|
|
157
|
+
"""订阅主题,回调在后台线程触发。"""
|
|
158
|
+
import threading
|
|
159
|
+
|
|
160
|
+
call = self._stub.Subscribe(pb.SubscribeRequest(topics=list(topics)))
|
|
161
|
+
stop = threading.Event()
|
|
162
|
+
finished = threading.Event()
|
|
163
|
+
|
|
164
|
+
def pump():
|
|
165
|
+
try:
|
|
166
|
+
for msg in call:
|
|
167
|
+
if stop.is_set():
|
|
168
|
+
break
|
|
169
|
+
on_event(Event(msg))
|
|
170
|
+
except grpc.RpcError as e:
|
|
171
|
+
if e.code() != grpc.StatusCode.CANCELLED and on_error:
|
|
172
|
+
on_error(e)
|
|
173
|
+
finally:
|
|
174
|
+
finished.set()
|
|
175
|
+
|
|
176
|
+
t = threading.Thread(target=pump, daemon=True, name="notifyhub-sub")
|
|
177
|
+
t.start()
|
|
178
|
+
|
|
179
|
+
def close():
|
|
180
|
+
stop.set()
|
|
181
|
+
call.cancel()
|
|
182
|
+
|
|
183
|
+
return Subscription(call, close)
|
|
184
|
+
|
|
185
|
+
# ---------- Admin ----------
|
|
186
|
+
|
|
187
|
+
@_wrap_grpc_error
|
|
188
|
+
def upsert_platform(self, name: str, type: str, webhook: str,
|
|
189
|
+
secret: str = "", topics: Optional[Iterable[str]] = None,
|
|
190
|
+
template: str = "", at_mobiles: Optional[Iterable[str]] = None,
|
|
191
|
+
extra: Optional[dict] = None,
|
|
192
|
+
rate_limit_qps: int = 0,
|
|
193
|
+
timeout: float = 10.0) -> dict:
|
|
194
|
+
"""用代码注册/更新推送平台(运行时生效,重启后需重新注册或写入配置文件)。"""
|
|
195
|
+
cfg = pb.PlatformConfig(
|
|
196
|
+
name=name, type=type, webhook=webhook, secret=secret,
|
|
197
|
+
topics=list(topics or ["*"]), template=template,
|
|
198
|
+
at_mobiles=list(at_mobiles or []), extra=extra or {},
|
|
199
|
+
rate_limit_qps=rate_limit_qps)
|
|
200
|
+
out = self._stub.UpsertPlatform(cfg, timeout=timeout)
|
|
201
|
+
return {"name": out.name, "type": out.type, "topics": list(out.topics)}
|
|
202
|
+
|
|
203
|
+
@_wrap_grpc_error
|
|
204
|
+
def list_platforms(self, timeout: float = 10.0) -> list:
|
|
205
|
+
out = self._stub.ListPlatforms(pb.Empty(), timeout=timeout)
|
|
206
|
+
return [{"name": p.name, "type": p.type, "webhook": p.webhook,
|
|
207
|
+
"topics": list(p.topics)} for p in out.platforms]
|
|
208
|
+
|
|
209
|
+
@_wrap_grpc_error
|
|
210
|
+
def remove_platform(self, name: str, timeout: float = 10.0) -> None:
|
|
211
|
+
self._stub.RemovePlatform(pb.PlatformRef(name=name), timeout=timeout)
|
|
212
|
+
|
|
213
|
+
@_wrap_grpc_error
|
|
214
|
+
def ping(self, timeout: float = 5.0) -> dict:
|
|
215
|
+
out = self._stub.Ping(pb.Empty(), timeout=timeout)
|
|
216
|
+
return {"version": out.version, "uptime_seconds": out.uptime_seconds}
|
|
217
|
+
|
|
218
|
+
# ---------- 生命周期 ----------
|
|
219
|
+
|
|
220
|
+
def close(self):
|
|
221
|
+
self._raw_channel.close()
|
|
222
|
+
|
|
223
|
+
def __enter__(self):
|
|
224
|
+
return self
|
|
225
|
+
|
|
226
|
+
def __exit__(self, *exc):
|
|
227
|
+
self.close()
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
+
# source: notify/v1/notify.proto
|
|
5
|
+
# Protobuf Python Version: 7.35.1
|
|
6
|
+
"""Generated protocol buffer code."""
|
|
7
|
+
from google.protobuf import descriptor as _descriptor
|
|
8
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
9
|
+
from google.protobuf import runtime_version as _runtime_version
|
|
10
|
+
from google.protobuf import symbol_database as _symbol_database
|
|
11
|
+
from google.protobuf.internal import builder as _builder
|
|
12
|
+
_runtime_version.ValidateProtobufRuntimeVersion(
|
|
13
|
+
_runtime_version.Domain.PUBLIC,
|
|
14
|
+
7,
|
|
15
|
+
35,
|
|
16
|
+
1,
|
|
17
|
+
'',
|
|
18
|
+
'notify/v1/notify.proto'
|
|
19
|
+
)
|
|
20
|
+
# @@protoc_insertion_point(imports)
|
|
21
|
+
|
|
22
|
+
_sym_db = _symbol_database.Default()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16notify/v1/notify.proto\x12\tnotify.v1\"\x07\n\x05\x45mpty\"/\n\x04Pong\x12\x0f\n\x07version\x18\x01 \x01(\t\x12\x16\n\x0euptime_seconds\x18\x02 \x01(\x03\"N\n\x07Options\x12\x11\n\tdedup_key\x18\x01 \x01(\t\x12\x18\n\x10skip_subscribers\x18\x02 \x01(\x08\x12\x16\n\x0eskip_platforms\x18\x03 \x01(\x08\"\xdd\x01\n\x0ePublishRequest\x12\r\n\x05topic\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\t\x12\x35\n\x06params\x18\x04 \x03(\x0b\x32%.notify.v1.PublishRequest.ParamsEntry\x12\x11\n\tplatforms\x18\x05 \x03(\t\x12#\n\x07options\x18\x06 \x01(\x0b\x32\x12.notify.v1.Options\x1a-\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"p\n\nPublishAck\x12\x10\n\x08\x65vent_id\x18\x01 \x01(\t\x12\x10\n\x08\x61\x63\x63\x65pted\x18\x02 \x01(\x08\x12\x14\n\x0c\x64\x65\x64uplicated\x18\x03 \x01(\x08\x12\x19\n\x11matched_platforms\x18\x04 \x03(\t\x12\r\n\x05\x65rror\x18\x05 \x01(\t\"\"\n\x10SubscribeRequest\x12\x0e\n\x06topics\x18\x01 \x03(\t\"\xca\x01\n\x05\x45vent\x12\r\n\x05topic\x18\x01 \x01(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\t\x12,\n\x06params\x18\x04 \x03(\x0b\x32\x1c.notify.v1.Event.ParamsEntry\x12\x10\n\x08platform\x18\x05 \x01(\t\x12\x10\n\x08\x65vent_id\x18\x06 \x01(\t\x12\x11\n\ttimestamp\x18\x07 \x01(\x03\x1a-\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xa5\x02\n\x0ePlatformConfig\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x0f\n\x07webhook\x18\x03 \x01(\t\x12\x0e\n\x06secret\x18\x04 \x01(\t\x12\x0e\n\x06topics\x18\x05 \x03(\t\x12\x10\n\x08template\x18\x06 \x01(\t\x12\x12\n\nat_mobiles\x18\x07 \x03(\t\x12\x33\n\x05\x65xtra\x18\x08 \x03(\x0b\x32$.notify.v1.PlatformConfig.ExtraEntry\x12%\n\x05retry\x18\t \x01(\x0b\x32\x16.notify.v1.RetryPolicy\x12\x16\n\x0erate_limit_qps\x18\n \x01(\x05\x1a,\n\nExtraEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"7\n\x0bRetryPolicy\x12\x14\n\x0cmax_attempts\x18\x01 \x01(\x05\x12\x12\n\nbackoff_ms\x18\x02 \x01(\x03\"\x1b\n\x0bPlatformRef\x12\x0c\n\x04name\x18\x01 \x01(\t\"<\n\x0cPlatformList\x12,\n\tplatforms\x18\x01 \x03(\x0b\x32\x19.notify.v1.PlatformConfig2\xb5\x03\n\x06Notify\x12;\n\x07Publish\x12\x19.notify.v1.PublishRequest\x1a\x15.notify.v1.PublishAck\x12<\n\tSubscribe\x12\x1b.notify.v1.SubscribeRequest\x1a\x10.notify.v1.Event0\x01\x12\x45\n\rPublishStream\x12\x19.notify.v1.PublishRequest\x1a\x15.notify.v1.PublishAck(\x01\x30\x01\x12\x46\n\x0eUpsertPlatform\x12\x19.notify.v1.PlatformConfig\x1a\x19.notify.v1.PlatformConfig\x12:\n\rListPlatforms\x12\x10.notify.v1.Empty\x1a\x17.notify.v1.PlatformList\x12:\n\x0eRemovePlatform\x12\x16.notify.v1.PlatformRef\x1a\x10.notify.v1.Empty\x12)\n\x04Ping\x12\x10.notify.v1.Empty\x1a\x0f.notify.v1.PongBc\n\x0fio.notifyhub.v1B\x0bNotifyProtoP\x01ZAgithub.com/huangwenfu750/notifyhub/sdks/go/gen/notify/v1;notifyv1b\x06proto3')
|
|
28
|
+
|
|
29
|
+
_globals = globals()
|
|
30
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
31
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'notify.v1.notify_pb2', _globals)
|
|
32
|
+
if not _descriptor._USE_C_DESCRIPTORS:
|
|
33
|
+
_globals['DESCRIPTOR']._loaded_options = None
|
|
34
|
+
_globals['DESCRIPTOR']._serialized_options = b'\n\017io.notifyhub.v1B\013NotifyProtoP\001ZAgithub.com/huangwenfu750/notifyhub/sdks/go/gen/notify/v1;notifyv1'
|
|
35
|
+
_globals['_PUBLISHREQUEST_PARAMSENTRY']._loaded_options = None
|
|
36
|
+
_globals['_PUBLISHREQUEST_PARAMSENTRY']._serialized_options = b'8\001'
|
|
37
|
+
_globals['_EVENT_PARAMSENTRY']._loaded_options = None
|
|
38
|
+
_globals['_EVENT_PARAMSENTRY']._serialized_options = b'8\001'
|
|
39
|
+
_globals['_PLATFORMCONFIG_EXTRAENTRY']._loaded_options = None
|
|
40
|
+
_globals['_PLATFORMCONFIG_EXTRAENTRY']._serialized_options = b'8\001'
|
|
41
|
+
_globals['_EMPTY']._serialized_start=37
|
|
42
|
+
_globals['_EMPTY']._serialized_end=44
|
|
43
|
+
_globals['_PONG']._serialized_start=46
|
|
44
|
+
_globals['_PONG']._serialized_end=93
|
|
45
|
+
_globals['_OPTIONS']._serialized_start=95
|
|
46
|
+
_globals['_OPTIONS']._serialized_end=173
|
|
47
|
+
_globals['_PUBLISHREQUEST']._serialized_start=176
|
|
48
|
+
_globals['_PUBLISHREQUEST']._serialized_end=397
|
|
49
|
+
_globals['_PUBLISHREQUEST_PARAMSENTRY']._serialized_start=352
|
|
50
|
+
_globals['_PUBLISHREQUEST_PARAMSENTRY']._serialized_end=397
|
|
51
|
+
_globals['_PUBLISHACK']._serialized_start=399
|
|
52
|
+
_globals['_PUBLISHACK']._serialized_end=511
|
|
53
|
+
_globals['_SUBSCRIBEREQUEST']._serialized_start=513
|
|
54
|
+
_globals['_SUBSCRIBEREQUEST']._serialized_end=547
|
|
55
|
+
_globals['_EVENT']._serialized_start=550
|
|
56
|
+
_globals['_EVENT']._serialized_end=752
|
|
57
|
+
_globals['_EVENT_PARAMSENTRY']._serialized_start=352
|
|
58
|
+
_globals['_EVENT_PARAMSENTRY']._serialized_end=397
|
|
59
|
+
_globals['_PLATFORMCONFIG']._serialized_start=755
|
|
60
|
+
_globals['_PLATFORMCONFIG']._serialized_end=1048
|
|
61
|
+
_globals['_PLATFORMCONFIG_EXTRAENTRY']._serialized_start=1004
|
|
62
|
+
_globals['_PLATFORMCONFIG_EXTRAENTRY']._serialized_end=1048
|
|
63
|
+
_globals['_RETRYPOLICY']._serialized_start=1050
|
|
64
|
+
_globals['_RETRYPOLICY']._serialized_end=1105
|
|
65
|
+
_globals['_PLATFORMREF']._serialized_start=1107
|
|
66
|
+
_globals['_PLATFORMREF']._serialized_end=1134
|
|
67
|
+
_globals['_PLATFORMLIST']._serialized_start=1136
|
|
68
|
+
_globals['_PLATFORMLIST']._serialized_end=1196
|
|
69
|
+
_globals['_NOTIFY']._serialized_start=1199
|
|
70
|
+
_globals['_NOTIFY']._serialized_end=1636
|
|
71
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
|
|
2
|
+
"""Client and server classes corresponding to protobuf-defined services."""
|
|
3
|
+
import grpc
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
from notifyhub.notify.v1 import notify_pb2 as notify_dot_v1_dot_notify__pb2
|
|
7
|
+
|
|
8
|
+
GRPC_GENERATED_VERSION = '1.84.0'
|
|
9
|
+
GRPC_VERSION = grpc.__version__
|
|
10
|
+
_version_not_supported = False
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from grpc._utilities import first_version_is_lower
|
|
14
|
+
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
|
15
|
+
except ImportError:
|
|
16
|
+
_version_not_supported = True
|
|
17
|
+
|
|
18
|
+
if _version_not_supported:
|
|
19
|
+
raise RuntimeError(
|
|
20
|
+
f'The grpc package installed is at version {GRPC_VERSION},'
|
|
21
|
+
+ ' but the generated code in notify/v1/notify_pb2_grpc.py depends on'
|
|
22
|
+
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
|
|
23
|
+
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
|
|
24
|
+
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class NotifyStub:
|
|
29
|
+
"""NotifyHub —— 多语言通知推送服务。
|
|
30
|
+
本文件是唯一契约:服务端将来重写(Go/Rust/Zig)时不得变更既有字段的编号与语义。
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, channel):
|
|
34
|
+
"""Constructor.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
channel: A grpc.Channel.
|
|
38
|
+
"""
|
|
39
|
+
self.Publish = channel.unary_unary(
|
|
40
|
+
'/notify.v1.Notify/Publish',
|
|
41
|
+
request_serializer=notify_dot_v1_dot_notify__pb2.PublishRequest.SerializeToString,
|
|
42
|
+
response_deserializer=notify_dot_v1_dot_notify__pb2.PublishAck.FromString,
|
|
43
|
+
_registered_method=True)
|
|
44
|
+
self.Subscribe = channel.unary_stream(
|
|
45
|
+
'/notify.v1.Notify/Subscribe',
|
|
46
|
+
request_serializer=notify_dot_v1_dot_notify__pb2.SubscribeRequest.SerializeToString,
|
|
47
|
+
response_deserializer=notify_dot_v1_dot_notify__pb2.Event.FromString,
|
|
48
|
+
_registered_method=True)
|
|
49
|
+
self.PublishStream = channel.stream_stream(
|
|
50
|
+
'/notify.v1.Notify/PublishStream',
|
|
51
|
+
request_serializer=notify_dot_v1_dot_notify__pb2.PublishRequest.SerializeToString,
|
|
52
|
+
response_deserializer=notify_dot_v1_dot_notify__pb2.PublishAck.FromString,
|
|
53
|
+
_registered_method=True)
|
|
54
|
+
self.UpsertPlatform = channel.unary_unary(
|
|
55
|
+
'/notify.v1.Notify/UpsertPlatform',
|
|
56
|
+
request_serializer=notify_dot_v1_dot_notify__pb2.PlatformConfig.SerializeToString,
|
|
57
|
+
response_deserializer=notify_dot_v1_dot_notify__pb2.PlatformConfig.FromString,
|
|
58
|
+
_registered_method=True)
|
|
59
|
+
self.ListPlatforms = channel.unary_unary(
|
|
60
|
+
'/notify.v1.Notify/ListPlatforms',
|
|
61
|
+
request_serializer=notify_dot_v1_dot_notify__pb2.Empty.SerializeToString,
|
|
62
|
+
response_deserializer=notify_dot_v1_dot_notify__pb2.PlatformList.FromString,
|
|
63
|
+
_registered_method=True)
|
|
64
|
+
self.RemovePlatform = channel.unary_unary(
|
|
65
|
+
'/notify.v1.Notify/RemovePlatform',
|
|
66
|
+
request_serializer=notify_dot_v1_dot_notify__pb2.PlatformRef.SerializeToString,
|
|
67
|
+
response_deserializer=notify_dot_v1_dot_notify__pb2.Empty.FromString,
|
|
68
|
+
_registered_method=True)
|
|
69
|
+
self.Ping = channel.unary_unary(
|
|
70
|
+
'/notify.v1.Notify/Ping',
|
|
71
|
+
request_serializer=notify_dot_v1_dot_notify__pb2.Empty.SerializeToString,
|
|
72
|
+
response_deserializer=notify_dot_v1_dot_notify__pb2.Pong.FromString,
|
|
73
|
+
_registered_method=True)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class NotifyServicer:
|
|
77
|
+
"""NotifyHub —— 多语言通知推送服务。
|
|
78
|
+
本文件是唯一契约:服务端将来重写(Go/Rust/Zig)时不得变更既有字段的编号与语义。
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def Publish(self, request, context):
|
|
82
|
+
"""发布通知:按路由推送到外部平台 + 广播给在线订阅者。
|
|
83
|
+
"""
|
|
84
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
85
|
+
context.set_details('Method not implemented!')
|
|
86
|
+
raise NotImplementedError('Method not implemented!')
|
|
87
|
+
|
|
88
|
+
def Subscribe(self, request, context):
|
|
89
|
+
"""订阅主题,服务端流式推送。
|
|
90
|
+
"""
|
|
91
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
92
|
+
context.set_details('Method not implemented!')
|
|
93
|
+
raise NotImplementedError('Method not implemented!')
|
|
94
|
+
|
|
95
|
+
def PublishStream(self, request_iterator, context):
|
|
96
|
+
"""批量发布(双向流:每收到一条请求,回执一条 Ack)。
|
|
97
|
+
"""
|
|
98
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
99
|
+
context.set_details('Method not implemented!')
|
|
100
|
+
raise NotImplementedError('Method not implemented!')
|
|
101
|
+
|
|
102
|
+
def UpsertPlatform(self, request, context):
|
|
103
|
+
"""用代码配置推送平台(运行时生效;重启后需重新注册,或写入配置文件)。
|
|
104
|
+
"""
|
|
105
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
106
|
+
context.set_details('Method not implemented!')
|
|
107
|
+
raise NotImplementedError('Method not implemented!')
|
|
108
|
+
|
|
109
|
+
def ListPlatforms(self, request, context):
|
|
110
|
+
"""Missing associated documentation comment in .proto file."""
|
|
111
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
112
|
+
context.set_details('Method not implemented!')
|
|
113
|
+
raise NotImplementedError('Method not implemented!')
|
|
114
|
+
|
|
115
|
+
def RemovePlatform(self, request, context):
|
|
116
|
+
"""Missing associated documentation comment in .proto file."""
|
|
117
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
118
|
+
context.set_details('Method not implemented!')
|
|
119
|
+
raise NotImplementedError('Method not implemented!')
|
|
120
|
+
|
|
121
|
+
def Ping(self, request, context):
|
|
122
|
+
"""健康检查(无需鉴权)。
|
|
123
|
+
"""
|
|
124
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
125
|
+
context.set_details('Method not implemented!')
|
|
126
|
+
raise NotImplementedError('Method not implemented!')
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def add_NotifyServicer_to_server(servicer, server):
|
|
130
|
+
rpc_method_handlers = {
|
|
131
|
+
'Publish': grpc.unary_unary_rpc_method_handler(
|
|
132
|
+
servicer.Publish,
|
|
133
|
+
request_deserializer=notify_dot_v1_dot_notify__pb2.PublishRequest.FromString,
|
|
134
|
+
response_serializer=notify_dot_v1_dot_notify__pb2.PublishAck.SerializeToString,
|
|
135
|
+
),
|
|
136
|
+
'Subscribe': grpc.unary_stream_rpc_method_handler(
|
|
137
|
+
servicer.Subscribe,
|
|
138
|
+
request_deserializer=notify_dot_v1_dot_notify__pb2.SubscribeRequest.FromString,
|
|
139
|
+
response_serializer=notify_dot_v1_dot_notify__pb2.Event.SerializeToString,
|
|
140
|
+
),
|
|
141
|
+
'PublishStream': grpc.stream_stream_rpc_method_handler(
|
|
142
|
+
servicer.PublishStream,
|
|
143
|
+
request_deserializer=notify_dot_v1_dot_notify__pb2.PublishRequest.FromString,
|
|
144
|
+
response_serializer=notify_dot_v1_dot_notify__pb2.PublishAck.SerializeToString,
|
|
145
|
+
),
|
|
146
|
+
'UpsertPlatform': grpc.unary_unary_rpc_method_handler(
|
|
147
|
+
servicer.UpsertPlatform,
|
|
148
|
+
request_deserializer=notify_dot_v1_dot_notify__pb2.PlatformConfig.FromString,
|
|
149
|
+
response_serializer=notify_dot_v1_dot_notify__pb2.PlatformConfig.SerializeToString,
|
|
150
|
+
),
|
|
151
|
+
'ListPlatforms': grpc.unary_unary_rpc_method_handler(
|
|
152
|
+
servicer.ListPlatforms,
|
|
153
|
+
request_deserializer=notify_dot_v1_dot_notify__pb2.Empty.FromString,
|
|
154
|
+
response_serializer=notify_dot_v1_dot_notify__pb2.PlatformList.SerializeToString,
|
|
155
|
+
),
|
|
156
|
+
'RemovePlatform': grpc.unary_unary_rpc_method_handler(
|
|
157
|
+
servicer.RemovePlatform,
|
|
158
|
+
request_deserializer=notify_dot_v1_dot_notify__pb2.PlatformRef.FromString,
|
|
159
|
+
response_serializer=notify_dot_v1_dot_notify__pb2.Empty.SerializeToString,
|
|
160
|
+
),
|
|
161
|
+
'Ping': grpc.unary_unary_rpc_method_handler(
|
|
162
|
+
servicer.Ping,
|
|
163
|
+
request_deserializer=notify_dot_v1_dot_notify__pb2.Empty.FromString,
|
|
164
|
+
response_serializer=notify_dot_v1_dot_notify__pb2.Pong.SerializeToString,
|
|
165
|
+
),
|
|
166
|
+
}
|
|
167
|
+
generic_handler = grpc.method_handlers_generic_handler(
|
|
168
|
+
'notify.v1.Notify', rpc_method_handlers)
|
|
169
|
+
server.add_generic_rpc_handlers((generic_handler,))
|
|
170
|
+
server.add_registered_method_handlers('notify.v1.Notify', rpc_method_handlers)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
# This class is part of an EXPERIMENTAL API.
|
|
174
|
+
class Notify:
|
|
175
|
+
"""NotifyHub —— 多语言通知推送服务。
|
|
176
|
+
本文件是唯一契约:服务端将来重写(Go/Rust/Zig)时不得变更既有字段的编号与语义。
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
@staticmethod
|
|
180
|
+
def Publish(request,
|
|
181
|
+
target,
|
|
182
|
+
options=(),
|
|
183
|
+
channel_credentials=None,
|
|
184
|
+
call_credentials=None,
|
|
185
|
+
insecure=False,
|
|
186
|
+
compression=None,
|
|
187
|
+
wait_for_ready=None,
|
|
188
|
+
timeout=None,
|
|
189
|
+
metadata=None):
|
|
190
|
+
return grpc.experimental.unary_unary(
|
|
191
|
+
request,
|
|
192
|
+
target,
|
|
193
|
+
'/notify.v1.Notify/Publish',
|
|
194
|
+
notify_dot_v1_dot_notify__pb2.PublishRequest.SerializeToString,
|
|
195
|
+
notify_dot_v1_dot_notify__pb2.PublishAck.FromString,
|
|
196
|
+
options,
|
|
197
|
+
channel_credentials,
|
|
198
|
+
insecure,
|
|
199
|
+
call_credentials,
|
|
200
|
+
compression,
|
|
201
|
+
wait_for_ready,
|
|
202
|
+
timeout,
|
|
203
|
+
metadata,
|
|
204
|
+
_registered_method=True)
|
|
205
|
+
|
|
206
|
+
@staticmethod
|
|
207
|
+
def Subscribe(request,
|
|
208
|
+
target,
|
|
209
|
+
options=(),
|
|
210
|
+
channel_credentials=None,
|
|
211
|
+
call_credentials=None,
|
|
212
|
+
insecure=False,
|
|
213
|
+
compression=None,
|
|
214
|
+
wait_for_ready=None,
|
|
215
|
+
timeout=None,
|
|
216
|
+
metadata=None):
|
|
217
|
+
return grpc.experimental.unary_stream(
|
|
218
|
+
request,
|
|
219
|
+
target,
|
|
220
|
+
'/notify.v1.Notify/Subscribe',
|
|
221
|
+
notify_dot_v1_dot_notify__pb2.SubscribeRequest.SerializeToString,
|
|
222
|
+
notify_dot_v1_dot_notify__pb2.Event.FromString,
|
|
223
|
+
options,
|
|
224
|
+
channel_credentials,
|
|
225
|
+
insecure,
|
|
226
|
+
call_credentials,
|
|
227
|
+
compression,
|
|
228
|
+
wait_for_ready,
|
|
229
|
+
timeout,
|
|
230
|
+
metadata,
|
|
231
|
+
_registered_method=True)
|
|
232
|
+
|
|
233
|
+
@staticmethod
|
|
234
|
+
def PublishStream(request_iterator,
|
|
235
|
+
target,
|
|
236
|
+
options=(),
|
|
237
|
+
channel_credentials=None,
|
|
238
|
+
call_credentials=None,
|
|
239
|
+
insecure=False,
|
|
240
|
+
compression=None,
|
|
241
|
+
wait_for_ready=None,
|
|
242
|
+
timeout=None,
|
|
243
|
+
metadata=None):
|
|
244
|
+
return grpc.experimental.stream_stream(
|
|
245
|
+
request_iterator,
|
|
246
|
+
target,
|
|
247
|
+
'/notify.v1.Notify/PublishStream',
|
|
248
|
+
notify_dot_v1_dot_notify__pb2.PublishRequest.SerializeToString,
|
|
249
|
+
notify_dot_v1_dot_notify__pb2.PublishAck.FromString,
|
|
250
|
+
options,
|
|
251
|
+
channel_credentials,
|
|
252
|
+
insecure,
|
|
253
|
+
call_credentials,
|
|
254
|
+
compression,
|
|
255
|
+
wait_for_ready,
|
|
256
|
+
timeout,
|
|
257
|
+
metadata,
|
|
258
|
+
_registered_method=True)
|
|
259
|
+
|
|
260
|
+
@staticmethod
|
|
261
|
+
def UpsertPlatform(request,
|
|
262
|
+
target,
|
|
263
|
+
options=(),
|
|
264
|
+
channel_credentials=None,
|
|
265
|
+
call_credentials=None,
|
|
266
|
+
insecure=False,
|
|
267
|
+
compression=None,
|
|
268
|
+
wait_for_ready=None,
|
|
269
|
+
timeout=None,
|
|
270
|
+
metadata=None):
|
|
271
|
+
return grpc.experimental.unary_unary(
|
|
272
|
+
request,
|
|
273
|
+
target,
|
|
274
|
+
'/notify.v1.Notify/UpsertPlatform',
|
|
275
|
+
notify_dot_v1_dot_notify__pb2.PlatformConfig.SerializeToString,
|
|
276
|
+
notify_dot_v1_dot_notify__pb2.PlatformConfig.FromString,
|
|
277
|
+
options,
|
|
278
|
+
channel_credentials,
|
|
279
|
+
insecure,
|
|
280
|
+
call_credentials,
|
|
281
|
+
compression,
|
|
282
|
+
wait_for_ready,
|
|
283
|
+
timeout,
|
|
284
|
+
metadata,
|
|
285
|
+
_registered_method=True)
|
|
286
|
+
|
|
287
|
+
@staticmethod
|
|
288
|
+
def ListPlatforms(request,
|
|
289
|
+
target,
|
|
290
|
+
options=(),
|
|
291
|
+
channel_credentials=None,
|
|
292
|
+
call_credentials=None,
|
|
293
|
+
insecure=False,
|
|
294
|
+
compression=None,
|
|
295
|
+
wait_for_ready=None,
|
|
296
|
+
timeout=None,
|
|
297
|
+
metadata=None):
|
|
298
|
+
return grpc.experimental.unary_unary(
|
|
299
|
+
request,
|
|
300
|
+
target,
|
|
301
|
+
'/notify.v1.Notify/ListPlatforms',
|
|
302
|
+
notify_dot_v1_dot_notify__pb2.Empty.SerializeToString,
|
|
303
|
+
notify_dot_v1_dot_notify__pb2.PlatformList.FromString,
|
|
304
|
+
options,
|
|
305
|
+
channel_credentials,
|
|
306
|
+
insecure,
|
|
307
|
+
call_credentials,
|
|
308
|
+
compression,
|
|
309
|
+
wait_for_ready,
|
|
310
|
+
timeout,
|
|
311
|
+
metadata,
|
|
312
|
+
_registered_method=True)
|
|
313
|
+
|
|
314
|
+
@staticmethod
|
|
315
|
+
def RemovePlatform(request,
|
|
316
|
+
target,
|
|
317
|
+
options=(),
|
|
318
|
+
channel_credentials=None,
|
|
319
|
+
call_credentials=None,
|
|
320
|
+
insecure=False,
|
|
321
|
+
compression=None,
|
|
322
|
+
wait_for_ready=None,
|
|
323
|
+
timeout=None,
|
|
324
|
+
metadata=None):
|
|
325
|
+
return grpc.experimental.unary_unary(
|
|
326
|
+
request,
|
|
327
|
+
target,
|
|
328
|
+
'/notify.v1.Notify/RemovePlatform',
|
|
329
|
+
notify_dot_v1_dot_notify__pb2.PlatformRef.SerializeToString,
|
|
330
|
+
notify_dot_v1_dot_notify__pb2.Empty.FromString,
|
|
331
|
+
options,
|
|
332
|
+
channel_credentials,
|
|
333
|
+
insecure,
|
|
334
|
+
call_credentials,
|
|
335
|
+
compression,
|
|
336
|
+
wait_for_ready,
|
|
337
|
+
timeout,
|
|
338
|
+
metadata,
|
|
339
|
+
_registered_method=True)
|
|
340
|
+
|
|
341
|
+
@staticmethod
|
|
342
|
+
def Ping(request,
|
|
343
|
+
target,
|
|
344
|
+
options=(),
|
|
345
|
+
channel_credentials=None,
|
|
346
|
+
call_credentials=None,
|
|
347
|
+
insecure=False,
|
|
348
|
+
compression=None,
|
|
349
|
+
wait_for_ready=None,
|
|
350
|
+
timeout=None,
|
|
351
|
+
metadata=None):
|
|
352
|
+
return grpc.experimental.unary_unary(
|
|
353
|
+
request,
|
|
354
|
+
target,
|
|
355
|
+
'/notify.v1.Notify/Ping',
|
|
356
|
+
notify_dot_v1_dot_notify__pb2.Empty.SerializeToString,
|
|
357
|
+
notify_dot_v1_dot_notify__pb2.Pong.FromString,
|
|
358
|
+
options,
|
|
359
|
+
channel_credentials,
|
|
360
|
+
insecure,
|
|
361
|
+
call_credentials,
|
|
362
|
+
compression,
|
|
363
|
+
wait_for_ready,
|
|
364
|
+
timeout,
|
|
365
|
+
metadata,
|
|
366
|
+
_registered_method=True)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: notifyhub-client
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: NotifyHub 多语言通知推送服务 - Python 客户端
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/huangwenfu750/notifyhub
|
|
7
|
+
Project-URL: Repository, https://github.com/huangwenfu750/notifyhub
|
|
8
|
+
Project-URL: Issues, https://github.com/huangwenfu750/notifyhub/issues
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: grpcio>=1.60
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: grpcio-tools>=1.60; extra == "dev"
|
|
14
|
+
|
|
15
|
+
# NotifyHub Python SDK
|
|
16
|
+
|
|
17
|
+
> English: [README.en.md](README.en.md)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install -e sdks/python # 本地安装(发布到 PyPI 前的用法)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from notifyhub import NotifyClient, PublishRequest
|
|
25
|
+
|
|
26
|
+
with NotifyClient("localhost:9987", token="ntf_xxx") as client:
|
|
27
|
+
client.publish("alert", "部署完成", "v1.2.0 上线", params={"env": "prod"})
|
|
28
|
+
print(client.ping())
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
批量发布(一条双向流,单条失败不中断):
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
reqs = [
|
|
35
|
+
PublishRequest(topic="alert.db", title="t1", content="c1"),
|
|
36
|
+
PublishRequest(title="缺 topic 的非法请求"),
|
|
37
|
+
]
|
|
38
|
+
for ack in client.publish_batch(reqs):
|
|
39
|
+
print(ack.accepted, ack.error) # True '' / False 'INVALID_ARGUMENT: topic 不能为空'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
订阅主题:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
sub = client.subscribe(["alert.*"], print)
|
|
46
|
+
...
|
|
47
|
+
sub.cancel()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
用代码注册推送平台:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
client.upsert_platform(
|
|
54
|
+
name="ding-alert", type="dingtalk",
|
|
55
|
+
webhook="https://oapi.dingtalk.com/robot/send?access_token=xxx",
|
|
56
|
+
secret="SECxxx", topics=["alert"],
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
重新生成 stub(改了 proto 之后):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
./scripts/gen-protos.sh python
|
|
64
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
src/notifyhub/__init__.py
|
|
4
|
+
src/notifyhub/client.py
|
|
5
|
+
src/notifyhub/notify/__init__.py
|
|
6
|
+
src/notifyhub/notify/v1/__init__.py
|
|
7
|
+
src/notifyhub/notify/v1/notify_pb2.py
|
|
8
|
+
src/notifyhub/notify/v1/notify_pb2_grpc.py
|
|
9
|
+
src/notifyhub_client.egg-info/PKG-INFO
|
|
10
|
+
src/notifyhub_client.egg-info/SOURCES.txt
|
|
11
|
+
src/notifyhub_client.egg-info/dependency_links.txt
|
|
12
|
+
src/notifyhub_client.egg-info/requires.txt
|
|
13
|
+
src/notifyhub_client.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
notifyhub
|