You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

151 lines
3.9 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import redis, frappe, re
  5. import cPickle as pickle
  6. from frappe.utils import cstr
  7. class RedisWrapper(redis.Redis):
  8. """Redis client that will automatically prefix conf.db_name"""
  9. def make_key(self, key, user=None):
  10. if user:
  11. if user == True:
  12. user = frappe.session.user
  13. key = "user:{0}:{1}".format(user, key)
  14. return "{0}|{1}".format(frappe.conf.db_name, key).encode('utf-8')
  15. def set_value(self, key, val, user=None):
  16. """Sets cache value."""
  17. key = self.make_key(key, user)
  18. frappe.local.cache[key] = val
  19. try:
  20. self.set(key, pickle.dumps(val))
  21. except redis.exceptions.ConnectionError:
  22. return None
  23. def get_value(self, key, generator=None, user=None):
  24. """Returns cache value. If not found and generator function is
  25. given, it will call the generator.
  26. :param key: Cache key.
  27. :param generator: Function to be called to generate a value if `None` is returned."""
  28. original_key = key
  29. key = self.make_key(key, user)
  30. if key not in frappe.local.cache:
  31. val = None
  32. try:
  33. val = self.get(key)
  34. except redis.exceptions.ConnectionError:
  35. pass
  36. if val is not None:
  37. val = pickle.loads(val)
  38. if val is None and generator:
  39. val = generator()
  40. self.set_value(original_key, val, user=user)
  41. else:
  42. frappe.local.cache[key] = val
  43. return frappe.local.cache.get(key)
  44. def get_all(self, key):
  45. ret = {}
  46. for k in self.get_keys(key):
  47. ret[key] = self.get_value(k)
  48. return ret
  49. def get_keys(self, key):
  50. """Return keys starting with `key`."""
  51. try:
  52. key = self.make_key(key + "*")
  53. return self.keys(key)
  54. except redis.exceptions.ConnectionError:
  55. regex = re.compile(cstr(key).replace("|", "\|").replace("*", "[\w]*"))
  56. return [k for k in frappe.local.cache.keys() if regex.match(k)]
  57. def delete_keys(self, key):
  58. """Delete keys with wildcard `*`."""
  59. try:
  60. self.delete_value(self.get_keys(key), make_keys=False)
  61. except redis.exceptions.ConnectionError:
  62. pass
  63. def delete_key(self, *args, **kwargs):
  64. self.delete_value(*args, **kwargs)
  65. def delete_value(self, keys, user=None, make_keys=True):
  66. """Delete value, list of values."""
  67. if not isinstance(keys, (list, tuple)):
  68. keys = (keys, )
  69. for key in keys:
  70. if make_keys:
  71. key = self.make_key(key)
  72. try:
  73. self.delete(key)
  74. except redis.exceptions.ConnectionError:
  75. pass
  76. if key in frappe.local.cache:
  77. del frappe.local.cache[key]
  78. def hset(self, name, key, value):
  79. if not name in frappe.local.cache:
  80. frappe.local.cache[name] = {}
  81. frappe.local.cache[name][key] = value
  82. try:
  83. super(redis.Redis, self).hset(self.make_key(name), key, pickle.dumps(value))
  84. except redis.exceptions.ConnectionError:
  85. pass
  86. def hget(self, name, key, generator=None):
  87. if not name in frappe.local.cache:
  88. frappe.local.cache[name] = {}
  89. if key in frappe.local.cache[name]:
  90. return frappe.local.cache[name][key]
  91. value = None
  92. try:
  93. value = super(redis.Redis, self).hget(self.make_key(name), key)
  94. except redis.exceptions.ConnectionError:
  95. pass
  96. if value:
  97. value = pickle.loads(value)
  98. frappe.local.cache[name][key] = value
  99. elif generator:
  100. value = generator()
  101. try:
  102. self.hset(name, key, value)
  103. except redis.exceptions.ConnectionError:
  104. pass
  105. return value
  106. def hdel(self, name, key):
  107. if name in frappe.local.cache:
  108. if key in frappe.local.cache[name]:
  109. del frappe.local.cache[name][key]
  110. try:
  111. super(redis.Redis, self).hdel(self.make_key(name), key)
  112. except redis.exceptions.ConnectionError:
  113. pass
  114. def hdel_keys(self, name_starts_with, key):
  115. """Delete hash names with wildcard `*` and key"""
  116. for name in frappe.cache().get_keys(name_starts_with):
  117. name = name.split("|", 1)[1]
  118. self.hdel(name, key)
  119. def hkeys(self, name):
  120. try:
  121. return super(redis.Redis, self).hkeys(self.make_key(name))
  122. except redis.exceptions.ConnectionError:
  123. return []