Add-on:Common plugin cache: Difference between revisions

From Official Kodi Wiki
Jump to navigation Jump to search
>TobiasTheCommie
m (Addon-Bot repo category update)
 
(123 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{Addon  
{{Addon  
|Name=Common plugin cache
|Name=Common plugin cache
|provider-name=TheCollective
|provider-name=anxdpanic, TheCollective
|ID=script.common.plugin.cache
|ID=script.common.plugin.cache
|latest-version=0.9.0
|latest-version=3.0.0
|extension point=xbmc.service
|extension point=xbmc.service
|provides=
|provides=
|Summary=Common caching api for xbmc plugins.
|Summary=A common caching API for Kodi add-ons.
|Description=
|Description=A common caching API for Kodi add-ons.
|Platform=all
|Platform=all
|Repo= [[:Category:Pre-Eden add-on repository|Pre-Eden (v11)]]
|Language=
|icon url=}}
|License=GPL-3.0-only
|Forum=
|Website=
|Source=https://github.com/anxdpanic/script.common.plugin.cache
|Email=
|broken=
|icon url=http://mirrors.kodi.tv/addons/omega/script.common.plugin.cache/icon.png}}
= Testing/Status =
= Testing/Status =
Integration and unittests are run continously by Jenkins
Integration and unittests are run continously by Jenkins
Line 23: Line 29:
Do note that important data should NOT be stored using this service as the sqlite database will be deleted on any corruption.
Do note that important data should NOT be stored using this service as the sqlite database will be deleted on any corruption.


Development and support thread: http://forum.xbmc.org/showthread.php?t=116496
Development and support thread: http://forum.kodi.tv/showthread.php?t=116496


== Setup ==
== Setup ==
Line 29: Line 35:


   <requires>
   <requires>
     <import addon="xbmc.python" version="2.0"/>
     <import addon="xbmc.python" version="2.1.0"/>
     <import addon="script.common.plugin.cache" version="0.9.0"/> # Add this
     <import addon="script.common.plugin.cache" version="2.5.5"/> # Add this
   </requires>
   </requires>


And add the following to your py file.
And add the following to your py file.
Line 40: Line 45:
   except:
   except:
     import storageserverdummy as StorageServer
     import storageserverdummy as StorageServer
   cache = StorageServer.StorageServer()
   cache = StorageServer.StorageServer("tablename", 24) # (Your plugin name, Cache time in hours)
  cache.table_name = "PluginName" # Name of your plugin.


You can now access the caching service through the "cache" variable.
You can now access the caching service through the "cache" variable.


Remember to include a fallback [http://hg.tobiasussing.dk/hgweb.cgi/youtubexbmc/file/21b17fff9eea/storageserverdummy.py storageserverdummy.py] file.
Remember to include a fallback storageserverdummy.py file(Copy it from the script.common.plugin.cache/lib/ directory)


== Debugging ==
== Debugging ==
To enable debugging set the following values in default.py
To enable debugging set the following values in default.py


  dbg = True # Default
  dbg = True


Or you can change it after import with.
Or you can change it after import with.


  common.dbg = True # Default
  common.dbg = True


Whenever you debug your own code you should also debug in the cache. Otherwise you should remember to DISABLE it.
Note: Only the client communication will be debugged when setting this flag.


== cacheFunction(self, funct = False, *args) ==
== cacheFunction(self, funct = False, *args) ==
Caching function results for one day.
Caching function results for one day.


The function being cached must return a tupple ( function_return, status), a status of 200 means the result is ok and should be cached. Any other value and the function result will be returned, but not cached.
The function being cached must return a list or a dictionary.
 
A cache is only stored if the result returned is longer than 0 in length.


returns a tupple of the results from the function called.
Returns what the provided function returns.


   def pi_count(self):
   def pi_count(self):
Line 83: Line 89:
       unity = 10**(digits + 10)
       unity = 10**(digits + 10)
       pi = 4 * (4*arccot(5, unity) - arccot(239, unity))
       pi = 4 * (4*arccot(5, unity) - arccot(239, unity))
       return (pi // 10**10, 200)
       return pi // 10**10
    
    
  cache.table_name = "PluginName" # Name of your plugin.
   result = cache.cacheFunction(pi_count) # This will call the pi_count function, save the result in the cache, and return the result.
   result = cache.cacheFunction(pi_count) # This will call the pi_count function, save the result in the cache, and return the result.
   time.sleep(300)
   time.sleep(300)
Line 95: Line 100:


   result = cache.cacheFunction(calc_add, 4, 4)
   result = cache.cacheFunction(calc_add, 4, 4)
   second_result = cache.cacheFunction(some_function, 5, ret = "True", { "complicated": "true" } )
   second_result = cache.cacheFunction(another_function, 5, ret = "True", { "complicated": "true" } )
 
If you need to pass on another function as an argument, this must be done in in a dictionary like this: { "new_results_function": pi_count }.


If you want to pass a function as an argument in the cache this MUST be done in a dictionary like this:
Because functions are instances they have specific identifiers that will change on every run. When cacheFunction generates the hash for a call and its result it will not take into account params["new_results_function"]. This means:
* One should NOT use params["new_results_function"] for anything OTHER than a function, since cacheFunction will then return false matches.
* One should NOT pass on a function in any way other than params["new_results_function"], as cacheFunction will never find a match.


   def some_function(start, length = 10 , params = {} ):
   def some_function(first, second, params = {} ):
     if start < time.time() and params.has_key("new_results_function"):
     if params.has_key("new_results_function"):
       return params["new_results_function"](length)
       return params["new_results_function"](first, second)
     else:
     else:
       return 0
       return 0
   
   
   result = cache.cacheFunction(some_function, 1, params = { "new_results_function": pi_count } )
   result = cache.cacheFunction(some_function, 1, 3, params = { "new_results_function": calc_add } )
 
Because functions are instances they have specific identifiers that will change on every run.


== lock(self, str) ==
== lock(self, str) ==
Line 124: Line 131:


== unlock(self, str) ==
== unlock(self, str) ==
Unlock
Try to unlock


Returns bool
Returns bool
Line 138: Line 145:
   if not new_unlocked:
   if not new_unlocked:
     print "Couldn't discard lock."
     print "Couldn't discard lock."
== delete(self, str) ==
Delete entities matching the str.
This functions accepts [http://www.w3schools.com/SQL/sql_wildcards.asp SQL wildcards].
Returns nothing
  cache.table_name = "PluginName"
  cache.set("mystring", "string")
  cache.set("myint", 1234)
  cache.set("mydict", repr({ "our": { "dictionary": [] } }) )
  cache.delete("my%")
  some_int = cache.get("myint")
  print some_int # prints ""
  some_string = cache.get("mystring")
  print some_string # prints ""
  some_dict = cache.get("mydict")
  print some_dict # prints ""


== set(self, str, object ) ==
== set(self, str, object ) ==
Line 147: Line 176:
   cache.set("some_string", "string")
   cache.set("some_string", "string")
   cache.set("some_int", 1234)
   cache.set("some_int", 1234)
   cache.set("some_dict", { "our": { "dictionary": [] } } )
   cache.set("some_dict", repr({ "our": { "dictionary": [] } }) )


== setMulti(self, str, dict) ==
== setMulti(self, str, dict) ==
Line 156: Line 185:
   cache.table_name = "PluginName"
   cache.table_name = "PluginName"
   
   
   save_data = { "some_string": "string", "some_int": 1234, "some_dict": { "our": { "dictionary": [] } } }
   save_data = { "some_string": "string", "some_int": 1234, "some_dict": repr({ "our": { "dictionary": [] } }) }
   cache.setMulti("pre-", save_data)
   cache.setMulti("pre-", save_data)


Line 167: Line 196:
   cache.set("some_string", "string")
   cache.set("some_string", "string")
   cache.set("some_int", 1234)
   cache.set("some_int", 1234)
   cache.set("some_dict", { "our": { "dictionary": [] } } )
   cache.set("some_dict", repr({ "our": { "dictionary": [] } }) )
   
   
   some_string = cache.get("some_string")
   some_string = cache.get("some_string")
Line 176: Line 205:
   
   
   some_dict = cache.get("some_dict")
   some_dict = cache.get("some_dict")
   print repr(some_dict) # prints '{ "our": { "dictionary": [] } }'
   print eval(some_dict) # prints '{ "our": { "dictionary": [] } }'


== getMulti(self, str, list) ==
== getMulti(self, str, list) ==
Line 185: Line 214:
   cache.table_name = "PluginName"
   cache.table_name = "PluginName"
   
   
   save_data = { "some_string": "string", "some_int": 1234, "some_dict": { "our": { "dictionary": [] } } }
   save_data = { "some_string": "string", "some_int": 1234, "some_dict": repr({ "our": { "dictionary": [] } }) }
   cache.setMulti("pre-", save_data)
   cache.setMulti("pre-", save_data)
   
   
Line 192: Line 221:
   print result[0] # Prints "string"
   print result[0] # Prints "string"
   print result[1] # Prints 1234
   print result[1] # Prints 1234
   print repr(result[2]) # Prints '{ "our": { "dictionary": [] } }'
   print eval(result[2]) # Prints '{ "our": { "dictionary": [] } }'


[[Category:Pre-Eden add-on repository]]
[[Category:Add-ons with license tag]]
[[Category:Add-ons with source tag]]
[[Category:All add-ons]]
[[Category:Service add-ons]]
[[Category:Gotham add-on repository]]
[[Category:Helix add-on repository]]
[[Category:Isengard add-on repository]]
[[Category:Jarvis add-on repository]]
[[Category:Krypton add-on repository]]
[[Category:Leia add-on repository]]
[[Category:Matrix add-on repository]]
[[Category:Nexus add-on repository]]
[[Category:Omega add-on repository]]

Latest revision as of 19:26, 11 April 2024

Common plugin cache
icon.png

See this add-on on the kodi.tv showcase

Author: anxdpanic, TheCollective

Type: Services
Repo: Kodi.tv repo v21
Kodi.tv repo v20
Kodi.tv repo v19

License: GPL-3.0-only
Source: Source code
Summary: A common caching API for Kodi add-ons.
Home icon grey.png   ▶ Add-ons ▶ Common plugin cache

A common caching API for Kodi add-ons.

Installing

This add-on is installed from the Add-on browser located in Kodi as follows:

  1. Settings
  2. Add-ons
  3. Install from repository
  4. Services
  5. Common plugin cache
  6. Install

Testing/Status

Integration and unittests are run continously by Jenkins

http://tc.tobiasussing.dk/jenkins/view/Cache%20Service/

Developers

This service works as an independant storage server to XBMC's implementation.

It provides proper thread safe locking and get set functions to store data.

Do note that important data should NOT be stored using this service as the sqlite database will be deleted on any corruption.

Development and support thread: http://forum.kodi.tv/showthread.php?t=116496

Setup

To use the cacheing service edit your addon.xml file like this.

 <requires>
   <import addon="xbmc.python" version="2.1.0"/>
   <import addon="script.common.plugin.cache" version="2.5.5"/> # Add this
 </requires>

And add the following to your py file.

 try:
   import StorageServer
 except:
   import storageserverdummy as StorageServer
 cache = StorageServer.StorageServer("tablename", 24) # (Your plugin name, Cache time in hours)

You can now access the caching service through the "cache" variable.

Remember to include a fallback storageserverdummy.py file(Copy it from the script.common.plugin.cache/lib/ directory)

Debugging

To enable debugging set the following values in default.py

dbg = True

Or you can change it after import with.

common.dbg = True

Note: Only the client communication will be debugged when setting this flag.

cacheFunction(self, funct = False, *args)

Caching function results for one day.

The function being cached must return a list or a dictionary.

A cache is only stored if the result returned is longer than 0 in length.

Returns what the provided function returns.

 def pi_count(self):
     def arccot(x, unity):
         sum = xpower = unity // x
         n = 3
         sign = -1
         while 1:
               xpower = xpower // (x*x)
               term = xpower // n
               if not term:
                       break
               sum += sign * term
               sign = -sign
               n += 2
         return sum
  
     digits = 40
     unity = 10**(digits + 10)
     pi = 4 * (4*arccot(5, unity) - arccot(239, unity))
     return pi // 10**10
 
 result = cache.cacheFunction(pi_count) # This will call the pi_count function, save the result in the cache, and return the result.
 time.sleep(300)
 result = cache.cacheFunction(pi_count) # This will return the cached result
 time.sleep(3600)
 result = cache.cacheFunction(pi_count) # This will again call pi_count since the result is now considered stale.

To pass arguments to the function, you just add them as additional arguments to cacheFunction.

 result = cache.cacheFunction(calc_add, 4, 4)
 second_result = cache.cacheFunction(another_function, 5, ret = "True", { "complicated": "true" } )

If you need to pass on another function as an argument, this must be done in in a dictionary like this: { "new_results_function": pi_count }.

Because functions are instances they have specific identifiers that will change on every run. When cacheFunction generates the hash for a call and its result it will not take into account params["new_results_function"]. This means:

  • One should NOT use params["new_results_function"] for anything OTHER than a function, since cacheFunction will then return false matches.
  • One should NOT pass on a function in any way other than params["new_results_function"], as cacheFunction will never find a match.
 def some_function(first, second, params = {} ):
   if params.has_key("new_results_function"):
     return params["new_results_function"](first, second)
   else:
     return 0

 result = cache.cacheFunction(some_function, 1, 3, params = { "new_results_function": calc_add } )

lock(self, str)

Try to aquire a lock

Returns bool

 cache.table_name = "PluginName"
 locked = cache.lock("lock_me") # Returns True
 if locked:
   print "Got lock"

 new_lock = cache.lock("lock_me") # Returns False
 if not new_lock:
   print "Couldn't aquire second lock.

unlock(self, str)

Try to unlock

Returns bool

 cache.table_name = "PluginName"
 lock = cache.lock("lock_me") # Returns True

 unlocked = cache.unlock("lock_me") # Returns True
 if unlocked:
   print "Discarded lock"

 new_unlocked = cache.unlock("lock_me") # Returns False
 if not new_unlocked:
   print "Couldn't discard lock."

delete(self, str)

Delete entities matching the str.

This functions accepts SQL wildcards.

Returns nothing

 cache.table_name = "PluginName"
 cache.set("mystring", "string")
 cache.set("myint", 1234)
 cache.set("mydict", repr({ "our": { "dictionary": [] } }) )
 cache.delete("my%")

 some_int = cache.get("myint")
 print some_int # prints ""

 some_string = cache.get("mystring")
 print some_string # prints ""

 some_dict = cache.get("mydict")
 print some_dict # prints ""

set(self, str, object )

Store a value

Returns nothing

 cache.table_name = "PluginName"
 cache.set("some_string", "string")
 cache.set("some_int", 1234)
 cache.set("some_dict", repr({ "our": { "dictionary": [] } }) )

setMulti(self, str, dict)

Store multiple values

Returns nothing

 cache.table_name = "PluginName"

 save_data = { "some_string": "string", "some_int": 1234, "some_dict": repr({ "our": { "dictionary": [] } }) }
 cache.setMulti("pre-", save_data)

get(self, str)

Get a value

Returns stored data.

 cache.table_name = "PluginName"
 cache.set("some_string", "string")
 cache.set("some_int", 1234)
 cache.set("some_dict", repr({ "our": { "dictionary": [] } }) )

 some_string = cache.get("some_string")
 print some_string # Prints "string"

 some_int = cache.get("some_int")
 print some_int # prints 1234

 some_dict = cache.get("some_dict")
 print eval(some_dict) # prints '{ "our": { "dictionary": [] } }'

getMulti(self, str, list)

Get multiple values

Retuns list of stored data elements.

 cache.table_name = "PluginName"

 save_data = { "some_string": "string", "some_int": 1234, "some_dict": repr({ "our": { "dictionary": [] } }) }
 cache.setMulti("pre-", save_data)

 get_list = [ "some_string", "some_int", "some_dict" ]
 result = cache.getMulti("pre-", get_list)
 print result[0] # Prints "string"
 print result[1] # Prints 1234
 print eval(result[2]) # Prints '{ "our": { "dictionary": [] } }'