redis.rb 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. class Sessions::Store::Redis
  3. SESSIONS_KEY = 'sessions'.freeze
  4. MESSAGES_KEY = 'messages'.freeze
  5. SPOOL_KEY = 'spool'.freeze
  6. NODES_KEY = 'nodes'.freeze
  7. def initialize
  8. # Only load redis if it is really used.
  9. require 'redis'
  10. require 'hiredis'
  11. @redis = Redis.new(driver: :hiredis)
  12. end
  13. def create(client_id, data)
  14. @redis.set client_session_key(client_id), data
  15. @redis.sadd? SESSIONS_KEY, client_id
  16. end
  17. def sessions
  18. @redis.smembers SESSIONS_KEY
  19. end
  20. def session_exists?(client_id)
  21. @redis.sismember SESSIONS_KEY, client_id
  22. end
  23. def destroy(client_id)
  24. @redis.srem? SESSIONS_KEY, client_id
  25. @redis.del client_session_key(client_id)
  26. @redis.del client_messages_key(client_id)
  27. end
  28. def set(client_id, data)
  29. @redis.set client_session_key(client_id), data.to_json
  30. end
  31. def get(client_id)
  32. data = nil
  33. # if only session is missing, then it's an error behavior
  34. session = @redis.get client_session_key(client_id)
  35. if !session
  36. destroy(client_id)
  37. Sessions.log('error', "missing session value for '#{client_id}', removing session.")
  38. return
  39. end
  40. data_json = JSON.parse(session)
  41. if data_json
  42. data = Sessions.symbolize_keys(data_json)
  43. data[:user] = data_json['user'] # for compat. reasons
  44. end
  45. data
  46. end
  47. def send_data(client_id, data)
  48. key = client_messages_key(client_id)
  49. key_is_new = !@redis.exists?(key)
  50. @redis.rpush(key, data.to_json).positive?.tap do
  51. # Make sure message keys are cleaned up even if they are no longer listed in 'sessions'.
  52. @redis.expire(key, 1.hour) if key_is_new
  53. end
  54. end
  55. def queue(client_id)
  56. data = []
  57. while (item = @redis.lpop(client_messages_key(client_id)))
  58. data.push JSON.parse(item)
  59. end
  60. data
  61. end
  62. def cleanup
  63. clear_spool
  64. clear_sessions
  65. clear_messages
  66. true
  67. end
  68. def add_to_spool(data)
  69. @redis.rpush SPOOL_KEY, data.to_json
  70. end
  71. def each_spool()
  72. @redis.lrange(SPOOL_KEY, 0, -1).each do |message|
  73. yield message, nil
  74. end
  75. end
  76. def remove_from_spool(message, _entry)
  77. @redis.lrem SPOOL_KEY, 1, message
  78. end
  79. def clear_spool
  80. @redis.del SPOOL_KEY
  81. end
  82. def clear_sessions
  83. @redis.keys("#{SESSIONS_KEY}/*").each do |key|
  84. @redis.del key
  85. end
  86. @redis.del SESSIONS_KEY
  87. end
  88. def clear_messages
  89. @redis.keys("#{MESSAGES_KEY}/*").each do |key|
  90. @redis.del key
  91. end
  92. end
  93. ### Node-specific methods ###
  94. def clear_nodes
  95. @redis.keys("#{NODES_KEY}/*").each do |key|
  96. @redis.del key
  97. end
  98. @redis.del NODES_KEY
  99. end
  100. def nodes
  101. nodes = []
  102. @redis.smembers(NODES_KEY).each do |node_id|
  103. content = @redis.get(node_key(node_id))
  104. if content
  105. data = JSON.parse(content)
  106. nodes.push data
  107. end
  108. end
  109. nodes
  110. end
  111. def add_node(node_id, data)
  112. @redis.set node_key(node_id), data.to_json
  113. @redis.sadd? NODES_KEY, node_id
  114. end
  115. def each_node_session(&)
  116. @redis.smembers(NODES_KEY).each do |node_id|
  117. each_session_by_node(node_id, &)
  118. end
  119. end
  120. def create_node_session(node_id, client_id, data)
  121. @redis.set node_client_session_key(node_id, client_id), data.to_json
  122. @redis.sadd? node_sessions_key(node_id), client_id
  123. end
  124. def each_session_by_node(node_id)
  125. @redis.smembers(node_sessions_key(node_id)).each do |client_id|
  126. content = @redis.get(node_client_session_key(node_id, client_id))
  127. if content
  128. data = JSON.parse(content)
  129. yield data
  130. end
  131. end
  132. end
  133. protected
  134. def client_session_key(client_id)
  135. "#{SESSIONS_KEY}/#{client_id}"
  136. end
  137. def client_messages_key(client_id)
  138. "#{MESSAGES_KEY}/#{client_id}"
  139. end
  140. def node_key(node_id)
  141. "#{NODES_KEY}/#{node_id}"
  142. end
  143. def node_sessions_key(node_id)
  144. "#{node_key(node_id)}/sessions"
  145. end
  146. def node_client_session_key(node_id, client_id)
  147. "#{node_sessions_key(node_id)}/#{client_id}"
  148. end
  149. end