redis 5.2.1__py3-none-any.whl → 5.3.0b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- redis/asyncio/client.py +42 -1
- redis/asyncio/cluster.py +54 -0
- redis/asyncio/connection.py +65 -8
- redis/auth/__init__.py +0 -0
- redis/auth/err.py +31 -0
- redis/auth/idp.py +28 -0
- redis/auth/token.py +126 -0
- redis/auth/token_manager.py +370 -0
- redis/client.py +51 -3
- redis/cluster.py +39 -0
- redis/connection.py +73 -0
- redis/credentials.py +40 -1
- redis/event.py +394 -0
- {redis-5.2.1.dist-info → redis-5.3.0b3.dist-info}/METADATA +1 -1
- {redis-5.2.1.dist-info → redis-5.3.0b3.dist-info}/RECORD +18 -12
- {redis-5.2.1.dist-info → redis-5.3.0b3.dist-info}/LICENSE +0 -0
- {redis-5.2.1.dist-info → redis-5.3.0b3.dist-info}/WHEEL +0 -0
- {redis-5.2.1.dist-info → redis-5.3.0b3.dist-info}/top_level.txt +0 -0
redis/connection.py
CHANGED
|
@@ -22,8 +22,10 @@ from redis.cache import (
|
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
from ._parsers import Encoder, _HiredisParser, _RESP2Parser, _RESP3Parser
|
|
25
|
+
from .auth.token import TokenInterface
|
|
25
26
|
from .backoff import NoBackoff
|
|
26
27
|
from .credentials import CredentialProvider, UsernamePasswordCredentialProvider
|
|
28
|
+
from .event import AfterConnectionReleasedEvent, EventDispatcher
|
|
27
29
|
from .exceptions import (
|
|
28
30
|
AuthenticationError,
|
|
29
31
|
AuthenticationWrongNumberOfArgsError,
|
|
@@ -151,6 +153,10 @@ class ConnectionInterface:
|
|
|
151
153
|
def set_parser(self, parser_class):
|
|
152
154
|
pass
|
|
153
155
|
|
|
156
|
+
@abstractmethod
|
|
157
|
+
def get_protocol(self):
|
|
158
|
+
pass
|
|
159
|
+
|
|
154
160
|
@abstractmethod
|
|
155
161
|
def connect(self):
|
|
156
162
|
pass
|
|
@@ -202,6 +208,14 @@ class ConnectionInterface:
|
|
|
202
208
|
def handshake_metadata(self) -> Union[Dict[bytes, bytes], Dict[str, str]]:
|
|
203
209
|
pass
|
|
204
210
|
|
|
211
|
+
@abstractmethod
|
|
212
|
+
def set_re_auth_token(self, token: TokenInterface):
|
|
213
|
+
pass
|
|
214
|
+
|
|
215
|
+
@abstractmethod
|
|
216
|
+
def re_auth(self):
|
|
217
|
+
pass
|
|
218
|
+
|
|
205
219
|
|
|
206
220
|
class AbstractConnection(ConnectionInterface):
|
|
207
221
|
"Manages communication to and from a Redis server"
|
|
@@ -229,6 +243,7 @@ class AbstractConnection(ConnectionInterface):
|
|
|
229
243
|
credential_provider: Optional[CredentialProvider] = None,
|
|
230
244
|
protocol: Optional[int] = 2,
|
|
231
245
|
command_packer: Optional[Callable[[], None]] = None,
|
|
246
|
+
event_dispatcher: Optional[EventDispatcher] = None,
|
|
232
247
|
):
|
|
233
248
|
"""
|
|
234
249
|
Initialize a new Connection.
|
|
@@ -244,6 +259,10 @@ class AbstractConnection(ConnectionInterface):
|
|
|
244
259
|
"1. 'password' and (optional) 'username'\n"
|
|
245
260
|
"2. 'credential_provider'"
|
|
246
261
|
)
|
|
262
|
+
if event_dispatcher is None:
|
|
263
|
+
self._event_dispatcher = EventDispatcher()
|
|
264
|
+
else:
|
|
265
|
+
self._event_dispatcher = event_dispatcher
|
|
247
266
|
self.pid = os.getpid()
|
|
248
267
|
self.db = db
|
|
249
268
|
self.client_name = client_name
|
|
@@ -283,6 +302,7 @@ class AbstractConnection(ConnectionInterface):
|
|
|
283
302
|
self.set_parser(parser_class)
|
|
284
303
|
self._connect_callbacks = []
|
|
285
304
|
self._buffer_cutoff = 6000
|
|
305
|
+
self._re_auth_token: Optional[TokenInterface] = None
|
|
286
306
|
try:
|
|
287
307
|
p = int(protocol)
|
|
288
308
|
except TypeError:
|
|
@@ -663,6 +683,19 @@ class AbstractConnection(ConnectionInterface):
|
|
|
663
683
|
def handshake_metadata(self, value: Union[Dict[bytes, bytes], Dict[str, str]]):
|
|
664
684
|
self._handshake_metadata = value
|
|
665
685
|
|
|
686
|
+
def set_re_auth_token(self, token: TokenInterface):
|
|
687
|
+
self._re_auth_token = token
|
|
688
|
+
|
|
689
|
+
def re_auth(self):
|
|
690
|
+
if self._re_auth_token is not None:
|
|
691
|
+
self.send_command(
|
|
692
|
+
"AUTH",
|
|
693
|
+
self._re_auth_token.try_get("oid"),
|
|
694
|
+
self._re_auth_token.get_value(),
|
|
695
|
+
)
|
|
696
|
+
self.read_response()
|
|
697
|
+
self._re_auth_token = None
|
|
698
|
+
|
|
666
699
|
|
|
667
700
|
class Connection(AbstractConnection):
|
|
668
701
|
"Manages TCP communication to and from a Redis server"
|
|
@@ -750,6 +783,7 @@ class CacheProxyConnection(ConnectionInterface):
|
|
|
750
783
|
self.retry = self._conn.retry
|
|
751
784
|
self.host = self._conn.host
|
|
752
785
|
self.port = self._conn.port
|
|
786
|
+
self.credential_provider = conn.credential_provider
|
|
753
787
|
self._pool_lock = pool_lock
|
|
754
788
|
self._cache = cache
|
|
755
789
|
self._cache_lock = threading.Lock()
|
|
@@ -933,6 +967,15 @@ class CacheProxyConnection(ConnectionInterface):
|
|
|
933
967
|
else:
|
|
934
968
|
self._cache.delete_by_redis_keys(data[1])
|
|
935
969
|
|
|
970
|
+
def get_protocol(self):
|
|
971
|
+
return self._conn.get_protocol()
|
|
972
|
+
|
|
973
|
+
def set_re_auth_token(self, token: TokenInterface):
|
|
974
|
+
self._conn.set_re_auth_token(token)
|
|
975
|
+
|
|
976
|
+
def re_auth(self):
|
|
977
|
+
self._conn.re_auth()
|
|
978
|
+
|
|
936
979
|
|
|
937
980
|
class SSLConnection(Connection):
|
|
938
981
|
"""Manages SSL connections to and from the Redis server(s).
|
|
@@ -1318,6 +1361,10 @@ class ConnectionPool:
|
|
|
1318
1361
|
connection_kwargs.pop("cache", None)
|
|
1319
1362
|
connection_kwargs.pop("cache_config", None)
|
|
1320
1363
|
|
|
1364
|
+
self._event_dispatcher = self.connection_kwargs.get("event_dispatcher", None)
|
|
1365
|
+
if self._event_dispatcher is None:
|
|
1366
|
+
self._event_dispatcher = EventDispatcher()
|
|
1367
|
+
|
|
1321
1368
|
# a lock to protect the critical section in _checkpid().
|
|
1322
1369
|
# this lock is acquired when the process id changes, such as
|
|
1323
1370
|
# after a fork. during this time, multiple threads in the child
|
|
@@ -1475,6 +1522,9 @@ class ConnectionPool:
|
|
|
1475
1522
|
|
|
1476
1523
|
if self.owns_connection(connection):
|
|
1477
1524
|
self._available_connections.append(connection)
|
|
1525
|
+
self._event_dispatcher.dispatch(
|
|
1526
|
+
AfterConnectionReleasedEvent(connection)
|
|
1527
|
+
)
|
|
1478
1528
|
else:
|
|
1479
1529
|
# pool doesn't own this connection. do not add it back
|
|
1480
1530
|
# to the pool and decrement the count so that another
|
|
@@ -1517,6 +1567,29 @@ class ConnectionPool:
|
|
|
1517
1567
|
for conn in self._in_use_connections:
|
|
1518
1568
|
conn.retry = retry
|
|
1519
1569
|
|
|
1570
|
+
def re_auth_callback(self, token: TokenInterface):
|
|
1571
|
+
with self._lock:
|
|
1572
|
+
for conn in self._available_connections:
|
|
1573
|
+
conn.retry.call_with_retry(
|
|
1574
|
+
lambda: conn.send_command(
|
|
1575
|
+
"AUTH", token.try_get("oid"), token.get_value()
|
|
1576
|
+
),
|
|
1577
|
+
lambda error: self._mock(error),
|
|
1578
|
+
)
|
|
1579
|
+
conn.retry.call_with_retry(
|
|
1580
|
+
lambda: conn.read_response(), lambda error: self._mock(error)
|
|
1581
|
+
)
|
|
1582
|
+
for conn in self._in_use_connections:
|
|
1583
|
+
conn.set_re_auth_token(token)
|
|
1584
|
+
|
|
1585
|
+
async def _mock(self, error: RedisError):
|
|
1586
|
+
"""
|
|
1587
|
+
Dummy functions, needs to be passed as error callback to retry object.
|
|
1588
|
+
:param error:
|
|
1589
|
+
:return:
|
|
1590
|
+
"""
|
|
1591
|
+
pass
|
|
1592
|
+
|
|
1520
1593
|
|
|
1521
1594
|
class BlockingConnectionPool(ConnectionPool):
|
|
1522
1595
|
"""
|
redis/credentials.py
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import logging
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Any, Callable, Optional, Tuple, Union
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
2
6
|
|
|
3
7
|
|
|
4
8
|
class CredentialProvider:
|
|
@@ -9,6 +13,38 @@ class CredentialProvider:
|
|
|
9
13
|
def get_credentials(self) -> Union[Tuple[str], Tuple[str, str]]:
|
|
10
14
|
raise NotImplementedError("get_credentials must be implemented")
|
|
11
15
|
|
|
16
|
+
async def get_credentials_async(self) -> Union[Tuple[str], Tuple[str, str]]:
|
|
17
|
+
logger.warning(
|
|
18
|
+
"This method is added for backward compatability. "
|
|
19
|
+
"Please override it in your implementation."
|
|
20
|
+
)
|
|
21
|
+
return self.get_credentials()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class StreamingCredentialProvider(CredentialProvider, ABC):
|
|
25
|
+
"""
|
|
26
|
+
Credential provider that streams credentials in the background.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def on_next(self, callback: Callable[[Any], None]):
|
|
31
|
+
"""
|
|
32
|
+
Specifies the callback that should be invoked
|
|
33
|
+
when the next credentials will be retrieved.
|
|
34
|
+
|
|
35
|
+
:param callback: Callback with
|
|
36
|
+
:return:
|
|
37
|
+
"""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def on_error(self, callback: Callable[[Exception], None]):
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
@abstractmethod
|
|
45
|
+
def is_streaming(self) -> bool:
|
|
46
|
+
pass
|
|
47
|
+
|
|
12
48
|
|
|
13
49
|
class UsernamePasswordCredentialProvider(CredentialProvider):
|
|
14
50
|
"""
|
|
@@ -24,3 +60,6 @@ class UsernamePasswordCredentialProvider(CredentialProvider):
|
|
|
24
60
|
if self.username:
|
|
25
61
|
return self.username, self.password
|
|
26
62
|
return (self.password,)
|
|
63
|
+
|
|
64
|
+
async def get_credentials_async(self) -> Union[Tuple[str], Tuple[str, str]]:
|
|
65
|
+
return self.get_credentials()
|
redis/event.py
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import threading
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import List, Optional, Union
|
|
6
|
+
|
|
7
|
+
from redis.auth.token import TokenInterface
|
|
8
|
+
from redis.credentials import CredentialProvider, StreamingCredentialProvider
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EventListenerInterface(ABC):
|
|
12
|
+
"""
|
|
13
|
+
Represents a listener for given event object.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def listen(self, event: object):
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AsyncEventListenerInterface(ABC):
|
|
22
|
+
"""
|
|
23
|
+
Represents an async listener for given event object.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
async def listen(self, event: object):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class EventDispatcherInterface(ABC):
|
|
32
|
+
"""
|
|
33
|
+
Represents a dispatcher that dispatches events to listeners
|
|
34
|
+
associated with given event.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def dispatch(self, event: object):
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
async def dispatch_async(self, event: object):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class EventException(Exception):
|
|
47
|
+
"""
|
|
48
|
+
Exception wrapper that adds an event object into exception context.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(self, exception: Exception, event: object):
|
|
52
|
+
self.exception = exception
|
|
53
|
+
self.event = event
|
|
54
|
+
super().__init__(exception)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class EventDispatcher(EventDispatcherInterface):
|
|
58
|
+
# TODO: Make dispatcher to accept external mappings.
|
|
59
|
+
def __init__(self):
|
|
60
|
+
"""
|
|
61
|
+
Mapping should be extended for any new events or listeners to be added.
|
|
62
|
+
"""
|
|
63
|
+
self._event_listeners_mapping = {
|
|
64
|
+
AfterConnectionReleasedEvent: [
|
|
65
|
+
ReAuthConnectionListener(),
|
|
66
|
+
],
|
|
67
|
+
AfterPooledConnectionsInstantiationEvent: [
|
|
68
|
+
RegisterReAuthForPooledConnections()
|
|
69
|
+
],
|
|
70
|
+
AfterSingleConnectionInstantiationEvent: [
|
|
71
|
+
RegisterReAuthForSingleConnection()
|
|
72
|
+
],
|
|
73
|
+
AfterPubSubConnectionInstantiationEvent: [RegisterReAuthForPubSub()],
|
|
74
|
+
AfterAsyncClusterInstantiationEvent: [RegisterReAuthForAsyncClusterNodes()],
|
|
75
|
+
AsyncAfterConnectionReleasedEvent: [
|
|
76
|
+
AsyncReAuthConnectionListener(),
|
|
77
|
+
],
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
def dispatch(self, event: object):
|
|
81
|
+
listeners = self._event_listeners_mapping.get(type(event))
|
|
82
|
+
|
|
83
|
+
for listener in listeners:
|
|
84
|
+
listener.listen(event)
|
|
85
|
+
|
|
86
|
+
async def dispatch_async(self, event: object):
|
|
87
|
+
listeners = self._event_listeners_mapping.get(type(event))
|
|
88
|
+
|
|
89
|
+
for listener in listeners:
|
|
90
|
+
await listener.listen(event)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class AfterConnectionReleasedEvent:
|
|
94
|
+
"""
|
|
95
|
+
Event that will be fired before each command execution.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def __init__(self, connection):
|
|
99
|
+
self._connection = connection
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def connection(self):
|
|
103
|
+
return self._connection
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class AsyncAfterConnectionReleasedEvent(AfterConnectionReleasedEvent):
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class ClientType(Enum):
|
|
111
|
+
SYNC = ("sync",)
|
|
112
|
+
ASYNC = ("async",)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class AfterPooledConnectionsInstantiationEvent:
|
|
116
|
+
"""
|
|
117
|
+
Event that will be fired after pooled connection instances was created.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def __init__(
|
|
121
|
+
self,
|
|
122
|
+
connection_pools: List,
|
|
123
|
+
client_type: ClientType,
|
|
124
|
+
credential_provider: Optional[CredentialProvider] = None,
|
|
125
|
+
):
|
|
126
|
+
self._connection_pools = connection_pools
|
|
127
|
+
self._client_type = client_type
|
|
128
|
+
self._credential_provider = credential_provider
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def connection_pools(self):
|
|
132
|
+
return self._connection_pools
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def client_type(self) -> ClientType:
|
|
136
|
+
return self._client_type
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def credential_provider(self) -> Union[CredentialProvider, None]:
|
|
140
|
+
return self._credential_provider
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class AfterSingleConnectionInstantiationEvent:
|
|
144
|
+
"""
|
|
145
|
+
Event that will be fired after single connection instances was created.
|
|
146
|
+
|
|
147
|
+
:param connection_lock: For sync client thread-lock should be provided,
|
|
148
|
+
for async asyncio.Lock
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
def __init__(
|
|
152
|
+
self,
|
|
153
|
+
connection,
|
|
154
|
+
client_type: ClientType,
|
|
155
|
+
connection_lock: Union[threading.Lock, asyncio.Lock],
|
|
156
|
+
):
|
|
157
|
+
self._connection = connection
|
|
158
|
+
self._client_type = client_type
|
|
159
|
+
self._connection_lock = connection_lock
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def connection(self):
|
|
163
|
+
return self._connection
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def client_type(self) -> ClientType:
|
|
167
|
+
return self._client_type
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def connection_lock(self) -> Union[threading.Lock, asyncio.Lock]:
|
|
171
|
+
return self._connection_lock
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class AfterPubSubConnectionInstantiationEvent:
|
|
175
|
+
def __init__(
|
|
176
|
+
self,
|
|
177
|
+
pubsub_connection,
|
|
178
|
+
connection_pool,
|
|
179
|
+
client_type: ClientType,
|
|
180
|
+
connection_lock: Union[threading.Lock, asyncio.Lock],
|
|
181
|
+
):
|
|
182
|
+
self._pubsub_connection = pubsub_connection
|
|
183
|
+
self._connection_pool = connection_pool
|
|
184
|
+
self._client_type = client_type
|
|
185
|
+
self._connection_lock = connection_lock
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
def pubsub_connection(self):
|
|
189
|
+
return self._pubsub_connection
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def connection_pool(self):
|
|
193
|
+
return self._connection_pool
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def client_type(self) -> ClientType:
|
|
197
|
+
return self._client_type
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def connection_lock(self) -> Union[threading.Lock, asyncio.Lock]:
|
|
201
|
+
return self._connection_lock
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class AfterAsyncClusterInstantiationEvent:
|
|
205
|
+
"""
|
|
206
|
+
Event that will be fired after async cluster instance was created.
|
|
207
|
+
|
|
208
|
+
Async cluster doesn't use connection pools,
|
|
209
|
+
instead ClusterNode object manages connections.
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
def __init__(
|
|
213
|
+
self,
|
|
214
|
+
nodes: dict,
|
|
215
|
+
credential_provider: Optional[CredentialProvider] = None,
|
|
216
|
+
):
|
|
217
|
+
self._nodes = nodes
|
|
218
|
+
self._credential_provider = credential_provider
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def nodes(self) -> dict:
|
|
222
|
+
return self._nodes
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def credential_provider(self) -> Union[CredentialProvider, None]:
|
|
226
|
+
return self._credential_provider
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class ReAuthConnectionListener(EventListenerInterface):
|
|
230
|
+
"""
|
|
231
|
+
Listener that performs re-authentication of given connection.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
def listen(self, event: AfterConnectionReleasedEvent):
|
|
235
|
+
event.connection.re_auth()
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class AsyncReAuthConnectionListener(AsyncEventListenerInterface):
|
|
239
|
+
"""
|
|
240
|
+
Async listener that performs re-authentication of given connection.
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
async def listen(self, event: AsyncAfterConnectionReleasedEvent):
|
|
244
|
+
await event.connection.re_auth()
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class RegisterReAuthForPooledConnections(EventListenerInterface):
|
|
248
|
+
"""
|
|
249
|
+
Listener that registers a re-authentication callback for pooled connections.
|
|
250
|
+
Required by :class:`StreamingCredentialProvider`.
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
def __init__(self):
|
|
254
|
+
self._event = None
|
|
255
|
+
|
|
256
|
+
def listen(self, event: AfterPooledConnectionsInstantiationEvent):
|
|
257
|
+
if isinstance(event.credential_provider, StreamingCredentialProvider):
|
|
258
|
+
self._event = event
|
|
259
|
+
|
|
260
|
+
if event.client_type == ClientType.SYNC:
|
|
261
|
+
event.credential_provider.on_next(self._re_auth)
|
|
262
|
+
event.credential_provider.on_error(self._raise_on_error)
|
|
263
|
+
else:
|
|
264
|
+
event.credential_provider.on_next(self._re_auth_async)
|
|
265
|
+
event.credential_provider.on_error(self._raise_on_error_async)
|
|
266
|
+
|
|
267
|
+
def _re_auth(self, token):
|
|
268
|
+
for pool in self._event.connection_pools:
|
|
269
|
+
pool.re_auth_callback(token)
|
|
270
|
+
|
|
271
|
+
async def _re_auth_async(self, token):
|
|
272
|
+
for pool in self._event.connection_pools:
|
|
273
|
+
await pool.re_auth_callback(token)
|
|
274
|
+
|
|
275
|
+
def _raise_on_error(self, error: Exception):
|
|
276
|
+
raise EventException(error, self._event)
|
|
277
|
+
|
|
278
|
+
async def _raise_on_error_async(self, error: Exception):
|
|
279
|
+
raise EventException(error, self._event)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class RegisterReAuthForSingleConnection(EventListenerInterface):
|
|
283
|
+
"""
|
|
284
|
+
Listener that registers a re-authentication callback for single connection.
|
|
285
|
+
Required by :class:`StreamingCredentialProvider`.
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
def __init__(self):
|
|
289
|
+
self._event = None
|
|
290
|
+
|
|
291
|
+
def listen(self, event: AfterSingleConnectionInstantiationEvent):
|
|
292
|
+
if isinstance(
|
|
293
|
+
event.connection.credential_provider, StreamingCredentialProvider
|
|
294
|
+
):
|
|
295
|
+
self._event = event
|
|
296
|
+
|
|
297
|
+
if event.client_type == ClientType.SYNC:
|
|
298
|
+
event.connection.credential_provider.on_next(self._re_auth)
|
|
299
|
+
event.connection.credential_provider.on_error(self._raise_on_error)
|
|
300
|
+
else:
|
|
301
|
+
event.connection.credential_provider.on_next(self._re_auth_async)
|
|
302
|
+
event.connection.credential_provider.on_error(
|
|
303
|
+
self._raise_on_error_async
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
def _re_auth(self, token):
|
|
307
|
+
with self._event.connection_lock:
|
|
308
|
+
self._event.connection.send_command(
|
|
309
|
+
"AUTH", token.try_get("oid"), token.get_value()
|
|
310
|
+
)
|
|
311
|
+
self._event.connection.read_response()
|
|
312
|
+
|
|
313
|
+
async def _re_auth_async(self, token):
|
|
314
|
+
async with self._event.connection_lock:
|
|
315
|
+
await self._event.connection.send_command(
|
|
316
|
+
"AUTH", token.try_get("oid"), token.get_value()
|
|
317
|
+
)
|
|
318
|
+
await self._event.connection.read_response()
|
|
319
|
+
|
|
320
|
+
def _raise_on_error(self, error: Exception):
|
|
321
|
+
raise EventException(error, self._event)
|
|
322
|
+
|
|
323
|
+
async def _raise_on_error_async(self, error: Exception):
|
|
324
|
+
raise EventException(error, self._event)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class RegisterReAuthForAsyncClusterNodes(EventListenerInterface):
|
|
328
|
+
def __init__(self):
|
|
329
|
+
self._event = None
|
|
330
|
+
|
|
331
|
+
def listen(self, event: AfterAsyncClusterInstantiationEvent):
|
|
332
|
+
if isinstance(event.credential_provider, StreamingCredentialProvider):
|
|
333
|
+
self._event = event
|
|
334
|
+
event.credential_provider.on_next(self._re_auth)
|
|
335
|
+
event.credential_provider.on_error(self._raise_on_error)
|
|
336
|
+
|
|
337
|
+
async def _re_auth(self, token: TokenInterface):
|
|
338
|
+
for key in self._event.nodes:
|
|
339
|
+
await self._event.nodes[key].re_auth_callback(token)
|
|
340
|
+
|
|
341
|
+
async def _raise_on_error(self, error: Exception):
|
|
342
|
+
raise EventException(error, self._event)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class RegisterReAuthForPubSub(EventListenerInterface):
|
|
346
|
+
def __init__(self):
|
|
347
|
+
self._connection = None
|
|
348
|
+
self._connection_pool = None
|
|
349
|
+
self._client_type = None
|
|
350
|
+
self._connection_lock = None
|
|
351
|
+
self._event = None
|
|
352
|
+
|
|
353
|
+
def listen(self, event: AfterPubSubConnectionInstantiationEvent):
|
|
354
|
+
if isinstance(
|
|
355
|
+
event.pubsub_connection.credential_provider, StreamingCredentialProvider
|
|
356
|
+
) and event.pubsub_connection.get_protocol() in [3, "3"]:
|
|
357
|
+
self._event = event
|
|
358
|
+
self._connection = event.pubsub_connection
|
|
359
|
+
self._connection_pool = event.connection_pool
|
|
360
|
+
self._client_type = event.client_type
|
|
361
|
+
self._connection_lock = event.connection_lock
|
|
362
|
+
|
|
363
|
+
if self._client_type == ClientType.SYNC:
|
|
364
|
+
self._connection.credential_provider.on_next(self._re_auth)
|
|
365
|
+
self._connection.credential_provider.on_error(self._raise_on_error)
|
|
366
|
+
else:
|
|
367
|
+
self._connection.credential_provider.on_next(self._re_auth_async)
|
|
368
|
+
self._connection.credential_provider.on_error(
|
|
369
|
+
self._raise_on_error_async
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
def _re_auth(self, token: TokenInterface):
|
|
373
|
+
with self._connection_lock:
|
|
374
|
+
self._connection.send_command(
|
|
375
|
+
"AUTH", token.try_get("oid"), token.get_value()
|
|
376
|
+
)
|
|
377
|
+
self._connection.read_response()
|
|
378
|
+
|
|
379
|
+
self._connection_pool.re_auth_callback(token)
|
|
380
|
+
|
|
381
|
+
async def _re_auth_async(self, token: TokenInterface):
|
|
382
|
+
async with self._connection_lock:
|
|
383
|
+
await self._connection.send_command(
|
|
384
|
+
"AUTH", token.try_get("oid"), token.get_value()
|
|
385
|
+
)
|
|
386
|
+
await self._connection.read_response()
|
|
387
|
+
|
|
388
|
+
await self._connection_pool.re_auth_callback(token)
|
|
389
|
+
|
|
390
|
+
def _raise_on_error(self, error: Exception):
|
|
391
|
+
raise EventException(error, self._event)
|
|
392
|
+
|
|
393
|
+
async def _raise_on_error_async(self, error: Exception):
|
|
394
|
+
raise EventException(error, self._event)
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
redis/__init__.py,sha256=WlARnwwst8oaEyjXV5XTcmSGyEKVCn3S9N1MrHyJ8U8,2015
|
|
2
2
|
redis/backoff.py,sha256=N2CZXkB3cdoHeMZ01r0zVry0bRKe8mk0ybi8hE7PvzU,3177
|
|
3
3
|
redis/cache.py,sha256=68rJDNogvNwgdgBel6zSX9QziL11qsKIMhmvQvHvznM,9549
|
|
4
|
-
redis/client.py,sha256=
|
|
5
|
-
redis/cluster.py,sha256=
|
|
6
|
-
redis/connection.py,sha256=
|
|
4
|
+
redis/client.py,sha256=MMDn5Qh6rcBx2sDFU4O_Jid5TdzhA3-91_sxzmOBWAM,61055
|
|
5
|
+
redis/cluster.py,sha256=4UBn9HoGjKGUZ-ILROSVw-4I3Kg_9YW8r0X4COKwPsI,95882
|
|
6
|
+
redis/connection.py,sha256=UXrGt2T_1ebCGnpTmIzafZRLiZyqMJi4LOsRFkaFVHU,64750
|
|
7
7
|
redis/crc.py,sha256=Z3kXFtkY2LdgefnQMud1xr4vG5UYvA9LCMqNMX1ywu4,729
|
|
8
|
-
redis/credentials.py,sha256=
|
|
8
|
+
redis/credentials.py,sha256=GOnO3-LSW34efHaIrUbS742Mw8l70mRzF6UrKiKZsMY,1828
|
|
9
|
+
redis/event.py,sha256=urOK241IdgmCQ3fq7GqXRstZ2vcXRV14bBBMdN3latk,12129
|
|
9
10
|
redis/exceptions.py,sha256=OmOGoS9EPInuTZPJT0BuDeIYuYrtRGEUT_Pu6NtEQNI,5211
|
|
10
11
|
redis/lock.py,sha256=3JOC3AmYJ10zbq0blOtV4uNwuEhw4K7xuJ6nM-qv5Ig,11976
|
|
11
12
|
redis/ocsp.py,sha256=4b1s43x-DJ859zRKtwGTIbNys_dyGv5YyOdWnOvigyM,11451
|
|
@@ -24,13 +25,18 @@ redis/_parsers/resp2.py,sha256=f22kH-_ZP2iNtOn6xOe65MSy_fJpu8OEn1u_hgeeojI,4813
|
|
|
24
25
|
redis/_parsers/resp3.py,sha256=jHtL1LYJegJ_LiNTsjzIvS-kZyNR58jZ_YV4cRfwuN0,11127
|
|
25
26
|
redis/_parsers/socket.py,sha256=CKD8QW_wFSNlIZzxlbNduaGpiv0I8wBcsGuAIojDfJg,5403
|
|
26
27
|
redis/asyncio/__init__.py,sha256=uoDD8XYVi0Kj6mcufYwLDUTQXmBRx7a0bhKF9stZr7I,1489
|
|
27
|
-
redis/asyncio/client.py,sha256=
|
|
28
|
-
redis/asyncio/cluster.py,sha256=
|
|
29
|
-
redis/asyncio/connection.py,sha256=
|
|
28
|
+
redis/asyncio/client.py,sha256=xxifh7JrWJkSPpbem1qVXV6sCvAQRlq4VCYrkj84yvQ,61176
|
|
29
|
+
redis/asyncio/cluster.py,sha256=c3dhOQjMUdXQO0WJCOn6-DTPxk-mbcgw52OpiSDrfG8,65243
|
|
30
|
+
redis/asyncio/connection.py,sha256=w4yYr2Pzx_8Q7uJbeEyqZrjrqBpXaEZFYHZC5Zuv5HA,47203
|
|
30
31
|
redis/asyncio/lock.py,sha256=lLasXEO2E1CskhX5ZZoaSGpmwZP1Q782R3HAUNG3wD4,11967
|
|
31
32
|
redis/asyncio/retry.py,sha256=SnPPOlo5gcyIFtkC4DY7HFvmDgUaILsJ3DeHioogdB8,2219
|
|
32
33
|
redis/asyncio/sentinel.py,sha256=QBpsrdlhZlFqENy_rK1IuasSicox55_xSvP_IywbhbQ,14293
|
|
33
34
|
redis/asyncio/utils.py,sha256=Yxc5YQumhLjtDDwCS4mgxI6yy2Z21AzLlFxVbxCohic,704
|
|
35
|
+
redis/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
+
redis/auth/err.py,sha256=WYkbuDIzwp1S-eAvsya6QMlO6g9QIXbzMITOsTWX0xk,694
|
|
37
|
+
redis/auth/idp.py,sha256=IMDIIb9q72vbIwtFN8vPdaAKZVTdh0HuC5uj5ufqmw4,631
|
|
38
|
+
redis/auth/token.py,sha256=DslJx_wN8yPcrmcF-Ui8E5emcamP6OUwi9PTGSvsXQw,3125
|
|
39
|
+
redis/auth/token_manager.py,sha256=ShBsYXiBZBJBOMB_Y-pXfLwEOAmc9s1okaCECinNZ7g,12018
|
|
34
40
|
redis/commands/__init__.py,sha256=cTUH-MGvaLYS0WuoytyqtN1wniw2A1KbkUXcpvOSY3I,576
|
|
35
41
|
redis/commands/cluster.py,sha256=BBHSyXfl3OETIJs4JC5DrcfzqgF2Kt4WMEcd0WMILOU,31598
|
|
36
42
|
redis/commands/core.py,sha256=YlCzD44YJnFzdEKIFDBloPh1ivgHKcFMZsxPzamE9JM,238528
|
|
@@ -69,8 +75,8 @@ redis/commands/timeseries/__init__.py,sha256=gkz6wshEzzQQryBOnrAqqQzttS-AHfXmuN_
|
|
|
69
75
|
redis/commands/timeseries/commands.py,sha256=8Z2BEyP23qTYCJR_e9zdG11yWmIDwGBMO2PJNLtK2BA,47147
|
|
70
76
|
redis/commands/timeseries/info.py,sha256=meZYdu7IV9KaUWMKZs9qW4vo3Q9MwhdY-EBtKQzls5o,3223
|
|
71
77
|
redis/commands/timeseries/utils.py,sha256=NLwSOS5Dz9N8dYQSzEyBIvrItOWwfQ0xgDj8un6x3dU,1319
|
|
72
|
-
redis-5.
|
|
73
|
-
redis-5.
|
|
74
|
-
redis-5.
|
|
75
|
-
redis-5.
|
|
76
|
-
redis-5.
|
|
78
|
+
redis-5.3.0b3.dist-info/LICENSE,sha256=pXslClvwPXr-VbdAYzE_Ktt7ANVGwKsUmok5gzP-PMg,1074
|
|
79
|
+
redis-5.3.0b3.dist-info/METADATA,sha256=-wR2WJlqo5dVm6xSA2HiBdbI5Sawtc5hwKdce1OhOms,9140
|
|
80
|
+
redis-5.3.0b3.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
81
|
+
redis-5.3.0b3.dist-info/top_level.txt,sha256=OMAefszlde6ZoOtlM35AWzpRIrwtcqAMHGlRit-w2-4,6
|
|
82
|
+
redis-5.3.0b3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|