valkey-glide 2.0.0__cp39-cp39-macosx_11_0_arm64.whl → 2.2.5rc1__cp39-cp39-macosx_11_0_arm64.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.
- glide/__init__.py +152 -118
- glide/async_commands/cluster_commands.py +29 -14
- glide/async_commands/core.py +600 -414
- glide/async_commands/{server_modules/ft.py → ft.py} +8 -7
- glide/async_commands/{server_modules/glide_json.py → glide_json.py} +15 -92
- glide/async_commands/standalone_commands.py +10 -51
- glide/glide.cpython-39-darwin.so +0 -0
- glide/glide.pyi +1 -1
- glide/glide_client.py +54 -48
- glide/logger.py +3 -3
- glide/opentelemetry.py +8 -4
- glide_shared/__init__.py +330 -0
- glide_shared/commands/__init__.py +0 -0
- {glide/async_commands → glide_shared/commands}/batch.py +426 -32
- {glide/async_commands → glide_shared/commands}/batch_options.py +1 -1
- glide_shared/commands/core_options.py +407 -0
- {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_aggregate_options.py +3 -3
- {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_create_options.py +4 -2
- {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_profile_options.py +4 -4
- {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_search_options.py +4 -2
- {glide/async_commands → glide_shared/commands}/server_modules/json_batch.py +4 -4
- glide_shared/commands/server_modules/json_options.py +93 -0
- {glide/async_commands → glide_shared/commands}/sorted_set.py +2 -2
- {glide/async_commands → glide_shared/commands}/stream.py +1 -1
- {glide → glide_shared}/config.py +315 -60
- {glide → glide_shared}/constants.py +3 -3
- {glide → glide_shared}/exceptions.py +27 -1
- glide_shared/protobuf/command_request_pb2.py +56 -0
- glide_shared/protobuf/connection_request_pb2.py +56 -0
- {glide → glide_shared}/routes.py +29 -15
- {valkey_glide-2.0.0.dist-info → valkey_glide-2.2.5rc1.dist-info}/METADATA +120 -58
- valkey_glide-2.2.5rc1.dist-info/RECORD +40 -0
- glide/protobuf/command_request_pb2.py +0 -54
- glide/protobuf/command_request_pb2.pyi +0 -1193
- glide/protobuf/connection_request_pb2.py +0 -52
- glide/protobuf/connection_request_pb2.pyi +0 -299
- glide/protobuf/response_pb2.pyi +0 -106
- valkey_glide-2.0.0.dist-info/RECORD +0 -39
- {glide/async_commands → glide_shared/commands}/bitmap.py +0 -0
- {glide/async_commands → glide_shared/commands}/command_args.py +0 -0
- {glide/async_commands → glide_shared/commands}/server_modules/ft_options/ft_constants.py +0 -0
- {glide → glide_shared}/protobuf/response_pb2.py +0 -0
- {glide → glide_shared}/protobuf_codec.py +0 -0
- {valkey_glide-2.0.0.dist-info → valkey_glide-2.2.5rc1.dist-info}/WHEEL +0 -0
{glide → glide_shared}/config.py
RENAMED
|
@@ -6,12 +6,18 @@ from dataclasses import dataclass
|
|
|
6
6
|
from enum import Enum, IntEnum
|
|
7
7
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
|
|
8
8
|
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
from
|
|
9
|
+
from glide_shared.commands.core_options import PubSubMsg
|
|
10
|
+
from glide_shared.exceptions import ConfigurationError
|
|
11
|
+
from glide_shared.protobuf.connection_request_pb2 import (
|
|
12
|
+
ConnectionRequest,
|
|
13
|
+
)
|
|
14
|
+
from glide_shared.protobuf.connection_request_pb2 import (
|
|
15
|
+
ProtocolVersion as SentProtocolVersion,
|
|
16
|
+
)
|
|
17
|
+
from glide_shared.protobuf.connection_request_pb2 import ReadFrom as ProtobufReadFrom
|
|
18
|
+
from glide_shared.protobuf.connection_request_pb2 import (
|
|
19
|
+
TlsMode,
|
|
20
|
+
)
|
|
15
21
|
|
|
16
22
|
|
|
17
23
|
class NodeAddress:
|
|
@@ -73,7 +79,7 @@ class BackoffStrategy:
|
|
|
73
79
|
"""
|
|
74
80
|
Represents the strategy used to determine how and when to reconnect, in case of connection failures.
|
|
75
81
|
The time between attempts grows exponentially, to the formula rand(0 .. factor * (exponentBase ^ N)), where N
|
|
76
|
-
is the number of failed attempts, and
|
|
82
|
+
is the number of failed attempts, and rand(...) applies a jitter of up to jitter_percent% to introduce randomness and reduce retry storms.
|
|
77
83
|
Once the maximum value is reached, that will remain the time between retry attempts until a reconnect attempt is
|
|
78
84
|
successful.
|
|
79
85
|
The client will attempt to reconnect indefinitely.
|
|
@@ -83,6 +89,7 @@ class BackoffStrategy:
|
|
|
83
89
|
where the time between retries increases. Once the retries have reached the maximum value, the time between
|
|
84
90
|
retries will remain constant until a reconnect attempt is succesful.
|
|
85
91
|
factor (int): The multiplier that will be applied to the waiting time between each retry.
|
|
92
|
+
This value is specified in milliseconds.
|
|
86
93
|
exponent_base (int): The exponent base configured for the strategy.
|
|
87
94
|
jitter_percent (Optional[int]): The Jitter percent on the calculated duration. If not set, a default value will be used.
|
|
88
95
|
"""
|
|
@@ -100,23 +107,92 @@ class BackoffStrategy:
|
|
|
100
107
|
self.jitter_percent = jitter_percent
|
|
101
108
|
|
|
102
109
|
|
|
110
|
+
class ServiceType(Enum):
|
|
111
|
+
"""
|
|
112
|
+
Represents the types of AWS services that can be used for IAM authentication.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
ELASTICACHE = 0
|
|
116
|
+
"""Amazon ElastiCache service."""
|
|
117
|
+
MEMORYDB = 1
|
|
118
|
+
"""Amazon MemoryDB service."""
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class IamAuthConfig:
|
|
122
|
+
"""
|
|
123
|
+
Configuration settings for IAM authentication.
|
|
124
|
+
|
|
125
|
+
Attributes:
|
|
126
|
+
cluster_name (str): The name of the ElastiCache/MemoryDB cluster.
|
|
127
|
+
service (ServiceType): The type of service being used (ElastiCache or MemoryDB).
|
|
128
|
+
region (str): The AWS region where the ElastiCache/MemoryDB cluster is located.
|
|
129
|
+
refresh_interval_seconds (Optional[int]): Optional refresh interval in seconds for renewing IAM authentication tokens.
|
|
130
|
+
If not provided, the core will use a default value of 300 seconds (5 min).
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
def __init__(
|
|
134
|
+
self,
|
|
135
|
+
cluster_name: str,
|
|
136
|
+
service: ServiceType,
|
|
137
|
+
region: str,
|
|
138
|
+
refresh_interval_seconds: Optional[int] = None,
|
|
139
|
+
):
|
|
140
|
+
self.cluster_name = cluster_name
|
|
141
|
+
self.service = service
|
|
142
|
+
self.region = region
|
|
143
|
+
self.refresh_interval_seconds = refresh_interval_seconds
|
|
144
|
+
|
|
145
|
+
|
|
103
146
|
class ServerCredentials:
|
|
104
147
|
"""
|
|
105
148
|
Represents the credentials for connecting to a server.
|
|
106
149
|
|
|
150
|
+
Exactly one of the following authentication modes must be provided:
|
|
151
|
+
- Password-based authentication: Use password (and optionally username)
|
|
152
|
+
- IAM authentication: Use username (required) and iam_config
|
|
153
|
+
|
|
154
|
+
These modes are mutually exclusive - you cannot use both simultaneously.
|
|
155
|
+
|
|
107
156
|
Attributes:
|
|
108
|
-
password (str): The password that will be used for authenticating connections to the servers.
|
|
157
|
+
password (Optional[str]): The password that will be used for authenticating connections to the servers.
|
|
158
|
+
Mutually exclusive with iam_config. Either password or iam_config must be provided.
|
|
109
159
|
username (Optional[str]): The username that will be used for authenticating connections to the servers.
|
|
110
|
-
If not supplied, "default" will be used.
|
|
160
|
+
If not supplied for password-based authentication, "default" will be used.
|
|
161
|
+
Required for IAM authentication.
|
|
162
|
+
iam_config (Optional[IamAuthConfig]): IAM authentication configuration. Mutually exclusive with password.
|
|
163
|
+
Either password or iam_config must be provided.
|
|
164
|
+
The client will automatically generate and refresh the authentication token based on the provided configuration.
|
|
111
165
|
"""
|
|
112
166
|
|
|
113
167
|
def __init__(
|
|
114
168
|
self,
|
|
115
|
-
password: str,
|
|
169
|
+
password: Optional[str] = None,
|
|
116
170
|
username: Optional[str] = None,
|
|
171
|
+
iam_config: Optional[IamAuthConfig] = None,
|
|
117
172
|
):
|
|
173
|
+
# Validate mutual exclusivity
|
|
174
|
+
if password is not None and iam_config is not None:
|
|
175
|
+
raise ConfigurationError(
|
|
176
|
+
"password and iam_config are mutually exclusive. Use either password-based or IAM authentication, not both."
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
# Validate IAM requires username
|
|
180
|
+
if iam_config is not None and not username:
|
|
181
|
+
raise ConfigurationError("username is required for IAM authentication.")
|
|
182
|
+
|
|
183
|
+
# At least one authentication method must be provided
|
|
184
|
+
if password is None and iam_config is None:
|
|
185
|
+
raise ConfigurationError(
|
|
186
|
+
"Either password or iam_config must be provided for authentication."
|
|
187
|
+
)
|
|
188
|
+
|
|
118
189
|
self.password = password
|
|
119
190
|
self.username = username
|
|
191
|
+
self.iam_config = iam_config
|
|
192
|
+
|
|
193
|
+
def is_iam_auth(self) -> bool:
|
|
194
|
+
"""Returns True if this credential is configured for IAM authentication."""
|
|
195
|
+
return self.iam_config is not None
|
|
120
196
|
|
|
121
197
|
|
|
122
198
|
class PeriodicChecksManualInterval:
|
|
@@ -165,10 +241,40 @@ class TlsAdvancedConfiguration:
|
|
|
165
241
|
Enabling it without TLS will result in a `ConfigurationError`.
|
|
166
242
|
|
|
167
243
|
- Default: False (verification is enforced).
|
|
244
|
+
|
|
245
|
+
root_pem_cacerts (Optional[bytes]): Custom root certificate data for TLS connections in PEM format.
|
|
246
|
+
|
|
247
|
+
- When provided, these certificates will be used instead of the system's default trust store.
|
|
248
|
+
This is useful for connecting to servers with self-signed certificates or corporate
|
|
249
|
+
certificate authorities.
|
|
250
|
+
|
|
251
|
+
- If set to an empty bytes object (non-None but length 0), a `ConfigurationError` will be raised.
|
|
252
|
+
|
|
253
|
+
- If None (default), the system's default certificate trust store will be used (platform verifier).
|
|
254
|
+
|
|
255
|
+
- The certificate data should be in PEM format as a bytes object.
|
|
256
|
+
|
|
257
|
+
- Multiple certificates can be provided by concatenating them in PEM format.
|
|
258
|
+
|
|
259
|
+
Example usage::
|
|
260
|
+
|
|
261
|
+
# Load from file
|
|
262
|
+
with open('/path/to/ca-cert.pem', 'rb') as f:
|
|
263
|
+
cert_data = f.read()
|
|
264
|
+
tls_config = TlsAdvancedConfiguration(root_pem_cacerts=cert_data)
|
|
265
|
+
|
|
266
|
+
# Or provide directly
|
|
267
|
+
cert_data = b"-----BEGIN CERTIFICATE-----\\n...\\n-----END CERTIFICATE-----"
|
|
268
|
+
tls_config = TlsAdvancedConfiguration(root_pem_cacerts=cert_data)
|
|
168
269
|
"""
|
|
169
270
|
|
|
170
|
-
def __init__(
|
|
271
|
+
def __init__(
|
|
272
|
+
self,
|
|
273
|
+
use_insecure_tls: Optional[bool] = None,
|
|
274
|
+
root_pem_cacerts: Optional[bytes] = None,
|
|
275
|
+
):
|
|
171
276
|
self.use_insecure_tls = use_insecure_tls
|
|
277
|
+
self.root_pem_cacerts = root_pem_cacerts
|
|
172
278
|
|
|
173
279
|
|
|
174
280
|
class AdvancedBaseClientConfiguration:
|
|
@@ -183,15 +289,21 @@ class AdvancedBaseClientConfiguration:
|
|
|
183
289
|
tls_config (Optional[TlsAdvancedConfiguration]): The advanced TLS configuration settings.
|
|
184
290
|
This allows for more granular control of TLS behavior, such as enabling an insecure mode
|
|
185
291
|
that bypasses certificate validation.
|
|
292
|
+
tcp_nodelay (Optional[bool]): Controls TCP_NODELAY socket option (Nagle's algorithm).
|
|
293
|
+
When True, disables Nagle's algorithm for lower latency by sending packets immediately without buffering.
|
|
294
|
+
When False, enables Nagle's algorithm to reduce network overhead by buffering small packets.
|
|
295
|
+
If not explicitly set, defaults to True.
|
|
186
296
|
"""
|
|
187
297
|
|
|
188
298
|
def __init__(
|
|
189
299
|
self,
|
|
190
300
|
connection_timeout: Optional[int] = None,
|
|
191
301
|
tls_config: Optional[TlsAdvancedConfiguration] = None,
|
|
302
|
+
tcp_nodelay: Optional[bool] = None,
|
|
192
303
|
):
|
|
193
304
|
self.connection_timeout = connection_timeout
|
|
194
305
|
self.tls_config = tls_config
|
|
306
|
+
self.tcp_nodelay = tcp_nodelay
|
|
195
307
|
|
|
196
308
|
def _create_a_protobuf_conn_request(
|
|
197
309
|
self, request: ConnectionRequest
|
|
@@ -199,13 +311,27 @@ class AdvancedBaseClientConfiguration:
|
|
|
199
311
|
if self.connection_timeout:
|
|
200
312
|
request.connection_timeout = self.connection_timeout
|
|
201
313
|
|
|
202
|
-
if self.
|
|
203
|
-
|
|
314
|
+
if self.tcp_nodelay is not None:
|
|
315
|
+
request.tcp_nodelay = self.tcp_nodelay
|
|
316
|
+
|
|
317
|
+
if self.tls_config:
|
|
318
|
+
if self.tls_config.use_insecure_tls:
|
|
319
|
+
# Validate that TLS is enabled before allowing insecure mode
|
|
320
|
+
if request.tls_mode == TlsMode.NoTls:
|
|
321
|
+
raise ConfigurationError(
|
|
322
|
+
"use_insecure_tls cannot be enabled when use_tls is disabled."
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# Override the default SecureTls mode to InsecureTls when user explicitly requests it
|
|
204
326
|
request.tls_mode = TlsMode.InsecureTls
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
)
|
|
327
|
+
|
|
328
|
+
# Handle root certificates
|
|
329
|
+
if self.tls_config.root_pem_cacerts is not None:
|
|
330
|
+
if len(self.tls_config.root_pem_cacerts) == 0:
|
|
331
|
+
raise ConfigurationError(
|
|
332
|
+
"root_pem_cacerts cannot be an empty bytes object; use None to use platform verifier"
|
|
333
|
+
)
|
|
334
|
+
request.root_certs.append(self.tls_config.root_pem_cacerts)
|
|
209
335
|
|
|
210
336
|
return request
|
|
211
337
|
|
|
@@ -223,9 +349,9 @@ class BaseClientConfiguration:
|
|
|
223
349
|
For example::
|
|
224
350
|
|
|
225
351
|
[
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
]
|
|
352
|
+
NodeAddress("sample-address-0001.use1.cache.amazonaws.com", 6379),
|
|
353
|
+
NodeAddress("sample-address-0002.use1.cache.amazonaws.com", 6379)
|
|
354
|
+
]
|
|
229
355
|
|
|
230
356
|
use_tls (bool): True if communication with the cluster should use Transport Level Security.
|
|
231
357
|
Should match the TLS configuration of the server/cluster, otherwise the connection attempt will fail.
|
|
@@ -242,6 +368,8 @@ class BaseClientConfiguration:
|
|
|
242
368
|
reconnect_strategy (Optional[BackoffStrategy]): Strategy used to determine how and when to reconnect, in case of
|
|
243
369
|
connection failures.
|
|
244
370
|
If not set, a default backoff strategy will be used.
|
|
371
|
+
database_id (Optional[int]): Index of the logical database to connect to.
|
|
372
|
+
Must be a non-negative integer.If not set, the client will connect to database 0.
|
|
245
373
|
client_name (Optional[str]): Client name to be used for the client. Will be used with CLIENT SETNAME command
|
|
246
374
|
during connection establishment.
|
|
247
375
|
protocol (ProtocolVersion): Serialization protocol to be used. If not set, `RESP3` will be used.
|
|
@@ -285,6 +413,7 @@ class BaseClientConfiguration:
|
|
|
285
413
|
read_from: ReadFrom = ReadFrom.PRIMARY,
|
|
286
414
|
request_timeout: Optional[int] = None,
|
|
287
415
|
reconnect_strategy: Optional[BackoffStrategy] = None,
|
|
416
|
+
database_id: Optional[int] = None,
|
|
288
417
|
client_name: Optional[str] = None,
|
|
289
418
|
protocol: ProtocolVersion = ProtocolVersion.RESP3,
|
|
290
419
|
inflight_requests_limit: Optional[int] = None,
|
|
@@ -298,6 +427,7 @@ class BaseClientConfiguration:
|
|
|
298
427
|
self.read_from = read_from
|
|
299
428
|
self.request_timeout = request_timeout
|
|
300
429
|
self.reconnect_strategy = reconnect_strategy
|
|
430
|
+
self.database_id = database_id
|
|
301
431
|
self.client_name = client_name
|
|
302
432
|
self.protocol = protocol
|
|
303
433
|
self.inflight_requests_limit = inflight_requests_limit
|
|
@@ -315,6 +445,73 @@ class BaseClientConfiguration:
|
|
|
315
445
|
"client_az must be set when read_from is set to AZ_AFFINITY_REPLICAS_AND_PRIMARY"
|
|
316
446
|
)
|
|
317
447
|
|
|
448
|
+
def _set_addresses_in_request(self, request: ConnectionRequest) -> None:
|
|
449
|
+
"""Set addresses in the protobuf request."""
|
|
450
|
+
for address in self.addresses:
|
|
451
|
+
address_info = request.addresses.add()
|
|
452
|
+
address_info.host = address.host
|
|
453
|
+
address_info.port = address.port
|
|
454
|
+
|
|
455
|
+
def _set_reconnect_strategy_in_request(self, request: ConnectionRequest) -> None:
|
|
456
|
+
"""Set reconnect strategy in the protobuf request."""
|
|
457
|
+
if not self.reconnect_strategy:
|
|
458
|
+
return
|
|
459
|
+
|
|
460
|
+
request.connection_retry_strategy.number_of_retries = (
|
|
461
|
+
self.reconnect_strategy.num_of_retries
|
|
462
|
+
)
|
|
463
|
+
request.connection_retry_strategy.factor = self.reconnect_strategy.factor
|
|
464
|
+
request.connection_retry_strategy.exponent_base = (
|
|
465
|
+
self.reconnect_strategy.exponent_base
|
|
466
|
+
)
|
|
467
|
+
if self.reconnect_strategy.jitter_percent is not None:
|
|
468
|
+
request.connection_retry_strategy.jitter_percent = (
|
|
469
|
+
self.reconnect_strategy.jitter_percent
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
def _set_credentials_in_request(self, request: ConnectionRequest) -> None:
|
|
473
|
+
"""Set credentials in the protobuf request."""
|
|
474
|
+
if not self.credentials:
|
|
475
|
+
return
|
|
476
|
+
|
|
477
|
+
if self.credentials.username:
|
|
478
|
+
request.authentication_info.username = self.credentials.username
|
|
479
|
+
|
|
480
|
+
if self.credentials.password:
|
|
481
|
+
request.authentication_info.password = self.credentials.password
|
|
482
|
+
|
|
483
|
+
# Set IAM credentials if present
|
|
484
|
+
if self.credentials.iam_config:
|
|
485
|
+
iam_config = self.credentials.iam_config
|
|
486
|
+
request.authentication_info.iam_credentials.cluster_name = (
|
|
487
|
+
iam_config.cluster_name
|
|
488
|
+
)
|
|
489
|
+
request.authentication_info.iam_credentials.region = iam_config.region
|
|
490
|
+
|
|
491
|
+
# Map ServiceType enum to protobuf ServiceType
|
|
492
|
+
if iam_config.service == ServiceType.ELASTICACHE:
|
|
493
|
+
from glide_shared.protobuf.connection_request_pb2 import (
|
|
494
|
+
ServiceType as ProtobufServiceType,
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
request.authentication_info.iam_credentials.service_type = (
|
|
498
|
+
ProtobufServiceType.ELASTICACHE
|
|
499
|
+
)
|
|
500
|
+
elif iam_config.service == ServiceType.MEMORYDB:
|
|
501
|
+
from glide_shared.protobuf.connection_request_pb2 import (
|
|
502
|
+
ServiceType as ProtobufServiceType,
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
request.authentication_info.iam_credentials.service_type = (
|
|
506
|
+
ProtobufServiceType.MEMORYDB
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
# Set optional refresh interval
|
|
510
|
+
if iam_config.refresh_interval_seconds is not None:
|
|
511
|
+
request.authentication_info.iam_credentials.refresh_interval_seconds = (
|
|
512
|
+
iam_config.refresh_interval_seconds
|
|
513
|
+
)
|
|
514
|
+
|
|
318
515
|
def _create_a_protobuf_conn_request(
|
|
319
516
|
self, cluster_mode: bool = False
|
|
320
517
|
) -> ConnectionRequest:
|
|
@@ -328,44 +525,34 @@ class BaseClientConfiguration:
|
|
|
328
525
|
ConnectionRequest: Protobuf ConnectionRequest.
|
|
329
526
|
"""
|
|
330
527
|
request = ConnectionRequest()
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
address_info.port = address.port
|
|
528
|
+
|
|
529
|
+
# Set basic configuration
|
|
530
|
+
self._set_addresses_in_request(request)
|
|
335
531
|
request.tls_mode = TlsMode.SecureTls if self.use_tls else TlsMode.NoTls
|
|
336
532
|
request.read_from = self.read_from.value
|
|
533
|
+
request.cluster_mode_enabled = cluster_mode
|
|
534
|
+
request.protocol = self.protocol.value
|
|
535
|
+
|
|
536
|
+
# Set optional configuration
|
|
337
537
|
if self.request_timeout:
|
|
338
538
|
request.request_timeout = self.request_timeout
|
|
339
|
-
if self.reconnect_strategy:
|
|
340
|
-
request.connection_retry_strategy.number_of_retries = (
|
|
341
|
-
self.reconnect_strategy.num_of_retries
|
|
342
|
-
)
|
|
343
|
-
request.connection_retry_strategy.factor = self.reconnect_strategy.factor
|
|
344
|
-
request.connection_retry_strategy.exponent_base = (
|
|
345
|
-
self.reconnect_strategy.exponent_base
|
|
346
|
-
)
|
|
347
|
-
if self.reconnect_strategy.jitter_percent is not None:
|
|
348
|
-
request.connection_retry_strategy.jitter_percent = (
|
|
349
|
-
self.reconnect_strategy.jitter_percent
|
|
350
|
-
)
|
|
351
539
|
|
|
352
|
-
request
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
request.authentication_info.username = self.credentials.username
|
|
356
|
-
request.authentication_info.password = self.credentials.password
|
|
540
|
+
self._set_reconnect_strategy_in_request(request)
|
|
541
|
+
self._set_credentials_in_request(request)
|
|
542
|
+
|
|
357
543
|
if self.client_name:
|
|
358
544
|
request.client_name = self.client_name
|
|
359
|
-
request.protocol = self.protocol.value
|
|
360
545
|
if self.inflight_requests_limit:
|
|
361
546
|
request.inflight_requests_limit = self.inflight_requests_limit
|
|
362
547
|
if self.client_az:
|
|
363
548
|
request.client_az = self.client_az
|
|
549
|
+
if self.database_id is not None:
|
|
550
|
+
request.database_id = self.database_id
|
|
364
551
|
if self.advanced_config:
|
|
365
552
|
self.advanced_config._create_a_protobuf_conn_request(request)
|
|
366
|
-
|
|
367
553
|
if self.lazy_connect is not None:
|
|
368
554
|
request.lazy_connect = self.lazy_connect
|
|
555
|
+
|
|
369
556
|
return request
|
|
370
557
|
|
|
371
558
|
def _is_pubsub_configured(self) -> bool:
|
|
@@ -373,7 +560,7 @@ class BaseClientConfiguration:
|
|
|
373
560
|
|
|
374
561
|
def _get_pubsub_callback_and_context(
|
|
375
562
|
self,
|
|
376
|
-
) -> Tuple[Optional[Callable[[
|
|
563
|
+
) -> Tuple[Optional[Callable[[PubSubMsg, Any], None]], Any]:
|
|
377
564
|
return None, None
|
|
378
565
|
|
|
379
566
|
|
|
@@ -386,9 +573,10 @@ class AdvancedGlideClientConfiguration(AdvancedBaseClientConfiguration):
|
|
|
386
573
|
self,
|
|
387
574
|
connection_timeout: Optional[int] = None,
|
|
388
575
|
tls_config: Optional[TlsAdvancedConfiguration] = None,
|
|
576
|
+
tcp_nodelay: Optional[bool] = None,
|
|
389
577
|
):
|
|
390
578
|
|
|
391
|
-
super().__init__(connection_timeout, tls_config)
|
|
579
|
+
super().__init__(connection_timeout, tls_config, tcp_nodelay)
|
|
392
580
|
|
|
393
581
|
|
|
394
582
|
class GlideClientConfiguration(BaseClientConfiguration):
|
|
@@ -397,12 +585,12 @@ class GlideClientConfiguration(BaseClientConfiguration):
|
|
|
397
585
|
|
|
398
586
|
Attributes:
|
|
399
587
|
addresses (List[NodeAddress]): DNS Addresses and ports of known nodes in the cluster.
|
|
400
|
-
|
|
588
|
+
Only nodes whose addresses were provided will be used by the client.
|
|
401
589
|
For example::
|
|
402
590
|
|
|
403
591
|
[
|
|
404
|
-
|
|
405
|
-
|
|
592
|
+
NodeAddress("sample-address-0001.use1.cache.amazonaws.com", 6379),
|
|
593
|
+
NodeAddress("sample-address-0002.use1.cache.amazonaws.com", 6379)
|
|
406
594
|
]
|
|
407
595
|
|
|
408
596
|
use_tls (bool): True if communication with the cluster should use Transport Level Security.
|
|
@@ -418,7 +606,7 @@ class GlideClientConfiguration(BaseClientConfiguration):
|
|
|
418
606
|
reconnect_strategy (Optional[BackoffStrategy]): Strategy used to determine how and when to reconnect, in case of
|
|
419
607
|
connection failures.
|
|
420
608
|
If not set, a default backoff strategy will be used.
|
|
421
|
-
database_id (Optional[int]):
|
|
609
|
+
database_id (Optional[int]): Index of the logical database to connect to.
|
|
422
610
|
client_name (Optional[str]): Client name to be used for the client. Will be used with CLIENT SETNAME command during
|
|
423
611
|
connection establishment.
|
|
424
612
|
protocol (ProtocolVersion): The version of the RESP protocol to communicate with the server.
|
|
@@ -457,7 +645,7 @@ class GlideClientConfiguration(BaseClientConfiguration):
|
|
|
457
645
|
Attributes:
|
|
458
646
|
channels_and_patterns (Dict[GlideClientConfiguration.PubSubChannelModes, Set[str]]):
|
|
459
647
|
Channels and patterns by modes.
|
|
460
|
-
callback (Optional[Callable[[
|
|
648
|
+
callback (Optional[Callable[[PubSubMsg, Any], None]]):
|
|
461
649
|
Optional callback to accept the incomming messages.
|
|
462
650
|
context (Any):
|
|
463
651
|
Arbitrary context to pass to the callback.
|
|
@@ -466,7 +654,7 @@ class GlideClientConfiguration(BaseClientConfiguration):
|
|
|
466
654
|
channels_and_patterns: Dict[
|
|
467
655
|
GlideClientConfiguration.PubSubChannelModes, Set[str]
|
|
468
656
|
]
|
|
469
|
-
callback: Optional[Callable[[
|
|
657
|
+
callback: Optional[Callable[[PubSubMsg, Any], None]]
|
|
470
658
|
context: Any
|
|
471
659
|
|
|
472
660
|
def __init__(
|
|
@@ -493,6 +681,7 @@ class GlideClientConfiguration(BaseClientConfiguration):
|
|
|
493
681
|
read_from=read_from,
|
|
494
682
|
request_timeout=request_timeout,
|
|
495
683
|
reconnect_strategy=reconnect_strategy,
|
|
684
|
+
database_id=database_id,
|
|
496
685
|
client_name=client_name,
|
|
497
686
|
protocol=protocol,
|
|
498
687
|
inflight_requests_limit=inflight_requests_limit,
|
|
@@ -500,7 +689,6 @@ class GlideClientConfiguration(BaseClientConfiguration):
|
|
|
500
689
|
advanced_config=advanced_config,
|
|
501
690
|
lazy_connect=lazy_connect,
|
|
502
691
|
)
|
|
503
|
-
self.database_id = database_id
|
|
504
692
|
self.pubsub_subscriptions = pubsub_subscriptions
|
|
505
693
|
|
|
506
694
|
def _create_a_protobuf_conn_request(
|
|
@@ -508,8 +696,6 @@ class GlideClientConfiguration(BaseClientConfiguration):
|
|
|
508
696
|
) -> ConnectionRequest:
|
|
509
697
|
assert cluster_mode is False
|
|
510
698
|
request = super()._create_a_protobuf_conn_request(cluster_mode)
|
|
511
|
-
if self.database_id:
|
|
512
|
-
request.database_id = self.database_id
|
|
513
699
|
|
|
514
700
|
if self.pubsub_subscriptions:
|
|
515
701
|
if self.protocol == ProtocolVersion.RESP2:
|
|
@@ -540,7 +726,7 @@ class GlideClientConfiguration(BaseClientConfiguration):
|
|
|
540
726
|
|
|
541
727
|
def _get_pubsub_callback_and_context(
|
|
542
728
|
self,
|
|
543
|
-
) -> Tuple[Optional[Callable[[
|
|
729
|
+
) -> Tuple[Optional[Callable[[PubSubMsg, Any], None]], Any]:
|
|
544
730
|
if self.pubsub_subscriptions:
|
|
545
731
|
return self.pubsub_subscriptions.callback, self.pubsub_subscriptions.context
|
|
546
732
|
return None, None
|
|
@@ -549,14 +735,39 @@ class GlideClientConfiguration(BaseClientConfiguration):
|
|
|
549
735
|
class AdvancedGlideClusterClientConfiguration(AdvancedBaseClientConfiguration):
|
|
550
736
|
"""
|
|
551
737
|
Represents the advanced configuration settings for a Glide Cluster client.
|
|
738
|
+
|
|
739
|
+
Attributes:
|
|
740
|
+
connection_timeout (Optional[int]): The duration in milliseconds to wait for a TCP/TLS connection to complete.
|
|
741
|
+
This applies both during initial client creation and any reconnection that may occur during request processing.
|
|
742
|
+
**Note**: A high connection timeout may lead to prolonged blocking of the entire command pipeline.
|
|
743
|
+
If not explicitly set, a default value of 2000 milliseconds will be used.
|
|
744
|
+
tls_config (Optional[TlsAdvancedConfiguration]): The advanced TLS configuration settings.
|
|
745
|
+
This allows for more granular control of TLS behavior, such as enabling an insecure mode
|
|
746
|
+
that bypasses certificate validation.
|
|
747
|
+
refresh_topology_from_initial_nodes (bool): Enables refreshing the cluster topology using only the initial nodes.
|
|
748
|
+
When this option is enabled, all topology updates (both the periodic checks and on-demand refreshes
|
|
749
|
+
triggered by topology changes) will query only the initial nodes provided when creating the client, rather than using the internal cluster view.
|
|
552
750
|
"""
|
|
553
751
|
|
|
554
752
|
def __init__(
|
|
555
753
|
self,
|
|
556
754
|
connection_timeout: Optional[int] = None,
|
|
557
755
|
tls_config: Optional[TlsAdvancedConfiguration] = None,
|
|
756
|
+
refresh_topology_from_initial_nodes: bool = False,
|
|
757
|
+
tcp_nodelay: Optional[bool] = None,
|
|
558
758
|
):
|
|
559
|
-
super().__init__(connection_timeout, tls_config)
|
|
759
|
+
super().__init__(connection_timeout, tls_config, tcp_nodelay)
|
|
760
|
+
self.refresh_topology_from_initial_nodes = refresh_topology_from_initial_nodes
|
|
761
|
+
|
|
762
|
+
def _create_a_protobuf_conn_request(
|
|
763
|
+
self, request: ConnectionRequest
|
|
764
|
+
) -> ConnectionRequest:
|
|
765
|
+
super()._create_a_protobuf_conn_request(request)
|
|
766
|
+
|
|
767
|
+
request.refresh_topology_from_initial_nodes = (
|
|
768
|
+
self.refresh_topology_from_initial_nodes
|
|
769
|
+
)
|
|
770
|
+
return request
|
|
560
771
|
|
|
561
772
|
|
|
562
773
|
class GlideClusterClientConfiguration(BaseClientConfiguration):
|
|
@@ -569,7 +780,7 @@ class GlideClusterClientConfiguration(BaseClientConfiguration):
|
|
|
569
780
|
For example::
|
|
570
781
|
|
|
571
782
|
[
|
|
572
|
-
|
|
783
|
+
NodeAddress("sample-address-0001.use1.cache.amazonaws.com", 6379),
|
|
573
784
|
]
|
|
574
785
|
|
|
575
786
|
use_tls (bool): True if communication with the cluster should use Transport Level Security.
|
|
@@ -585,6 +796,7 @@ class GlideClusterClientConfiguration(BaseClientConfiguration):
|
|
|
585
796
|
reconnect_strategy (Optional[BackoffStrategy]): Strategy used to determine how and when to reconnect, in case of
|
|
586
797
|
connection failures.
|
|
587
798
|
If not set, a default backoff strategy will be used.
|
|
799
|
+
database_id (Optional[int]): Index of the logical database to connect to.
|
|
588
800
|
client_name (Optional[str]): Client name to be used for the client. Will be used with CLIENT SETNAME command during
|
|
589
801
|
connection establishment.
|
|
590
802
|
protocol (ProtocolVersion): The version of the RESP protocol to communicate with the server.
|
|
@@ -634,7 +846,7 @@ class GlideClusterClientConfiguration(BaseClientConfiguration):
|
|
|
634
846
|
Attributes:
|
|
635
847
|
channels_and_patterns (Dict[GlideClusterClientConfiguration.PubSubChannelModes, Set[str]]):
|
|
636
848
|
Channels and patterns by modes.
|
|
637
|
-
callback (Optional[Callable[[
|
|
849
|
+
callback (Optional[Callable[[PubSubMsg, Any], None]]):
|
|
638
850
|
Optional callback to accept the incoming messages.
|
|
639
851
|
context (Any):
|
|
640
852
|
Arbitrary context to pass to the callback.
|
|
@@ -643,7 +855,7 @@ class GlideClusterClientConfiguration(BaseClientConfiguration):
|
|
|
643
855
|
channels_and_patterns: Dict[
|
|
644
856
|
GlideClusterClientConfiguration.PubSubChannelModes, Set[str]
|
|
645
857
|
]
|
|
646
|
-
callback: Optional[Callable[[
|
|
858
|
+
callback: Optional[Callable[[PubSubMsg, Any], None]]
|
|
647
859
|
context: Any
|
|
648
860
|
|
|
649
861
|
def __init__(
|
|
@@ -654,6 +866,7 @@ class GlideClusterClientConfiguration(BaseClientConfiguration):
|
|
|
654
866
|
read_from: ReadFrom = ReadFrom.PRIMARY,
|
|
655
867
|
request_timeout: Optional[int] = None,
|
|
656
868
|
reconnect_strategy: Optional[BackoffStrategy] = None,
|
|
869
|
+
database_id: Optional[int] = None,
|
|
657
870
|
client_name: Optional[str] = None,
|
|
658
871
|
protocol: ProtocolVersion = ProtocolVersion.RESP3,
|
|
659
872
|
periodic_checks: Union[
|
|
@@ -672,6 +885,7 @@ class GlideClusterClientConfiguration(BaseClientConfiguration):
|
|
|
672
885
|
read_from=read_from,
|
|
673
886
|
request_timeout=request_timeout,
|
|
674
887
|
reconnect_strategy=reconnect_strategy,
|
|
888
|
+
database_id=database_id,
|
|
675
889
|
client_name=client_name,
|
|
676
890
|
protocol=protocol,
|
|
677
891
|
inflight_requests_limit=inflight_requests_limit,
|
|
@@ -725,7 +939,48 @@ class GlideClusterClientConfiguration(BaseClientConfiguration):
|
|
|
725
939
|
|
|
726
940
|
def _get_pubsub_callback_and_context(
|
|
727
941
|
self,
|
|
728
|
-
) -> Tuple[Optional[Callable[[
|
|
942
|
+
) -> Tuple[Optional[Callable[[PubSubMsg, Any], None]], Any]:
|
|
729
943
|
if self.pubsub_subscriptions:
|
|
730
944
|
return self.pubsub_subscriptions.callback, self.pubsub_subscriptions.context
|
|
731
945
|
return None, None
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
def load_root_certificates_from_file(path: str) -> bytes:
|
|
949
|
+
"""
|
|
950
|
+
Load PEM-encoded root certificates from a file.
|
|
951
|
+
|
|
952
|
+
This is a convenience function for loading custom root certificates from disk
|
|
953
|
+
to be used with TlsAdvancedConfiguration.
|
|
954
|
+
|
|
955
|
+
Args:
|
|
956
|
+
path (str): The file path to the PEM-encoded certificate file.
|
|
957
|
+
|
|
958
|
+
Returns:
|
|
959
|
+
bytes: The certificate data in PEM format.
|
|
960
|
+
|
|
961
|
+
Raises:
|
|
962
|
+
FileNotFoundError: If the certificate file does not exist.
|
|
963
|
+
ConfigurationError: If the certificate file is empty.
|
|
964
|
+
|
|
965
|
+
Example usage::
|
|
966
|
+
|
|
967
|
+
from glide_shared.config import load_root_certificates_from_file, TlsAdvancedConfiguration
|
|
968
|
+
|
|
969
|
+
# Load certificates from file
|
|
970
|
+
certs = load_root_certificates_from_file('/path/to/ca-cert.pem')
|
|
971
|
+
|
|
972
|
+
# Use in TLS configuration
|
|
973
|
+
tls_config = TlsAdvancedConfiguration(root_pem_cacerts=certs)
|
|
974
|
+
"""
|
|
975
|
+
try:
|
|
976
|
+
with open(path, "rb") as f:
|
|
977
|
+
data = f.read()
|
|
978
|
+
except FileNotFoundError:
|
|
979
|
+
raise FileNotFoundError(f"Certificate file not found: {path}")
|
|
980
|
+
except Exception as e:
|
|
981
|
+
raise ConfigurationError(f"Failed to read certificate file: {e}")
|
|
982
|
+
|
|
983
|
+
if len(data) == 0:
|
|
984
|
+
raise ConfigurationError(f"Certificate file is empty: {path}")
|
|
985
|
+
|
|
986
|
+
return data
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, Dict, List, Literal, Mapping, Optional, Set, TypeVar, Union
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
from
|
|
5
|
+
from glide_shared.protobuf.command_request_pb2 import CommandRequest
|
|
6
|
+
from glide_shared.protobuf.connection_request_pb2 import ConnectionRequest
|
|
7
|
+
from glide_shared.routes import ByAddressRoute, RandomNode, SlotIdRoute, SlotKeyRoute
|
|
8
8
|
|
|
9
9
|
OK: str = "OK"
|
|
10
10
|
DEFAULT_READ_BYTES_SIZE: int = pow(2, 16)
|