Class: Tina4::SessionHandlers::RespClient
- Inherits:
-
Object
- Object
- Tina4::SessionHandlers::RespClient
- Defined in:
- lib/tina4/session_handlers/resp_client.rb
Overview
Zero-dependency synchronous RESP client over a TCP socket. Used by the Redis and Valkey session handlers as the fallback when the optional ‘redis` gem is not installed, so a Tina4 app talks to Redis/Valkey for sessions with NO third-party gem. Parity with the Python (redis-py + raw RESP) and Node (redis npm + raw respClient) session handlers, and with the framework’s own cache backends, which already speak raw RESP this way.
One short-lived connection per command (open -> AUTH? -> SELECT? -> command -> close), matching the cache backends. Ruby’s blocking sockets make the reply reader straightforward: read the header line up to CRLF, then read the bulk body by its exact byte count (so a large session value spanning several TCP segments is read in full, not truncated to one recv()).
Instance Method Summary collapse
-
#command(*args) ⇒ Object
Send one RESP command and return its reply: a String for a simple/bulk string or integer, an Array for a multi-bulk reply, or nil for a nil bulk ($-1) / miss.
- #del(key) ⇒ Object
- #get(key) ⇒ Object
-
#initialize(host:, port:, password: nil, db: 0, timeout: 5) ⇒ RespClient
constructor
A new instance of RespClient.
- #set(key, value) ⇒ Object
- #setex(key, ttl, value) ⇒ Object
Constructor Details
#initialize(host:, port:, password: nil, db: 0, timeout: 5) ⇒ RespClient
Returns a new instance of RespClient.
24 25 26 27 28 29 30 |
# File 'lib/tina4/session_handlers/resp_client.rb', line 24 def initialize(host:, port:, password: nil, db: 0, timeout: 5) @host = host @port = port @password = password @db = (db || 0).to_i @timeout = timeout end |
Instance Method Details
#command(*args) ⇒ Object
Send one RESP command and return its reply: a String for a simple/bulk string or integer, an Array for a multi-bulk reply, or nil for a nil bulk ($-1) / miss. A transport failure (server unreachable, rejected AUTH or SELECT, timeout, connection closed mid-reply) RAISES so the Session boundary can log-loud + degrade (a real op never silently no-ops).
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/tina4/session_handlers/resp_client.rb', line 53 def command(*args) sock = Socket.tcp(@host, @port, connect_timeout: @timeout) sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, [@timeout, 0].pack("l_2")) begin if @password && !@password.empty? write_command(sock, "AUTH", @password) reply = read_reply(sock) raise RespError, "AUTH rejected: #{reply.}" if reply.is_a?(RespError) end if @db != 0 write_command(sock, "SELECT", @db.to_s) reply = read_reply(sock) raise RespError, "SELECT rejected: #{reply.}" if reply.is_a?(RespError) end write_command(sock, *args) reply = read_reply(sock) raise reply if reply.is_a?(RespError) reply ensure begin sock.close rescue StandardError # already closed / never opened — nothing to do end end end |
#del(key) ⇒ Object
44 45 46 |
# File 'lib/tina4/session_handlers/resp_client.rb', line 44 def del(key) command("DEL", key) end |
#get(key) ⇒ Object
32 33 34 |
# File 'lib/tina4/session_handlers/resp_client.rb', line 32 def get(key) command("GET", key) end |
#set(key, value) ⇒ Object
36 37 38 |
# File 'lib/tina4/session_handlers/resp_client.rb', line 36 def set(key, value) command("SET", key, value) end |
#setex(key, ttl, value) ⇒ Object
40 41 42 |
# File 'lib/tina4/session_handlers/resp_client.rb', line 40 def setex(key, ttl, value) command("SETEX", key, ttl.to_s, value) end |