112 lines
3.7 KiB
Python
112 lines
3.7 KiB
Python
|
import logging
|
||
|
|
||
|
from coapthon.defines import Codes
|
||
|
|
||
|
from coapthon.caching.cache import *
|
||
|
|
||
|
__author__ = 'Emilio Vallati'
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
class CacheLayer(object):
|
||
|
|
||
|
def __init__(self, mode, max_dim=2048):
|
||
|
"""
|
||
|
|
||
|
:param max_dim:
|
||
|
"""
|
||
|
self.cache = Cache(mode, max_dim)
|
||
|
|
||
|
def receive_request(self, transaction):
|
||
|
"""
|
||
|
checks the cache for a response to the request
|
||
|
|
||
|
:param transaction:
|
||
|
:return:
|
||
|
"""
|
||
|
|
||
|
transaction.cached_element = self.cache.search_response(transaction.request)
|
||
|
if transaction.cached_element is None:
|
||
|
transaction.cacheHit = False
|
||
|
else:
|
||
|
transaction.response = transaction.cached_element.cached_response
|
||
|
transaction.response.mid = transaction.request.mid
|
||
|
transaction.cacheHit = True
|
||
|
|
||
|
age = transaction.cached_element.creation_time + transaction.cached_element.max_age - time.time()
|
||
|
if transaction.cached_element.freshness is True:
|
||
|
if age <= 0:
|
||
|
logger.debug("resource not fresh")
|
||
|
"""
|
||
|
if the resource is not fresh, its Etag must be added to the request so that the server might validate it instead of sending a new one
|
||
|
"""
|
||
|
transaction.cached_element.freshness = False
|
||
|
"""
|
||
|
ensuring that the request goes to the server
|
||
|
"""
|
||
|
transaction.cacheHit = False
|
||
|
logger.debug("requesting etag %s", transaction.response.etag)
|
||
|
transaction.request.etag = transaction.response.etag
|
||
|
else:
|
||
|
transaction.response.max_age = age
|
||
|
else:
|
||
|
transaction.cacheHit = False
|
||
|
return transaction
|
||
|
|
||
|
def send_response(self, transaction):
|
||
|
"""
|
||
|
updates the cache with the response if there was a cache miss
|
||
|
|
||
|
:param transaction:
|
||
|
:return:
|
||
|
"""
|
||
|
if transaction.cacheHit is False:
|
||
|
"""
|
||
|
handling response based on the code
|
||
|
"""
|
||
|
logger.debug("handling response")
|
||
|
self._handle_response(transaction)
|
||
|
return transaction
|
||
|
|
||
|
def _handle_response(self, transaction):
|
||
|
"""
|
||
|
handles responses based on their type
|
||
|
|
||
|
:param transaction:
|
||
|
:return:
|
||
|
"""
|
||
|
code = transaction.response.code
|
||
|
utils.check_code(code)
|
||
|
"""
|
||
|
VALID response:
|
||
|
change the current cache value by switching the option set with the one provided
|
||
|
also resets the timestamp
|
||
|
if the request etag is different from the response, send the cached response
|
||
|
"""
|
||
|
if code == Codes.VALID.number:
|
||
|
logger.debug("received VALID")
|
||
|
self.cache.validate(transaction.request, transaction.response)
|
||
|
if transaction.request.etag != transaction.response.etag:
|
||
|
element = self.cache.search_response(transaction.request)
|
||
|
transaction.response = element.cached_response
|
||
|
return transaction
|
||
|
|
||
|
"""
|
||
|
CHANGED, CREATED or DELETED response:
|
||
|
mark the requested resource as not fresh
|
||
|
"""
|
||
|
if code == Codes.CHANGED.number or code == Codes.CREATED.number or code == Codes.DELETED.number:
|
||
|
target = self.cache.search_related(transaction.request)
|
||
|
if target is not None:
|
||
|
for element in target:
|
||
|
self.cache.mark(element)
|
||
|
return transaction
|
||
|
|
||
|
"""
|
||
|
any other response code can be cached normally
|
||
|
"""
|
||
|
self.cache.cache_add(transaction.request, transaction.response)
|
||
|
return transaction
|
||
|
|