您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

190 行
4.8 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, expires_in_sec=None):
  16. """Sets cache value.
  17. :param key: Cache key
  18. :param val: Value to be cached
  19. :param user: Prepends key with User
  20. :param expires_in_sec: Expire value of this key in X seconds
  21. """
  22. key = self.make_key(key, user)
  23. if not expires_in_sec:
  24. frappe.local.cache[key] = val
  25. try:
  26. if expires_in_sec:
  27. self.setex(key, pickle.dumps(val), expires_in_sec)
  28. else:
  29. self.set(key, pickle.dumps(val))
  30. except redis.exceptions.ConnectionError:
  31. return None
  32. def get_value(self, key, generator=None, user=None, expires=False):
  33. """Returns cache value. If not found and generator function is
  34. given, it will call the generator.
  35. :param key: Cache key.
  36. :param generator: Function to be called to generate a value if `None` is returned.
  37. :param expires: If the key is supposed to be with an expiry, don't store it in frappe.local
  38. """
  39. original_key = key
  40. key = self.make_key(key, user)
  41. if key in frappe.local.cache:
  42. val = frappe.local.cache[key]
  43. else:
  44. val = None
  45. try:
  46. val = self.get(key)
  47. except redis.exceptions.ConnectionError:
  48. pass
  49. if val is not None:
  50. val = pickle.loads(val)
  51. if not expires:
  52. if val is None and generator:
  53. val = generator()
  54. self.set_value(original_key, val, user=user)
  55. else:
  56. frappe.local.cache[key] = val
  57. return val
  58. def get_all(self, key):
  59. ret = {}
  60. for k in self.get_keys(key):
  61. ret[key] = self.get_value(k)
  62. return ret
  63. def get_keys(self, key):
  64. """Return keys starting with `key`."""
  65. try:
  66. key = self.make_key(key + "*")
  67. return self.keys(key)
  68. except redis.exceptions.ConnectionError:
  69. regex = re.compile(cstr(key).replace("|", "\|").replace("*", "[\w]*"))
  70. return [k for k in frappe.local.cache.keys() if regex.match(k)]
  71. def delete_keys(self, key):
  72. """Delete keys with wildcard `*`."""
  73. try:
  74. self.delete_value(self.get_keys(key), make_keys=False)
  75. except redis.exceptions.ConnectionError:
  76. pass
  77. def delete_key(self, *args, **kwargs):
  78. self.delete_value(*args, **kwargs)
  79. def delete_value(self, keys, user=None, make_keys=True):
  80. """Delete value, list of values."""
  81. if not isinstance(keys, (list, tuple)):
  82. keys = (keys, )
  83. for key in keys:
  84. if make_keys:
  85. key = self.make_key(key)
  86. try:
  87. self.delete(key)
  88. except redis.exceptions.ConnectionError:
  89. pass
  90. if key in frappe.local.cache:
  91. del frappe.local.cache[key]
  92. def lpush(self, key, value):
  93. super(redis.Redis, self).lpush(self.make_key(key), value)
  94. def rpush(self, key, value):
  95. super(redis.Redis, self).rpush(self.make_key(key), value)
  96. def lpop(self, key):
  97. return super(redis.Redis, self).lpop(self.make_key(key))
  98. def llen(self, key):
  99. return super(redis.Redis, self).llen(self.make_key(key))
  100. def hset(self, name, key, value):
  101. if not name in frappe.local.cache:
  102. frappe.local.cache[name] = {}
  103. frappe.local.cache[name][key] = value
  104. try:
  105. super(redis.Redis, self).hset(self.make_key(name), key, pickle.dumps(value))
  106. except redis.exceptions.ConnectionError:
  107. pass
  108. def hgetall(self, name):
  109. return {key: pickle.loads(value) for key, value in
  110. super(redis.Redis, self).hgetall(self.make_key(name)).iteritems()}
  111. def hget(self, name, key, generator=None):
  112. if not name in frappe.local.cache:
  113. frappe.local.cache[name] = {}
  114. if key in frappe.local.cache[name]:
  115. return frappe.local.cache[name][key]
  116. value = None
  117. try:
  118. value = super(redis.Redis, self).hget(self.make_key(name), key)
  119. except redis.exceptions.ConnectionError:
  120. pass
  121. if value:
  122. value = pickle.loads(value)
  123. frappe.local.cache[name][key] = value
  124. elif generator:
  125. value = generator()
  126. try:
  127. self.hset(name, key, value)
  128. except redis.exceptions.ConnectionError:
  129. pass
  130. return value
  131. def hdel(self, name, key):
  132. if name in frappe.local.cache:
  133. if key in frappe.local.cache[name]:
  134. del frappe.local.cache[name][key]
  135. try:
  136. super(redis.Redis, self).hdel(self.make_key(name), key)
  137. except redis.exceptions.ConnectionError:
  138. pass
  139. def hdel_keys(self, name_starts_with, key):
  140. """Delete hash names with wildcard `*` and key"""
  141. for name in frappe.cache().get_keys(name_starts_with):
  142. name = name.split("|", 1)[1]
  143. self.hdel(name, key)
  144. def hkeys(self, name):
  145. try:
  146. return super(redis.Redis, self).hkeys(self.make_key(name))
  147. except redis.exceptions.ConnectionError:
  148. return []