2022-01-01 13:38:12 +00:00
|
|
|
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
|
2021-06-30 08:24:58 +00:00
|
|
|
|
|
|
|
class Sessions::Store::Redis
|
|
|
|
SESSIONS_KEY = 'sessions'.freeze
|
|
|
|
MESSAGES_KEY = 'messages'.freeze
|
|
|
|
SPOOL_KEY = 'spool'.freeze
|
|
|
|
NODES_KEY = 'nodes'.freeze
|
|
|
|
|
|
|
|
def initialize
|
|
|
|
# Only load redis if it is really used.
|
|
|
|
require 'redis'
|
2021-06-30 12:04:59 +00:00
|
|
|
require 'hiredis'
|
2021-07-16 13:38:01 +00:00
|
|
|
@redis = Redis.new(driver: :hiredis)
|
2021-06-30 08:24:58 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def create(client_id, data)
|
|
|
|
@redis.set client_session_key(client_id), data
|
|
|
|
@redis.sadd SESSIONS_KEY, client_id
|
|
|
|
end
|
|
|
|
|
|
|
|
def sessions
|
|
|
|
@redis.smembers SESSIONS_KEY
|
|
|
|
end
|
|
|
|
|
|
|
|
def session_exists?(client_id)
|
|
|
|
@redis.sismember SESSIONS_KEY, client_id
|
|
|
|
end
|
|
|
|
|
|
|
|
def destroy(client_id)
|
|
|
|
@redis.srem SESSIONS_KEY, client_id
|
|
|
|
@redis.del client_session_key(client_id)
|
|
|
|
@redis.del client_messages_key(client_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
def set(client_id, data)
|
|
|
|
@redis.set client_session_key(client_id), data.to_json
|
|
|
|
end
|
|
|
|
|
|
|
|
def get(client_id)
|
|
|
|
data = nil
|
|
|
|
|
|
|
|
# if only session is missing, then it's an error behavior
|
|
|
|
session = @redis.get client_session_key(client_id)
|
|
|
|
if !session
|
|
|
|
destroy(client_id)
|
|
|
|
Sessions.log('error', "missing session value for '#{client_id}', removing session.")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
data_json = JSON.parse(session)
|
|
|
|
if data_json
|
|
|
|
data = Sessions.symbolize_keys(data_json)
|
|
|
|
data[:user] = data_json['user'] # for compat. reasons
|
|
|
|
end
|
|
|
|
|
|
|
|
data
|
|
|
|
end
|
|
|
|
|
|
|
|
def send_data(client_id, data)
|
|
|
|
@redis.rpush(client_messages_key(client_id), data.to_json).positive?
|
|
|
|
end
|
|
|
|
|
|
|
|
def queue(client_id)
|
|
|
|
data = []
|
|
|
|
while (item = @redis.lpop(client_messages_key(client_id)))
|
|
|
|
data.push JSON.parse(item)
|
|
|
|
end
|
|
|
|
data
|
|
|
|
end
|
|
|
|
|
|
|
|
def cleanup
|
|
|
|
clear_spool
|
|
|
|
clear_sessions
|
|
|
|
clear_messages
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def add_to_spool(data)
|
|
|
|
@redis.rpush SPOOL_KEY, data.to_json
|
|
|
|
end
|
|
|
|
|
2021-07-16 09:16:04 +00:00
|
|
|
def each_spool()
|
|
|
|
@redis.lrange(SPOOL_KEY, 0, -1).each do |message|
|
|
|
|
yield message, nil
|
|
|
|
end
|
2021-06-30 08:24:58 +00:00
|
|
|
end
|
|
|
|
|
2021-07-16 09:16:04 +00:00
|
|
|
def remove_from_spool(message, _entry)
|
2021-06-30 08:24:58 +00:00
|
|
|
@redis.lrem SPOOL_KEY, 1, message
|
|
|
|
end
|
|
|
|
|
|
|
|
def clear_spool
|
|
|
|
@redis.del SPOOL_KEY
|
|
|
|
end
|
|
|
|
|
|
|
|
def clear_sessions
|
|
|
|
@redis.keys("#{SESSIONS_KEY}/*").each do |key|
|
|
|
|
@redis.del key
|
|
|
|
end
|
|
|
|
@redis.del SESSIONS_KEY
|
|
|
|
end
|
|
|
|
|
|
|
|
def clear_messages
|
|
|
|
@redis.keys("#{MESSAGES_KEY}/*").each do |key|
|
|
|
|
@redis.del key
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
### Node-specific methods ###
|
|
|
|
|
|
|
|
def clear_nodes
|
|
|
|
@redis.keys("#{NODES_KEY}/*").each do |key|
|
|
|
|
@redis.del key
|
|
|
|
end
|
|
|
|
@redis.del NODES_KEY
|
|
|
|
end
|
|
|
|
|
|
|
|
def nodes
|
|
|
|
nodes = []
|
|
|
|
@redis.smembers(NODES_KEY).each do |node_id|
|
|
|
|
content = @redis.get(node_key(node_id))
|
|
|
|
if content
|
|
|
|
data = JSON.parse(content)
|
|
|
|
nodes.push data
|
|
|
|
end
|
|
|
|
end
|
|
|
|
nodes
|
|
|
|
end
|
|
|
|
|
|
|
|
def add_node(node_id, data)
|
|
|
|
@redis.set node_key(node_id), data.to_json
|
|
|
|
@redis.sadd NODES_KEY, node_id
|
|
|
|
end
|
|
|
|
|
|
|
|
def each_node_session(&block)
|
|
|
|
@redis.smembers(NODES_KEY).each do |node_id|
|
|
|
|
each_session_by_node(node_id, &block)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def create_node_session(node_id, client_id, data)
|
|
|
|
@redis.set node_client_session_key(node_id, client_id), data.to_json
|
|
|
|
@redis.sadd node_sessions_key(node_id), client_id
|
|
|
|
end
|
|
|
|
|
|
|
|
def each_session_by_node(node_id)
|
|
|
|
@redis.smembers(node_sessions_key(node_id)).each do |client_id|
|
|
|
|
content = @redis.get(node_client_session_key(node_id, client_id))
|
|
|
|
if content
|
|
|
|
data = JSON.parse(content)
|
|
|
|
yield data
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
protected
|
|
|
|
|
|
|
|
def client_session_key(client_id)
|
|
|
|
"#{SESSIONS_KEY}/#{client_id}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def client_messages_key(client_id)
|
|
|
|
"#{MESSAGES_KEY}/#{client_id}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def node_key(node_id)
|
|
|
|
"#{NODES_KEY}/#{node_id}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def node_sessions_key(node_id)
|
|
|
|
"#{node_key(node_id)}/sessions"
|
|
|
|
end
|
|
|
|
|
|
|
|
def node_client_session_key(node_id, client_id)
|
|
|
|
"#{node_sessions_key(node_id)}/#{client_id}"
|
|
|
|
end
|
|
|
|
end
|