Class: Async::Redis::Endpoint
- Inherits:
-
IO::Endpoint::Generic
- Object
- IO::Endpoint::Generic
- Async::Redis::Endpoint
- Defined in:
- lib/async/redis/endpoint.rb
Overview
Represents a way to connect to a remote Redis server.
Constant Summary collapse
- LOCALHOST =
URI::Generic.build(scheme: "redis", host: "localhost").freeze
- SCHEMES =
{ "redis" => URI::Generic, "rediss" => URI::Generic, }
Instance Attribute Summary collapse
-
#url ⇒ Object
readonly
Returns the value of attribute url.
Class Method Summary collapse
-
.[](object) ⇒ Object
Coerce the given object into an endpoint.
-
.for(scheme, host, port: nil, database: nil, **options) ⇒ Object
Construct an endpoint with a specified scheme, hostname, optional path, and options.
-
.local(**options) ⇒ Object
Create a local Redis endpoint.
-
.parse(string, endpoint = nil, **options) ⇒ Object
Parse a Redis URL string into an endpoint.
-
.remote(host, port = 6379, **options) ⇒ Object
Create a remote Redis endpoint.
-
.unix(path, **options) ⇒ Object
Create a local Redis endpoint from a UNIX socket path.
Instance Method Summary collapse
-
#address ⇒ Object
Get the address of the underlying endpoint.
-
#bind(*arguments, &block) ⇒ Object
Bind to the endpoint and yield the server socket.
-
#build_endpoint(endpoint = nil) ⇒ Object
Build the underlying endpoint with optional SSL wrapping.
-
#connect(&block) ⇒ Object
Connect to the endpoint and yield the client socket.
-
#credentials ⇒ Object
Get the credentials for authentication.
-
#database ⇒ Object
Get the database number for this endpoint.
-
#default_port ⇒ Object
Get the default port for Redis connections.
-
#default_port? ⇒ Boolean
Check if the endpoint is using the default port.
-
#each ⇒ Object
Iterate over each possible endpoint variation.
-
#endpoint ⇒ Object
Get the underlying endpoint, building it if necessary.
-
#endpoint=(endpoint) ⇒ Object
Set the underlying endpoint.
-
#eql?(other) ⇒ Boolean
Check if this endpoint is equal to another.
-
#hash ⇒ Object
Get the hash code for this endpoint.
-
#hostname ⇒ Object
The hostname is the server we are connecting to:.
-
#initialize(url, endpoint = nil, **options) ⇒ Endpoint
constructor
Create a new endpoint.
-
#inspect ⇒ Object
Convert the endpoint to an inspectable string.
-
#key ⇒ Object
Get the key for hashing and equality comparison.
-
#localhost? ⇒ Boolean
Check if the endpoint is connecting to localhost.
-
#port ⇒ Object
Get the port for this endpoint.
-
#protocol ⇒ Object
Get the protocol for this endpoint.
-
#scheme ⇒ Object
Get the scheme for this endpoint.
-
#secure? ⇒ Boolean
Check if the connection is secure (using TLS).
-
#ssl_context ⇒ Object
Get the SSL context for secure connections.
-
#ssl_verify_mode ⇒ Object
We don't try to validate peer certificates when talking to localhost because they would always be self-signed.
-
#to_s ⇒ Object
Convert the endpoint to a string representation.
-
#to_url ⇒ Object
Convert the endpoint to a URL.
Constructor Details
#initialize(url, endpoint = nil, **options) ⇒ Endpoint
Create a new endpoint.
122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/async/redis/endpoint.rb', line 122 def initialize(url, endpoint = nil, **) super(**) raise ArgumentError, "URL must be absolute (include scheme, host): #{url}" unless url.absolute? @url = url if endpoint @endpoint = self.build_endpoint(endpoint) else @endpoint = nil end end |
Instance Attribute Details
#url ⇒ Object (readonly)
Returns the value of attribute url.
160 161 162 |
# File 'lib/async/redis/endpoint.rb', line 160 def url @url end |
Class Method Details
.[](object) ⇒ Object
Coerce the given object into an endpoint.
106 107 108 109 110 111 112 |
# File 'lib/async/redis/endpoint.rb', line 106 def self.[](object) if object.is_a?(self) return object else self.parse(object.to_s) end end |
.for(scheme, host, port: nil, database: nil, **options) ⇒ Object
Construct an endpoint with a specified scheme, hostname, optional path, and options. If no scheme is provided, it will be auto-detected based on SSL context.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/async/redis/endpoint.rb', line 77 def self.for(scheme, host, port: nil, database: nil, **) # Auto-detect scheme if not provided: if default_scheme = .delete(:scheme) scheme ||= default_scheme end scheme ||= [:ssl_context] ? "rediss" : "redis" uri_klass = SCHEMES.fetch(scheme.downcase) do raise ArgumentError, "Unsupported scheme: #{scheme.inspect}" end if database path = "/#{database}" end self.new( uri_klass.build( scheme: scheme, host: host, port: port, path: path, ), ** ) end |
.local(**options) ⇒ Object
Create a local Redis endpoint.
32 33 34 |
# File 'lib/async/redis/endpoint.rb', line 32 def self.local(**) self.new(LOCALHOST, **) end |
.parse(string, endpoint = nil, **options) ⇒ Object
Parse a Redis URL string into an endpoint.
65 66 67 68 69 |
# File 'lib/async/redis/endpoint.rb', line 65 def self.parse(string, endpoint = nil, **) url = URI.parse(string) return self.new(url, endpoint, **) end |
.remote(host, port = 6379, **options) ⇒ Object
Create a remote Redis endpoint.
41 42 43 44 |
# File 'lib/async/redis/endpoint.rb', line 41 def self.remote(host, port = 6379, **) # URI::Generic.build automatically handles IPv6 addresses correctly: self.new(URI::Generic.build(scheme: "redis", host: host, port: port), **) end |
.unix(path, **options) ⇒ Object
Create a local Redis endpoint from a UNIX socket path.
50 51 52 53 |
# File 'lib/async/redis/endpoint.rb', line 50 def self.unix(path, **) endpoint = ::IO::Endpoint.unix(path) self.new(URI::Generic.build(scheme: "redis", path:), endpoint, **) end |
Instance Method Details
#address ⇒ Object
Get the address of the underlying endpoint.
164 165 166 |
# File 'lib/async/redis/endpoint.rb', line 164 def address endpoint.address end |
#bind(*arguments, &block) ⇒ Object
Bind to the endpoint and yield the server socket.
305 306 307 |
# File 'lib/async/redis/endpoint.rb', line 305 def bind(*arguments, &block) endpoint.bind(*arguments, &block) end |
#build_endpoint(endpoint = nil) ⇒ Object
Build the underlying endpoint with optional SSL wrapping.
275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/async/redis/endpoint.rb', line 275 def build_endpoint(endpoint = nil) endpoint ||= make_endpoint if secure? # Wrap it in SSL: return ::IO::Endpoint::SSLEndpoint.new(endpoint, ssl_context: self.ssl_context, hostname: @url.hostname, timeout: self.timeout, ) end return endpoint end |
#connect(&block) ⇒ Object
Connect to the endpoint and yield the client socket.
311 312 313 |
# File 'lib/async/redis/endpoint.rb', line 311 def connect(&block) endpoint.connect(&block) end |
#credentials ⇒ Object
Get the credentials for authentication.
233 234 235 |
# File 'lib/async/redis/endpoint.rb', line 233 def credentials @options[:credentials] || extract_userinfo(@url.userinfo) end |
#database ⇒ Object
Get the database number for this endpoint.
221 222 223 |
# File 'lib/async/redis/endpoint.rb', line 221 def database @options[:database] || extract_database(@url.path) end |
#default_port ⇒ Object
Get the default port for Redis connections.
192 193 194 |
# File 'lib/async/redis/endpoint.rb', line 192 def default_port 6379 end |
#default_port? ⇒ Boolean
Check if the endpoint is using the default port.
198 199 200 |
# File 'lib/async/redis/endpoint.rb', line 198 def default_port? port == default_port end |
#each ⇒ Object
Iterate over each possible endpoint variation.
317 318 319 320 321 322 323 |
# File 'lib/async/redis/endpoint.rb', line 317 def each return to_enum unless block_given? self.tcp_endpoint.each do |endpoint| yield self.class.new(@url, endpoint, **@options) end end |
#endpoint ⇒ Object
Get the underlying endpoint, building it if necessary.
292 293 294 |
# File 'lib/async/redis/endpoint.rb', line 292 def endpoint @endpoint ||= build_endpoint end |
#endpoint=(endpoint) ⇒ Object
Set the underlying endpoint.
298 299 300 |
# File 'lib/async/redis/endpoint.rb', line 298 def endpoint=(endpoint) @endpoint = build_endpoint(endpoint) end |
#eql?(other) ⇒ Boolean
Check if this endpoint is equal to another.
334 335 336 |
# File 'lib/async/redis/endpoint.rb', line 334 def eql? other self.key.eql? other.key end |
#hash ⇒ Object
Get the hash code for this endpoint.
340 341 342 |
# File 'lib/async/redis/endpoint.rb', line 340 def hash self.key.hash end |
#hostname ⇒ Object
The hostname is the server we are connecting to:
209 210 211 |
# File 'lib/async/redis/endpoint.rb', line 209 def hostname @options[:hostname] || @url.hostname end |
#inspect ⇒ Object
Convert the endpoint to an inspectable string.
156 157 158 |
# File 'lib/async/redis/endpoint.rb', line 156 def inspect "\#<#{self.class} #{self.to_url} #{@options.inspect}>" end |
#key ⇒ Object
Get the key for hashing and equality comparison.
327 328 329 |
# File 'lib/async/redis/endpoint.rb', line 327 def key [@url, @options] end |
#localhost? ⇒ Boolean
Check if the endpoint is connecting to localhost.
249 250 251 |
# File 'lib/async/redis/endpoint.rb', line 249 def localhost? @url.hostname =~ /^(.*?\.)?localhost\.?$/ end |
#port ⇒ Object
Get the port for this endpoint.
204 205 206 |
# File 'lib/async/redis/endpoint.rb', line 204 def port @options[:port] || @url.port || default_port end |
#protocol ⇒ Object
Get the protocol for this endpoint.
176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/async/redis/endpoint.rb', line 176 def protocol protocol = @options.fetch(:protocol, Protocol::RESP2) if credentials = self.credentials protocol = Protocol::Authenticated.new(credentials, protocol) end if database = self.database protocol = Protocol::Selected.new(database, protocol) end return protocol end |
#scheme ⇒ Object
Get the scheme for this endpoint.
215 216 217 |
# File 'lib/async/redis/endpoint.rb', line 215 def scheme @options[:scheme] || @url.scheme end |
#secure? ⇒ Boolean
Check if the connection is secure (using TLS).
170 171 172 |
# File 'lib/async/redis/endpoint.rb', line 170 def secure? ["rediss"].include?(self.scheme) end |
#ssl_context ⇒ Object
Get the SSL context for secure connections.
264 265 266 267 268 269 270 |
# File 'lib/async/redis/endpoint.rb', line 264 def ssl_context @options[:ssl_context] || OpenSSL::SSL::SSLContext.new.tap do |context| context.set_params( verify_mode: self.ssl_verify_mode ) end end |
#ssl_verify_mode ⇒ Object
We don't try to validate peer certificates when talking to localhost because they would always be self-signed.
254 255 256 257 258 259 260 |
# File 'lib/async/redis/endpoint.rb', line 254 def ssl_verify_mode if self.localhost? OpenSSL::SSL::VERIFY_NONE else OpenSSL::SSL::VERIFY_PEER end end |
#to_s ⇒ Object
Convert the endpoint to a string representation.
150 151 152 |
# File 'lib/async/redis/endpoint.rb', line 150 def to_s "\#<#{self.class} #{self.to_url} #{@options}>" end |
#to_url ⇒ Object
Convert the endpoint to a URL.
138 139 140 141 142 143 144 145 146 |
# File 'lib/async/redis/endpoint.rb', line 138 def to_url url = @url.dup unless default_port? url.port = self.port end return url end |