Module: Redis::LibIdentity
- Defined in:
- lib/redis/lib_identity.rb
Overview
Reports redis-rb as the connecting library via CLIENT SETINFO.
redis-client builds its own LIB-NAME as redis-client(<driver_info>) and always
reports its own version as LIB-VER, which would identify redis-client rather than
redis-rb to the server. We append a second pair of CLIENT SETINFO commands, which wins
because the command is last-write-wins, so that CLIENT LIST / CLIENT INFO report
lib-name=redis-rb and lib-ver=<Redis::VERSION>.
Libraries built on top of redis-rb can still identify themselves by passing driver_info,
in which case they are reported inside the parentheses, e.g. lib-name=redis-rb(my-gem_v1.0.0).
The official convention for such suffixes is <name>_v<version> (matching
(?<custom-name>[ -~]+)[ -~]v(?<custom-version>[\d\.]+)), with ; delimiting multiple
suffixes and parentheses avoided inside them — see
https://redis.io/docs/latest/commands/client-setinfo/. Passing driver_info: false disables
CLIENT SETINFO entirely, for peers that can't tolerate unknown commands during the handshake
(e.g. some proxies).
Applications that use redis-client directly are left untouched: the override only applies
to configurations whose driver_info was built by this module.
Constant Summary collapse
- MARKER =
Follows the official suffix convention, so that the transient pair
redis-clientitself builds from this value (lib-name=redis-client(redis-rb_v<version>)) is well-formed too. "redis-rb_v"- LIB_NAME =
"redis-rb"- SEPARATOR =
";"- OWN_INFO =
Interpolated strings are not frozen by the magic comment; explicit freezes keep these constants Ractor-shareable (lazy module ivars here would raise Ractor::IsolationError).
"#{MARKER}#{Redis::VERSION}".freeze
- OWN_PREFIX =
"#{OWN_INFO}#{SEPARATOR}".freeze
- INVALID_CHARS =
CLIENT SETINFOvalues must be printable ASCII with no spaces — the server rejects anything else, andredis-clientswallows that error, which would silently leavelib-nameempty. Parentheses are excluded as well: they delimit the suffix inlib-name=redis-rb(<suffix>), so a suffix containing them would corrupt the reported name. /(?:[^!-~]|[()])+/
Class Method Summary collapse
-
.driver_info(downstream = nil) ⇒ Object
Combines redis-rb's own identity with the
driver_infoa downstream library passed in, so that both can be recovered when the connection prelude is built. -
.ours?(info) ⇒ Boolean
True only for values
driver_infoproduced: exactly our own identity, or our identity followed by a downstream library's. - .setinfo_commands(info) ⇒ Object
Instance Method Summary collapse
Class Method Details
.driver_info(downstream = nil) ⇒ Object
Combines redis-rb's own identity with the driver_info a downstream library passed in,
so that both can be recovered when the connection prelude is built. false is passed
through untouched and, being falsy, turns CLIENT SETINFO off wholesale (redis-client
gates its own commands on driver_info too). Any other non-String, non-Array value is
also passed through, leaving redis-client to reject it.
48 49 50 51 52 53 54 55 |
# File 'lib/redis/lib_identity.rb', line 48 def driver_info(downstream = nil) case downstream when nil then OWN_INFO when String then combine(downstream) when Array then combine(downstream.join(SEPARATOR)) else downstream end end |
.ours?(info) ⇒ Boolean
True only for values driver_info produced: exactly our own identity, or our identity
followed by a downstream library's. Matching on the bare MARKER prefix instead would
also capture a direct redis-client user whose own driver_info merely starts with
redis-rb_v (say redis-rb_viewer-1.0) and would silently discard their identity.
61 62 63 |
# File 'lib/redis/lib_identity.rb', line 61 def ours?(info) info.is_a?(String) && (info == OWN_INFO || info.start_with?(OWN_PREFIX)) end |
Instance Method Details
#connection_prelude ⇒ Object
87 88 89 90 91 92 93 94 95 |
# File 'lib/redis/lib_identity.rb', line 87 def connection_prelude prelude = super info = driver_info return prelude unless LibIdentity.ours?(info) # `CLIENT SETINFO` is last-write-wins, so appending after the commands `redis-client` # already built overrides them, without having to recognise or remove them. (prelude + LibIdentity.setinfo_commands(info)).freeze end |