summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlaixintao <laixintaoo@gmail.com>2020-08-28 09:36:33 +0800
committerlaixintao <laixintaoo@gmail.com>2020-08-28 09:36:33 +0800
commitf1161c6b5af87bad95e2c961a6385c4a88584984 (patch)
treeb40f1e90e40467559e4d02790013743516cb99d8
parent365091fad4d1d0cd90d76414aba5ea27bc2d27f8 (diff)
feature: support reissue for auth-required node.
-rw-r--r--iredis/client.py45
-rw-r--r--iredis/entry.py67
-rw-r--r--iredis/utils.py67
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)