yellowstone-fumarole-client 0.1.0rc2__tar.gz → 0.2.1__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.
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/PKG-INFO +35 -30
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/README.md +33 -24
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/pyproject.toml +3 -7
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_client/__init__.py +86 -19
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_client/config.py +17 -1
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_client/grpc_connectivity.py +11 -28
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_client/runtime/aio.py +86 -70
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_client/runtime/state_machine.py +23 -22
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_client/utils/aio.py +0 -2
- yellowstone_fumarole_client-0.2.1/yellowstone_fumarole_client/utils/collections.py +37 -0
- yellowstone_fumarole_client-0.2.1/yellowstone_fumarole_proto/fumarole_pb2.py +134 -0
- yellowstone_fumarole_client-0.1.0rc2/yellowstone_fumarole_proto/fumarole_v2_pb2.pyi → yellowstone_fumarole_client-0.2.1/yellowstone_fumarole_proto/fumarole_pb2.pyi +51 -5
- yellowstone_fumarole_client-0.1.0rc2/yellowstone_fumarole_proto/fumarole_v2_pb2_grpc.py → yellowstone_fumarole_client-0.2.1/yellowstone_fumarole_proto/fumarole_pb2_grpc.py +155 -69
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_proto/geyser_pb2.py +39 -35
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_proto/geyser_pb2.pyi +15 -2
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_proto/geyser_pb2_grpc.py +44 -1
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_proto/solana_storage_pb2.py +32 -32
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_proto/solana_storage_pb2.pyi +6 -3
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_proto/solana_storage_pb2_grpc.py +1 -1
- yellowstone_fumarole_client-0.1.0rc2/yellowstone_fumarole_proto/fumarole_v2_pb2.py +0 -122
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_client/runtime/__init__.py +0 -0
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_client/utils/__init__.py +0 -0
- {yellowstone_fumarole_client-0.1.0rc2 → yellowstone_fumarole_client-0.2.1}/yellowstone_fumarole_proto/__init__.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: yellowstone-fumarole-client
|
3
|
-
Version: 0.1
|
3
|
+
Version: 0.2.1
|
4
4
|
Summary: Yellowstone Fumarole Python Client
|
5
5
|
Home-page: https://github.com/rpcpool/yellowstone-fumarole
|
6
6
|
Author: Louis-Vincent
|
@@ -8,14 +8,9 @@ Author-email: louis-vincent@triton.one
|
|
8
8
|
Requires-Python: >=3.13,<4.0
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
10
10
|
Classifier: Programming Language :: Python :: 3.13
|
11
|
-
Requires-Dist: asyncio (>=3.4.3,<4.0.0)
|
12
|
-
Requires-Dist: base58 (>=2.1.1,<3.0.0)
|
13
|
-
Requires-Dist: click (>=8.1.7,<9.0.0)
|
14
11
|
Requires-Dist: grpcio (>=1.71.1,<2.0.0)
|
15
|
-
Requires-Dist: protobuf (>=
|
12
|
+
Requires-Dist: protobuf (>=6.32.0,<7.0.0)
|
16
13
|
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
17
|
-
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
18
|
-
Requires-Dist: toml (>=0.10.2,<0.11.0)
|
19
14
|
Project-URL: Repository, https://github.com/rpcpool/yellowstone-fumarole
|
20
15
|
Description-Content-Type: text/markdown
|
21
16
|
|
@@ -83,33 +78,43 @@ async def dragonsmouth_like_session(fumarole_config):
|
|
83
78
|
session = await client.dragonsmouth_subscribe(
|
84
79
|
consumer_group_name="test",
|
85
80
|
request=SubscribeRequest(
|
86
|
-
|
81
|
+
accounts={"fumarole": SubscribeRequestFilterAccounts()},
|
87
82
|
transactions={"fumarole": SubscribeRequestFilterTransactions()},
|
88
83
|
blocks_meta={"fumarole": SubscribeRequestFilterBlocksMeta()},
|
89
84
|
entry={"fumarole": SubscribeRequestFilterEntry()},
|
90
85
|
slots={"fumarole": SubscribeRequestFilterSlots()},
|
91
86
|
),
|
92
87
|
)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
88
|
+
async with session:
|
89
|
+
dragonsmouth_like_source = session.source
|
90
|
+
# result: SubscribeUpdate
|
91
|
+
async for result in dragonsmouth_like_source:
|
92
|
+
if result.HasField("block_meta"):
|
93
|
+
block_meta: SubscribeUpdateBlockMeta = result.block_meta
|
94
|
+
elif result.HasField("transaction"):
|
95
|
+
tx: SubscribeUpdateTransaction = result.transaction
|
96
|
+
elif result.HasField("account"):
|
97
|
+
account: SubscribeUpdateAccount = result.account
|
98
|
+
elif result.HasField("entry"):
|
99
|
+
entry: SubscribeUpdateEntry = result.entry
|
100
|
+
elif result.HasField("slot"):
|
101
|
+
result: SubscribeUpdateSlot = result.slot
|
102
|
+
|
103
|
+
# OUTSIDE THE SCOPE, YOU SHOULD NEVER USE `session` again.
|
104
|
+
```
|
105
|
+
|
106
|
+
|
107
|
+
At any point you can get a rough estimate if you are progression through the slot using `DragonsmouthAdapterSession.stats()` call:
|
108
|
+
|
109
|
+
```python
|
110
|
+
|
111
|
+
async with session:
|
112
|
+
stats: FumaroleSubscribeStats = session.stats()
|
113
|
+
print(f"{stats.log_committed_offset}, {stats.log_committable_offset}, {stats.max_slot_seen}")
|
115
114
|
```
|
115
|
+
|
116
|
+
`log_committed_offset` : what have been ACK so for to fumarole remote service.
|
117
|
+
`log_committable_offset` : what can be ACK to next commit call.
|
118
|
+
`max_slot_seen` : maximum slot seen in the inner fumarole client state -- not yet processed by your code.
|
119
|
+
|
120
|
+
|
@@ -62,33 +62,42 @@ async def dragonsmouth_like_session(fumarole_config):
|
|
62
62
|
session = await client.dragonsmouth_subscribe(
|
63
63
|
consumer_group_name="test",
|
64
64
|
request=SubscribeRequest(
|
65
|
-
|
65
|
+
accounts={"fumarole": SubscribeRequestFilterAccounts()},
|
66
66
|
transactions={"fumarole": SubscribeRequestFilterTransactions()},
|
67
67
|
blocks_meta={"fumarole": SubscribeRequestFilterBlocksMeta()},
|
68
68
|
entry={"fumarole": SubscribeRequestFilterEntry()},
|
69
69
|
slots={"fumarole": SubscribeRequestFilterSlots()},
|
70
70
|
),
|
71
71
|
)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
72
|
+
async with session:
|
73
|
+
dragonsmouth_like_source = session.source
|
74
|
+
# result: SubscribeUpdate
|
75
|
+
async for result in dragonsmouth_like_source:
|
76
|
+
if result.HasField("block_meta"):
|
77
|
+
block_meta: SubscribeUpdateBlockMeta = result.block_meta
|
78
|
+
elif result.HasField("transaction"):
|
79
|
+
tx: SubscribeUpdateTransaction = result.transaction
|
80
|
+
elif result.HasField("account"):
|
81
|
+
account: SubscribeUpdateAccount = result.account
|
82
|
+
elif result.HasField("entry"):
|
83
|
+
entry: SubscribeUpdateEntry = result.entry
|
84
|
+
elif result.HasField("slot"):
|
85
|
+
result: SubscribeUpdateSlot = result.slot
|
86
|
+
|
87
|
+
# OUTSIDE THE SCOPE, YOU SHOULD NEVER USE `session` again.
|
88
|
+
```
|
89
|
+
|
90
|
+
|
91
|
+
At any point you can get a rough estimate if you are progression through the slot using `DragonsmouthAdapterSession.stats()` call:
|
92
|
+
|
93
|
+
```python
|
94
|
+
|
95
|
+
async with session:
|
96
|
+
stats: FumaroleSubscribeStats = session.stats()
|
97
|
+
print(f"{stats.log_committed_offset}, {stats.log_committable_offset}, {stats.max_slot_seen}")
|
98
|
+
```
|
99
|
+
|
100
|
+
`log_committed_offset` : what have been ACK so for to fumarole remote service.
|
101
|
+
`log_committable_offset` : what can be ACK to next commit call.
|
102
|
+
`max_slot_seen` : maximum slot seen in the inner fumarole client state -- not yet processed by your code.
|
103
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "yellowstone-fumarole-client"
|
3
|
-
version = "0.1
|
3
|
+
version = "0.2.1"
|
4
4
|
homepage = "https://github.com/rpcpool/yellowstone-fumarole"
|
5
5
|
repository = "https://github.com/rpcpool/yellowstone-fumarole"
|
6
6
|
description = "Yellowstone Fumarole Python Client"
|
@@ -14,13 +14,8 @@ packages = [
|
|
14
14
|
|
15
15
|
[tool.poetry.dependencies]
|
16
16
|
python = "^3.13"
|
17
|
-
click = "^8.1.7"
|
18
17
|
grpcio = "^1.71.1"
|
19
|
-
protobuf = "^
|
20
|
-
toml = "^0.10.2"
|
21
|
-
base58 = "^2.1.1"
|
22
|
-
tabulate = "^0.9.0"
|
23
|
-
asyncio = "^3.4.3"
|
18
|
+
protobuf = "^6.32.0"
|
24
19
|
pyyaml = "^6.0.2"
|
25
20
|
|
26
21
|
[tool.poetry.group.test.dependencies]
|
@@ -30,6 +25,7 @@ pytest = "^8.3.4"
|
|
30
25
|
grpcio-tools = "^1.68.1"
|
31
26
|
black = "^24.10.0"
|
32
27
|
pytest-asyncio = "^0.26.0"
|
28
|
+
deptry = "^0.23.1"
|
33
29
|
|
34
30
|
[build-system]
|
35
31
|
requires = ["poetry-core"]
|
@@ -3,18 +3,21 @@ import logging
|
|
3
3
|
from yellowstone_fumarole_client.grpc_connectivity import (
|
4
4
|
FumaroleGrpcConnector,
|
5
5
|
)
|
6
|
-
from typing import
|
6
|
+
from typing import AsyncGenerator, Optional
|
7
7
|
from dataclasses import dataclass
|
8
|
-
from . import
|
8
|
+
from yellowstone_fumarole_client.config import FumaroleConfig
|
9
9
|
from yellowstone_fumarole_client.runtime.aio import (
|
10
10
|
AsyncioFumeDragonsmouthRuntime,
|
11
|
-
FumaroleSM,
|
12
11
|
DEFAULT_GC_INTERVAL,
|
13
12
|
DEFAULT_SLOT_MEMORY_RETENTION,
|
14
13
|
GrpcSlotDownloader,
|
15
14
|
)
|
15
|
+
from yellowstone_fumarole_client.runtime.state_machine import (
|
16
|
+
FumaroleSM,
|
17
|
+
FumeOffset,
|
18
|
+
)
|
16
19
|
from yellowstone_fumarole_proto.geyser_pb2 import SubscribeRequest, SubscribeUpdate
|
17
|
-
from yellowstone_fumarole_proto.
|
20
|
+
from yellowstone_fumarole_proto.fumarole_pb2 import (
|
18
21
|
ControlResponse,
|
19
22
|
VersionRequest,
|
20
23
|
VersionResponse,
|
@@ -29,9 +32,11 @@ from yellowstone_fumarole_proto.fumarole_v2_pb2 import (
|
|
29
32
|
CreateConsumerGroupRequest,
|
30
33
|
CreateConsumerGroupResponse,
|
31
34
|
)
|
32
|
-
from yellowstone_fumarole_proto.
|
35
|
+
from yellowstone_fumarole_proto.fumarole_pb2_grpc import FumaroleStub
|
33
36
|
import grpc
|
34
37
|
|
38
|
+
from yellowstone_fumarole_client import config
|
39
|
+
|
35
40
|
__all__ = [
|
36
41
|
"FumaroleClient",
|
37
42
|
"FumaroleConfig",
|
@@ -44,7 +49,7 @@ __all__ = [
|
|
44
49
|
]
|
45
50
|
|
46
51
|
# Constants
|
47
|
-
DEFAULT_DRAGONSMOUTH_CAPACITY =
|
52
|
+
DEFAULT_DRAGONSMOUTH_CAPACITY = 100000
|
48
53
|
DEFAULT_COMMIT_INTERVAL = 5.0 # seconds
|
49
54
|
DEFAULT_MAX_SLOT_DOWNLOAD_ATTEMPT = 3
|
50
55
|
DEFAULT_CONCURRENT_DOWNLOAD_LIMIT_PER_TCP = 10
|
@@ -72,10 +77,23 @@ class FumaroleSubscribeConfig:
|
|
72
77
|
# The interval at which to perform garbage collection on the slot memory.
|
73
78
|
gc_interval: int = DEFAULT_GC_INTERVAL
|
74
79
|
|
75
|
-
#
|
80
|
+
# How many processed slot numbers to retain in memory to avoid duplication.
|
76
81
|
slot_memory_retention: int = DEFAULT_SLOT_MEMORY_RETENTION
|
77
82
|
|
78
83
|
|
84
|
+
@dataclass
|
85
|
+
class FumaroleSubscribeStats:
|
86
|
+
"""Commit/slot statistics for the Fumarole subscribe session."""
|
87
|
+
|
88
|
+
# Last committed log offset in Fumarole -- this is a low-level, implementation detail.
|
89
|
+
# NOTE: this should not be part as business logic, can change any time.
|
90
|
+
log_committed_offset: FumeOffset
|
91
|
+
# NOTE:: this is a low-level information, can change any time.
|
92
|
+
log_committable_offset: FumeOffset
|
93
|
+
# Max slot seen by the in the current session - does not mean it has been processed.
|
94
|
+
max_slot_seen: int
|
95
|
+
|
96
|
+
|
79
97
|
# DragonsmouthAdapterSession
|
80
98
|
@dataclass
|
81
99
|
class DragonsmouthAdapterSession:
|
@@ -85,10 +103,31 @@ class DragonsmouthAdapterSession:
|
|
85
103
|
sink: asyncio.Queue
|
86
104
|
|
87
105
|
# The queue for receiving SubscribeUpdate from the dragonsmouth stream.
|
88
|
-
source:
|
106
|
+
source: AsyncGenerator[SubscribeUpdate, None]
|
89
107
|
|
90
108
|
# The task handle for the fumarole runtime.
|
91
|
-
|
109
|
+
_fumarole_handle: asyncio.Task
|
110
|
+
|
111
|
+
_sm: FumaroleSM
|
112
|
+
|
113
|
+
async def __aenter__(self):
|
114
|
+
"""Enter the session context."""
|
115
|
+
return self
|
116
|
+
|
117
|
+
async def __aexit__(self, exc_type, exc_value, traceback):
|
118
|
+
self.sink.shutdown()
|
119
|
+
self._fumarole_handle.cancel()
|
120
|
+
|
121
|
+
def stats(self) -> FumaroleSubscribeStats:
|
122
|
+
"""Get low-level statistics of the Fumarole state-machine."""
|
123
|
+
commitable = self._sm.committable_offset
|
124
|
+
committed = self._sm.last_committed_offset
|
125
|
+
max_slot = self._sm.max_slot_detected
|
126
|
+
return FumaroleSubscribeStats(
|
127
|
+
log_committed_offset=committed,
|
128
|
+
log_committable_offset=commitable,
|
129
|
+
max_slot_seen=max_slot,
|
130
|
+
)
|
92
131
|
|
93
132
|
|
94
133
|
# FumaroleClient
|
@@ -117,7 +156,7 @@ class FumaroleClient:
|
|
117
156
|
async def version(self) -> VersionResponse:
|
118
157
|
"""Get the version of the Fumarole server."""
|
119
158
|
request = VersionRequest()
|
120
|
-
response = await self.stub.
|
159
|
+
response = await self.stub.Version(request)
|
121
160
|
return response
|
122
161
|
|
123
162
|
async def dragonsmouth_subscribe(
|
@@ -162,12 +201,12 @@ class FumaroleClient:
|
|
162
201
|
try:
|
163
202
|
update = await fume_control_plane_q.get()
|
164
203
|
yield update
|
165
|
-
except asyncio.QueueShutDown:
|
204
|
+
except (asyncio.CancelledError, asyncio.QueueShutDown):
|
166
205
|
break
|
167
206
|
|
168
|
-
fume_control_plane_stream_rx: grpc.aio.
|
169
|
-
|
170
|
-
)
|
207
|
+
fume_control_plane_stream_rx: grpc.aio.StreamStreamCall = self.stub.Subscribe(
|
208
|
+
control_plane_sink()
|
209
|
+
) # it's actually InterceptedStreamStreamCall, but grpc lib doesn't export it
|
171
210
|
|
172
211
|
control_response: ControlResponse = await fume_control_plane_stream_rx.read()
|
173
212
|
init = control_response.init
|
@@ -187,8 +226,12 @@ class FumaroleClient:
|
|
187
226
|
await fume_control_plane_rx_q.put(update)
|
188
227
|
except asyncio.QueueShutDown:
|
189
228
|
break
|
229
|
+
except asyncio.CancelledError:
|
230
|
+
break
|
231
|
+
finally:
|
232
|
+
fume_control_plane_rx_q.shutdown()
|
190
233
|
|
191
|
-
|
234
|
+
control_plane_src_task = asyncio.create_task(control_plane_source())
|
192
235
|
|
193
236
|
FumaroleClient.logger.debug(f"Control response: {control_response}")
|
194
237
|
|
@@ -219,12 +262,36 @@ class FumaroleClient:
|
|
219
262
|
max_concurrent_download=config.concurrent_download_limit,
|
220
263
|
)
|
221
264
|
|
222
|
-
|
223
|
-
|
265
|
+
async def rt_run(rt):
|
266
|
+
async with rt as rt:
|
267
|
+
await rt.run()
|
268
|
+
|
269
|
+
rt_task = asyncio.create_task(rt_run(rt))
|
270
|
+
|
271
|
+
async def fumarole_overseer():
|
272
|
+
done, pending = await asyncio.wait(
|
273
|
+
[rt_task, control_plane_src_task], return_when=asyncio.FIRST_COMPLETED
|
274
|
+
)
|
275
|
+
for t in pending:
|
276
|
+
t.cancel()
|
277
|
+
|
278
|
+
fumarole_handle = asyncio.create_task(fumarole_overseer())
|
279
|
+
|
280
|
+
async def source_gen() -> AsyncGenerator[SubscribeUpdate, None]:
|
281
|
+
try:
|
282
|
+
while True:
|
283
|
+
update = await dragonsmouth_outlet.get()
|
284
|
+
yield update
|
285
|
+
except (asyncio.CancelledError, asyncio.QueueShutDown):
|
286
|
+
pass
|
287
|
+
finally:
|
288
|
+
dragonsmouth_outlet.shutdown()
|
289
|
+
|
224
290
|
return DragonsmouthAdapterSession(
|
225
291
|
sink=subscribe_request_queue,
|
226
|
-
source=
|
227
|
-
|
292
|
+
source=source_gen(),
|
293
|
+
_fumarole_handle=fumarole_handle,
|
294
|
+
_sm=sm,
|
228
295
|
)
|
229
296
|
|
230
297
|
async def list_consumer_groups(
|
@@ -1,14 +1,19 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from typing import Dict, Optional
|
2
|
+
from typing import Dict, Literal, Optional
|
3
3
|
import yaml
|
4
4
|
|
5
5
|
|
6
|
+
SUPPORTED_COMPRESSION = ["gzip"]
|
7
|
+
SupportedCompression = Literal["gzip"]
|
8
|
+
|
9
|
+
|
6
10
|
@dataclass
|
7
11
|
class FumaroleConfig:
|
8
12
|
endpoint: str
|
9
13
|
x_token: Optional[str] = None
|
10
14
|
max_decoding_message_size_bytes: int = 512_000_000
|
11
15
|
x_metadata: Dict[str, str] = None
|
16
|
+
response_compression: Optional[SupportedCompression] = None
|
12
17
|
|
13
18
|
def __post_init__(self):
|
14
19
|
self.x_metadata = self.x_metadata or {}
|
@@ -16,6 +21,14 @@ class FumaroleConfig:
|
|
16
21
|
@classmethod
|
17
22
|
def from_yaml(cls, fileobj) -> "FumaroleConfig":
|
18
23
|
data = yaml.safe_load(fileobj)
|
24
|
+
response_compression = data.get(
|
25
|
+
"response_compression", cls.response_compression
|
26
|
+
)
|
27
|
+
if (
|
28
|
+
response_compression is not None
|
29
|
+
and response_compression not in SUPPORTED_COMPRESSION
|
30
|
+
):
|
31
|
+
raise ValueError(f"response_compression must be in {SUPPORTED_COMPRESSION}")
|
19
32
|
return cls(
|
20
33
|
endpoint=data["endpoint"],
|
21
34
|
x_token=data.get("x-token") or data.get("x_token"),
|
@@ -23,4 +36,7 @@ class FumaroleConfig:
|
|
23
36
|
"max_decoding_message_size_bytes", cls.max_decoding_message_size_bytes
|
24
37
|
),
|
25
38
|
x_metadata=data.get("x-metadata", {}),
|
39
|
+
response_compression=data.get(
|
40
|
+
"response_compression", cls.response_compression
|
41
|
+
),
|
26
42
|
)
|
@@ -2,7 +2,7 @@ import logging
|
|
2
2
|
from typing import Optional
|
3
3
|
import grpc
|
4
4
|
from yellowstone_fumarole_client.config import FumaroleConfig
|
5
|
-
from yellowstone_fumarole_proto.
|
5
|
+
from yellowstone_fumarole_proto.fumarole_pb2_grpc import FumaroleStub
|
6
6
|
|
7
7
|
X_TOKEN_HEADER = "x-token"
|
8
8
|
|
@@ -31,34 +31,8 @@ class TritonAuthMetadataPlugin(grpc.AuthMetadataPlugin):
|
|
31
31
|
return _triton_sign_request(callback, self.x_token, None)
|
32
32
|
|
33
33
|
|
34
|
-
def grpc_channel(endpoint: str, x_token=None, compression=None, *grpc_options):
|
35
|
-
options = [("grpc.max_receive_message_length", 111111110), *grpc_options]
|
36
|
-
if x_token is not None:
|
37
|
-
auth = TritonAuthMetadataPlugin(x_token)
|
38
|
-
# ssl_creds allow you to use our https endpoint
|
39
|
-
# grpc.ssl_channel_credentials with no arguments will look through your CA trust store.
|
40
|
-
ssl_creds = grpc.ssl_channel_credentials()
|
41
|
-
|
42
|
-
# call credentials will be sent on each request if setup with composite_channel_credentials.
|
43
|
-
call_creds: grpc.CallCredentials = grpc.metadata_call_credentials(auth)
|
44
|
-
|
45
|
-
# Combined creds will store the channel creds aswell as the call credentials
|
46
|
-
combined_creds = grpc.composite_channel_credentials(ssl_creds, call_creds)
|
47
|
-
|
48
|
-
return grpc.secure_channel(
|
49
|
-
endpoint,
|
50
|
-
credentials=combined_creds,
|
51
|
-
compression=compression,
|
52
|
-
options=options,
|
53
|
-
)
|
54
|
-
else:
|
55
|
-
return grpc.insecure_channel(endpoint, compression=compression, options=options)
|
56
|
-
|
57
|
-
|
58
34
|
# Because of a bug in grpcio library, multiple inheritance of ClientInterceptor subclasses does not work.
|
59
35
|
# You have to create a new class for each type of interceptor you want to use.
|
60
|
-
|
61
|
-
|
62
36
|
class MetadataInterceptor(
|
63
37
|
grpc.aio.UnaryStreamClientInterceptor,
|
64
38
|
grpc.aio.StreamUnaryClientInterceptor,
|
@@ -166,6 +140,11 @@ class FumaroleGrpcConnector:
|
|
166
140
|
async def connect(self, *grpc_options) -> FumaroleStub:
|
167
141
|
options = [("grpc.max_receive_message_length", 111111110), *grpc_options]
|
168
142
|
interceptors = MetadataInterceptor(self.config.x_metadata).interceptors()
|
143
|
+
compression = (
|
144
|
+
grpc.Compression.Gzip
|
145
|
+
if self.config.response_compression == "gzip"
|
146
|
+
else None
|
147
|
+
)
|
169
148
|
if self.config.x_token is not None:
|
170
149
|
auth = TritonAuthMetadataPlugin(self.config.x_token)
|
171
150
|
# ssl_creds allow you to use our https endpoint
|
@@ -184,6 +163,7 @@ class FumaroleGrpcConnector:
|
|
184
163
|
self.endpoint,
|
185
164
|
credentials=combined_creds,
|
186
165
|
options=options,
|
166
|
+
compression=compression,
|
187
167
|
interceptors=interceptors,
|
188
168
|
)
|
189
169
|
else:
|
@@ -191,7 +171,10 @@ class FumaroleGrpcConnector:
|
|
191
171
|
"Using insecure channel without authentication"
|
192
172
|
)
|
193
173
|
channel = grpc.aio.insecure_channel(
|
194
|
-
self.endpoint,
|
174
|
+
self.endpoint,
|
175
|
+
options=options,
|
176
|
+
interceptors=interceptors,
|
177
|
+
compression=compression,
|
195
178
|
)
|
196
179
|
|
197
180
|
return FumaroleStub(channel)
|