diff options
author | laixintao <laixintaoo@gmail.com> | 2020-08-28 09:36:33 +0800 |
---|---|---|
committer | laixintao <laixintaoo@gmail.com> | 2020-08-28 09:36:33 +0800 |
commit | f1161c6b5af87bad95e2c961a6385c4a88584984 (patch) | |
tree | b40f1e90e40467559e4d02790013743516cb99d8 | |
parent | 365091fad4d1d0cd90d76414aba5ea27bc2d27f8 (diff) |
feature: support reissue for auth-required node.
-rw-r--r-- | iredis/client.py | 45 | ||||
-rw-r--r-- | iredis/entry.py | 67 | ||||
-rw-r--r-- | iredis/utils.py | 67 |
3 files changed, 98 insertions, 81 deletions
diff --git a/iredis/client.py b/iredis/client.py index 1120709..d831d24 100644 --- a/iredis/client.py +++ b/iredis/client.py @@ -40,6 +40,7 @@ from .utils import ( nativestr, exit, convert_formatted_text_to_bytes, + parse_url, ) from .warning import confirm_dangerous_command @@ -71,13 +72,7 @@ class Client: self.scheme = scheme self.connection = self.create_connection( - host, - port, - db, - password, - path, - scheme, - username, + host, port, db, password, path, scheme, username, ) # all command upper case @@ -252,17 +247,37 @@ class Client: This feature is not supported for unix socket connection. """ - # TODO read dsn for password username # Redis Cluster only supports database zero. _, slot, ip_port = response.split(" ") ip, port = ip_port.split(":") - print( - response, - file=sys.stderr, - ) - logger.info(f"redirect response type: {type(response)}") - # create a new connection for redirection - connection = self.create_connection(ip, port) + port = int(port) + + print(response, file=sys.stderr) + + # if user sets dsn for dest node + # use username and password from dsn settings + for dsn_name, dsn_url in config.alias_dsn.items(): + dsn = parse_url(dsn_url) + if dsn.host == ip and dsn.port == port: + print( + f"Connect {ip}:{port} via dns settings of {dsn_name}", + file=sys.stderr, + ) + connection = self.create_connection( + dsn.host, + dsn.port, + dsn.db, + dsn.password, + dsn.path, + dsn.scheme, + dsn.username, + ) + break + else: + # create a new connection for redirection + connection = self.create_connection(ip, port) + + connection.connect() return self.execute_by_connection(connection, *args, **kwargs) def render_response(self, response, command_name): diff --git a/iredis/entry.py b/iredis/entry.py index a099eef..8e396a4 100644 --- a/iredis/entry.py +++ b/iredis/entry.py @@ -4,8 +4,6 @@ import logging import sys import time from pathlib import Path -from collections import namedtuple -from urllib.parse import parse_qs, unquote, urlparse import platform import click @@ -24,13 +22,12 @@ from .style import STYLE from .config import config, load_config_files from .processors import UserInputCommand, UpdateBottomProcessor, PasswordProcessor from .bottom import BottomToolbar -from .utils import timer, exit, convert_formatted_text_to_bytes +from .utils import timer, exit, convert_formatted_text_to_bytes, parse_url from .completers import IRedisCompleter from .lexer import IRedisLexer from . import __version__ logger = logging.getLogger(__name__) -DSN = namedtuple("DSN", "scheme host port path db username password") class SkipAuthFileHistory(FileHistory): @@ -220,68 +217,6 @@ def repl(client, session, start_time): print("(error)", str(e)) -def parse_url(url, db=0): - """ - Return a Redis client object configured from the given URL - - For example:: - - redis://[[username]:[password]]@localhost:6379/0 - rediss://[[username]:[password]]@localhost:6379/0 - unix://[[username]:[password]]@/path/to/socket.sock?db=0 - - Three URL schemes are supported: - - - ```redis://`` - <http://www.iana.org/assignments/uri-schemes/prov/redis>`_ creates a - normal TCP socket connection - - ```rediss://`` - <http://www.iana.org/assignments/uri-schemes/prov/rediss>`_ creates a - SSL wrapped TCP socket connection - - ``unix://`` creates a Unix Domain Socket connection - - There are several ways to specify a database number. The parse function - will return the first specified option: - 1. A ``db`` querystring option, e.g. redis://localhost?db=0 - 2. If using the redis:// scheme, the path argument of the url, e.g. - redis://localhost/0 - 3. The ``db`` argument to this function. - - If none of these options are specified, db=0 is used. - """ - url = urlparse(url) - - scheme = url.scheme - path = unquote(url.path) if url.path else None - # We only support redis://, rediss:// and unix:// schemes. - # if scheme is ``unix``, read ``db`` from query string - # otherwise read ``db`` from path - if url.scheme == "unix": - qs = parse_qs(url.query) - if "db" in qs: - db = int(qs["db"][0] or db) - elif url.scheme in ("redis", "rediss"): - scheme = url.scheme - if path: - try: - db = int(path.replace("/", "")) - path = None - except (AttributeError, ValueError): - pass - else: - valid_schemes = ", ".join(("redis://", "rediss://", "unix://")) - raise ValueError( - "Redis URL must specify one of the following" "schemes (%s)" % valid_schemes - ) - - username = unquote(url.username) if url.username else None - password = unquote(url.password) if url.password else None - hostname = unquote(url.hostname) if url.hostname else None - port = url.port - - return DSN(scheme, hostname, port, path, db, username, password) - - RAW_HELP = """ Use raw formatting for replies (default when STDOUT is not a tty). \ However, you can use --no-raw to force formatted output even \ diff --git a/iredis/utils.py b/iredis/utils.py index cf2509b..b11097d 100644 --- a/iredis/utils.py +++ b/iredis/utils.py @@ -2,6 +2,8 @@ import re import sys import time import logging +from collections import namedtuple +from urllib.parse import parse_qs, unquote, urlparse from prompt_toolkit.formatted_text import FormattedText @@ -254,3 +256,68 @@ def exit(): def convert_formatted_text_to_bytes(formatted_text): to_render = [text for style, text in formatted_text] return "".join(to_render).encode() + + +DSN = namedtuple("DSN", "scheme host port path db username password") + + +def parse_url(url, db=0): + """ + Return a Redis client object configured from the given URL + + For example:: + + redis://[[username]:[password]]@localhost:6379/0 + rediss://[[username]:[password]]@localhost:6379/0 + unix://[[username]:[password]]@/path/to/socket.sock?db=0 + + Three URL schemes are supported: + + - ```redis://`` + <http://www.iana.org/assignments/uri-schemes/prov/redis>`_ creates a + normal TCP socket connection + - ```rediss://`` + <http://www.iana.org/assignments/uri-schemes/prov/rediss>`_ creates a + SSL wrapped TCP socket connection + - ``unix://`` creates a Unix Domain Socket connection + + There are several ways to specify a database number. The parse function + will return the first specified option: + 1. A ``db`` querystring option, e.g. redis://localhost?db=0 + 2. If using the redis:// scheme, the path argument of the url, e.g. + redis://localhost/0 + 3. The ``db`` argument to this function. + + If none of these options are specified, db=0 is used. + """ + url = urlparse(url) + + scheme = url.scheme + path = unquote(url.path) if url.path else None + # We only support redis://, rediss:// and unix:// schemes. + # if scheme is ``unix``, read ``db`` from query string + # otherwise read ``db`` from path + if url.scheme == "unix": + qs = parse_qs(url.query) + if "db" in qs: + db = int(qs["db"][0] or db) + elif url.scheme in ("redis", "rediss"): + scheme = url.scheme + if path: + try: + db = int(path.replace("/", "")) + path = None + except (AttributeError, ValueError): + pass + else: + valid_schemes = ", ".join(("redis://", "rediss://", "unix://")) + raise ValueError( + "Redis URL must specify one of the following" "schemes (%s)" % valid_schemes + ) + + username = unquote(url.username) if url.username else None + password = unquote(url.password) if url.password else None + hostname = unquote(url.hostname) if url.hostname else None + port = url.port + + return DSN(scheme, hostname, port, path, db, username, password) |