from coapthon import defines __author__ = 'Giacomo Tanganelli' class Resource(object): """ The Resource class. Represents the base class for all resources. """ def __init__(self, name, coap_server=None, visible=True, observable=True, allow_children=True): """ Initialize a new Resource. :param name: the name of the resource. :param coap_server: the server that own the resource :param visible: if the resource is visible :param observable: if the resource is observable :param allow_children: if the resource could has children """ # The attributes of this resource. self._attributes = {} # The resource name. self.name = name # The resource path. self.path = None # Indicates whether this resource is visible to clients. self._visible = visible # Indicates whether this resource is observable by clients. self._observable = observable if self._observable: self._attributes["obs"] = "" self._allow_children = allow_children self._observe_count = 1 self._payload = {} self._content_type = None self._etag = [] self._location_query = [] self._max_age = None self._coap_server = coap_server self._deleted = False self._changed = False @property def deleted(self): """ Check if the resource has been deleted. For observing purpose. :rtype: bool :return: True, if deleted """ return self._deleted @deleted.setter def deleted(self, b): """ Set the deleted parameter. For observing purpose. :type b: bool :param b: True, if deleted """ self._deleted = b @property def changed(self): """ Check if the resource has been changed. For observing purpose. :rtype: bool :return: True, if changed """ return self._changed @changed.setter def changed(self, b): """ Set the changed parameter. For observing purpose. :type b: bool :param b: True, if changed """ self._changed = b @property def etag(self): """ Get the last valid ETag of the resource. :return: the last ETag value or None if the resource doesn't have any ETag """ if self._etag: return self._etag[-1] else: return None @etag.setter def etag(self, etag): """ Set the ETag of the resource. :param etag: the ETag """ if not isinstance(etag, bytes): etag = bytes(etag, "utf-8") self._etag.append(etag) @property def location_query(self): """ Get the Location-Query of a resource. :return: the Location-Query """ return self._location_query @location_query.setter def location_query(self, lq): """ Set the Location-Query. :param lq: the Location-Query """ self._location_query = lq @location_query.deleter def location_query(self): """ Delete the Location-Query. """ self.location_query = [] @property def max_age(self): """ Get the Max-Age. :return: the Max-Age """ return self._max_age @max_age.setter def max_age(self, ma): """ Set the Max-Age. :param ma: the Max-Age """ self._max_age = ma @property def payload(self): """ Get the payload of the resource according to the content type specified by required_content_type or "text/plain" by default. :return: the payload. """ if self._content_type is not None: try: return self._payload[self._content_type] except KeyError: raise KeyError("Content-Type not available") else: if defines.Content_types["text/plain"] in self._payload: return self._payload[defines.Content_types["text/plain"]] else: val = list(self._payload.keys()) return val[0], self._payload[val[0]] @payload.setter def payload(self, p): """ Set the payload of the resource. :param p: the new payload """ if isinstance(p, tuple): k = p[0] v = p[1] self.actual_content_type = k self._payload[k] = v else: self._payload = {defines.Content_types["text/plain"]: p} @property def attributes(self): """ Get the CoRE Link Format attribute of the resource. :return: the attribute of the resource """ return self._attributes @attributes.setter def attributes(self, att): # TODO assert """ Set the CoRE Link Format attribute of the resource. :param att: the attributes """ self._attributes = att @property def visible(self): """ Get if the resource is visible. :return: True, if visible """ return self._visible @property def observable(self): """ Get if the resource is observable. :return: True, if observable """ return self._observable @property def allow_children(self): """ Get if the resource allow children. :return: True, if allow children """ return self._allow_children @property def observe_count(self): """ Get the Observe counter. :return: the Observe counter value """ return self._observe_count @observe_count.setter def observe_count(self, v): """ Set the Observe counter. :param v: the Observe counter value """ assert isinstance(v, int) self._observe_count = (v % 65000) @property def actual_content_type(self): """ Get the actual required Content-Type. :return: the actual required Content-Type. """ return self._content_type @actual_content_type.setter def actual_content_type(self, act): """ Set the actual required Content-Type. :param act: the actual required Content-Type. """ self._content_type = act @property def content_type(self): """ Get the CoRE Link Format ct attribute of the resource. :return: the CoRE Link Format ct attribute """ value = "" lst = self._attributes.get("ct") if lst is not None and len(lst) > 0: value = "ct=" for v in lst: value += str(v) + " " if len(value) > 0: value = value[:-1] return value @content_type.setter def content_type(self, lst): """ Set the CoRE Link Format ct attribute of the resource. :param lst: the list of CoRE Link Format ct attribute of the resource """ value = [] if isinstance(lst, str): ct = defines.Content_types[lst] self.add_content_type(ct) elif isinstance(lst, list): for ct in lst: self.add_content_type(ct) def add_content_type(self, ct): """ Add a CoRE Link Format ct attribute to the resource. :param ct: the CoRE Link Format ct attribute """ lst = self._attributes.get("ct") if lst is None: lst = [] if isinstance(ct, str): ct = defines.Content_types[ct] lst.append(ct) self._attributes["ct"] = lst @property def resource_type(self): """ Get the CoRE Link Format rt attribute of the resource. :return: the CoRE Link Format rt attribute """ value = "rt=" lst = self._attributes.get("rt") if lst is None: value = "" else: value += "\"" + str(lst) + "\"" return value @resource_type.setter def resource_type(self, rt): """ Set the CoRE Link Format rt attribute of the resource. :param rt: the CoRE Link Format rt attribute """ if not isinstance(rt, str): rt = str(rt) self._attributes["rt"] = rt @property def interface_type(self): """ Get the CoRE Link Format if attribute of the resource. :return: the CoRE Link Format if attribute """ value = "if=" lst = self._attributes.get("if") if lst is None: value = "" else: value += "\"" + str(lst) + "\"" return value @interface_type.setter def interface_type(self, ift): """ Set the CoRE Link Format if attribute of the resource. :param ift: the CoRE Link Format if attribute """ if not isinstance(ift, str): ift = str(ift) self._attributes["if"] = ift @property def maximum_size_estimated(self): """ Get the CoRE Link Format sz attribute of the resource. :return: the CoRE Link Format sz attribute """ value = "sz=" lst = self._attributes.get("sz") if lst is None: value = "" else: value += "\"" + str(lst) + "\"" return value @maximum_size_estimated.setter def maximum_size_estimated(self, sz): """ Set the CoRE Link Format sz attribute of the resource. :param sz: the CoRE Link Format sz attribute """ if not isinstance(sz, str): sz = str(sz) self._attributes["sz"] = sz @property def observing(self): """ Get the CoRE Link Format obs attribute of the resource. :return: the CoRE Link Format obs attribute """ if self._observable: return "obs" def init_resource(self, request, res): """ Helper function to initialize a new resource. :param request: the request that generate the new resource :param res: the resource :return: the edited resource """ res.location_query = request.uri_query res.payload = (request.content_type, request.payload) return res def edit_resource(self, request): """ Helper function to edit a resource :param request: the request that edit the resource """ self.location_query = request.uri_query self.payload = (request.content_type, request.payload) def render_GET(self, request): """ Method to be redefined to render a GET request on the resource. :param request: the request :return: the resource """ raise NotImplementedError def render_GET_advanced(self, request, response): """ Method to be redefined to render a GET request on the resource. :param response: the partially filled response :param request: the request :return: a tuple with (the resource, the response) """ raise NotImplementedError def render_PUT(self, request): """ Method to be redefined to render a PUTT request on the resource. :param request: the request :return: the resource """ raise NotImplementedError def render_PUT_advanced(self, request, response): """ Method to be redefined to render a PUTT request on the resource. :param response: the partially filled response :param request: the request :return: a tuple with (the resource, the response) """ raise NotImplementedError def render_POST(self, request): """ Method to be redefined to render a POST request on the resource. :param request: the request :return: the resource """ raise NotImplementedError def render_POST_advanced(self, request, response): """ Method to be redefined to render a POST request on the resource. :param response: the partially filled response :param request: the request :return: a tuple with (the resource, the response) """ raise NotImplementedError def render_DELETE(self, request): """ Method to be redefined to render a DELETE request on the resource. :param request: the request :return: a boolean """ raise NotImplementedError def render_DELETE_advanced(self, request, response): """ Method to be redefined to render a DELETE request on the resource. :param response: the partially filled response :param request: the request :return: a tuple with a boolean and the response """ raise NotImplementedError