Skip to content

Commit

Permalink
Every truth has two sides; it is as well to look at both, before we c…
Browse files Browse the repository at this point in the history
…ommit ourselves to either
  • Loading branch information
FraserChapman committed Jul 1, 2019
0 parents commit d3c935f
Show file tree
Hide file tree
Showing 7 changed files with 452 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.pyo
.idea
venv
.DS_Store
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2019 Fraser Chapman <fraser.chapman@gmail.com> (https://github.com/FraserChapman)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
100 changes: 100 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# script.module.cache

![foo](resources/icon.png)

Simple Python HTTP Cache using sqlite3

* Stores cached data in sqlite3.Blobs.
* Calculates lifetime, freshness as virtual columns.
* Obeys cache control directives, immutable, no-store, etc.
* Supports etag, last_modified, etc for conditional requests.
* Can be used as a generic key/blob data store when used without directives.

By default the Cache (and Store) use a sqlite3 database named "cache.sqlite" located in the add-on profile directory

# Examples

Quick examples of basic usage

## Request cache

How to use the Cache class with requests

The Cache class allows you to easily store URIs, as keys, along with their response data and headers in a persistent database.

The calculated column "fresh" and the "conditional_headers" method can be used to limit the number of requests made
and the amount of data transferred respectively.

~~~~python
import requests
from cache import Cache, conditional_headers


def get_html(uri):
# type: (str) -> Union[str, None]
headers = {
"Accept": "text/html",
"Accept-encoding": "gzip"
}
with Cache() as c:
# check if uri is cached
cached = c.get(uri)
if cached:
# if the data is fresh then simply return it
if cached["fresh"]:
return cached["blob"]
# otherwise append applicable "If-None-Match"/"If-Modified-Since" headers
headers.update(conditional_headers(cached))
# request a new version of the data
r = requests.get(uri, headers=headers, timeout=60)
if 200 == r.status_code:
# add the new data and headers to the cache
c.set(uri, r.content, r.headers)
return r.content
if 304 == r.status_code:
# the data hasn't been modified so just touch the cache with the new headers
# and return the existing data
c.touch(uri, r.headers)
return cached["blob"]
# perhaps log any other status codes for debugging
return None

~~~~

## Generic string storage

Generic string storage is facilitated by the Store class.

The Store class allows a "key" to be used to append to, remove from or retrieve a set of unique string values.

This is useful for saving things like; a history of searched terms, urls of played films, etc.

~~~~python
from cache import Store


# key can be anything, app:// prefix isn't required
# the only requirement is that the key be unique with in your add-on
searches = Store("app://user-searches")

# add strings to the store
searches.append("foo")
searches.append("bar")
searches.append("bat")
print(searches.retrieve()) # {'bar', 'bat', 'foo'}

# remove a string from the store
searches.remove("bar")
print(searches.retrieve()) # {'bat', 'foo'}

# clear the store
searches.clear()
print(searches.retrieve()) # set()

~~~~

# References

* [DB-API 2.0 interface for SQLite databases](https://docs.python.org/2/library/sqlite3.html)
* [RFC7234 - HTTP/1.1 Caching](https://tools.ietf.org/html/rfc7234)
* [RFC7232 - HTTP/1.1 Conditional Requests](https://tools.ietf.org/html/rfc7232)
20 changes: 20 additions & 0 deletions addon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.module.cache" name="cache" version="1.0.0" provider-name="fraser">
<requires>
<import addon="xbmc.python" version="2.26.0"/>
</requires>
<extension point="xbmc.python.module" library="lib"/>
<extension point="xbmc.addon.metadata">
<summary lang="en_GB">Simple HTTP Cache using sqlite3</summary>
<description lang="en_GB">Stores cached data in sqlite3.Blobs. Calculates lifetime, freshness as virtual
columns.
Obeys cache control directives, immutable, no-store, etc. Supports etag, last_modified, etc for validation.
Can be used as a generic key/blob data store when used without directives
</description>
<license>MIT</license>
<platform>all</platform>
<email>fraser.chapman@gmail.com</email>
<source>https://github.com/FraserChapman/script.module.cache</source>
<news>v1.0.0 (17-6-19) - Initial version</news>
</extension>
</addon>
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v1.0.0 - Initial version
Loading

0 comments on commit d3c935f

Please sign in to comment.