def _do_delete_children(self): child_promises = [] for child in self.resource.childResource: request = OneM2MRequest(OneM2MOperation.delete, child.path, fr=None, rqi=self.request.rqi) request.cascading = True child_promises.append(self.handle_onem2m_request(request)) async_all(child_promises, fulfill_with_none=True).get()
def _start(self): def retrieve_remote_cse_list(): def get_collection(session): p = session.get_collection(None, RemoteCSE, CSEBase(path="/onem2m")) session.commit() return p return self.api.db.start_session().then(get_collection) def get_cse(cse): cse_req = OneM2MRequest(OneM2MOperation.retrieve, cse, None, MetaInformation(None)) return (self.api.handle_onem2m_request(cse_req) .then(lambda r: r.resource)) def handle_remote_cse_list(remote_cse_list): self.logger.debug("Loaded RemoteCSE list is %s" % remote_cse_list) for cse in remote_cse_list: self.logger.debug("Adding CSE %s in the list" % cse) self._cse_links[cse.path] = cse.link return retrieve_remote_cse_list() \ .then( lambda remote_cse_list: async_all(map(get_cse, remote_cse_list))) \ .then(handle_remote_cse_list) \ .then(self._started)
def _handle_deleted(self, instance, req_ind): poc_path = instance.path scl_path = poc_path.rpartition('/')[0].rpartition('/')[0] self.logger.debug("_handle_deleted: instance: %s %s", poc_path, scl_path) promises = [] del (self.pocs_info[scl_path][poc_path]) #delete m2mpoc from list if len(self.pocs_info[scl_path]) <= 1: #check if the scl has more pocs del (self.pocs_info[scl_path]) #delete scl from the list onlinestatus_path = scl_path + "/onlineStatus" online_status = {"onlineStatus": "OFFLINE"} rq = UpdateRequestIndication(onlinestatus_path, resource=online_status, typename="scl") rq.internal = True serverCapability_path = scl_path + "/serverCapability" serverCapability = {"serverCapability": "FALSE"} rq2 = UpdateRequestIndication(serverCapability_path, resource=serverCapability, typename="scl") rq2.internal = True promises = [ self.api.handle_request_indication(rq), self.api.handle_request_indication(rq2) ] promises.append(self._update_scl(scl_path, self.pocs_info[scl_path])) return async_all(promises, fulfill_with_none=True)
def handle_items(items): if not items: p = Promise() return p.fulfill(None) promises = [] for path, pocs in items: promises.append(self._do_handle_pocs(path, pocs, shelve)) return async_all(promises, fulfill_with_none=True)
def _handle_updated(self, instance, req_ind): """ #example: instance:M2mPoc(path='/m2m/scls/gscl/m2mPocs/m2mPoc1qvr4rUOGJAKEPFK', name='m2mPoc1qvr4rUOGJAKEPFK') req_ind:RequestIndication: { path: /m2m/scls/gscl/m2mPocs/m2mPoc1qvr4rUOGJAKEPFK, method: update, typename: m2mPoc, resource: { 'expirationTime': '2014-07-11T17:05:09.004744+00:00', 'contactInfo': 'https://[2001:638:806:65:f4bf:ccb0:cad5:a203]:6000', 'onlineStatus': 'ONLINE' } } """ self.logger.debug("_handle_updated: instance:%s req_ind:%s", instance, req_ind) resource = req_ind.resource poc_path = instance.path scl_path = poc_path.rpartition('/')[0].rpartition('/')[0] online_status = resource['onlineStatus'] self.logger.debug("_handle_updated: pocs_info:%s", self.pocs_info) self.pocs_info[scl_path][poc_path] = {'onlineStatus': online_status} has_offline = False has_online = False for key, value in self.pocs_info.get(scl_path).items(): if key != 'onlineStatus': if value['onlineStatus'] == 'ONLINE': has_online = True elif value['onlineStatus'] == 'OFFLINE': has_offline = True if has_online: self.pocs_info[scl_path]['onlineStatus'] = "ONLINE" elif has_offline: self.pocs_info[scl_path]['onlineStatus'] = "OFFLINE" else: self.pocs_info[scl_path]['onlineStatus'] = "NOT_REACHABLE" onlinestatus_path = scl_path + "/onlineStatus" online_status = { "onlineStatus": self.pocs_info[scl_path]['onlineStatus'] } rq = UpdateRequestIndication(onlinestatus_path, resource=online_status, typename="scl") rq.internal = True promises = [ self._update_scl(scl_path, self.pocs_info[scl_path]), self.api.handle_request_indication(rq) ] return async_all(promises, fulfill_with_none=True)
def _start(self): def retrieve_scl_list(): scls_req_ind = RetrieveRequestIndication(self._scl_base + '/scls') return (self.api.handle_request_indication(scls_req_ind) .then(lambda r: r.resource.sclCollection)) def get_scl(scl): scl_req_ind = RetrieveRequestIndication(scl) return (self.api.handle_request_indication(scl_req_ind) .then(lambda r: r.resource)) def handle_scl_list(scl_list): for scl in scl_list: self._scl_links[scl.path] = scl.link return retrieve_scl_list().then( lambda scls_list: async_all(map(get_scl, scls_list))).then( handle_scl_list).then( self._started)
def _register_pocs(self): def send_update(m2mpoc, fields): uri = self.nscl_uri + "/" + "scls/" + self.gscl_id\ + "/" + "m2mPocs" + "/" + m2mpoc.id rq = UpdateRequestIndication(uri, m2mpoc) rq.requestingEntity = self.config.get("requesting_entity") # TODO: add restore function in case of 404 or something return self.api.send_request_indication(rq) def _start_endpoint_refresher(response, m2mpoc): m2mpoc.set_path(response.resourceURI) self.poc_refresher.start(m2mpoc, []) def _register_endpoint(endpoint): # create a M2mPoc with the endpoint as contact info in the NSCL # (onlineStatus=ONLINE) uri = self.nscl_uri + "/" + "scls/" + self.gscl_id + "/" + "m2mPocs" m2mpoc = M2mPoc() m2mpoc.onlineStatus = "ONLINE" m2mpoc.contactInfo = endpoint.base_uri m2mpoc.expirationTime = self._gscl.expirationTime rq = CreateRequestIndication(uri, m2mpoc) rq.requestingEntity = self.config.get("requesting_entity") p = self.api.send_request_indication(rq).then( lambda evt, m2mpoc=m2mpoc: _start_endpoint_refresher( evt, m2mpoc)) return p # we use a separate refresher for pocs, # because refresher is specifically for Scl (see send_update) self.poc_refresher = ExpTimeUpdater(self.api, send_update, interval=self.interval, offset=self.offset) promise_list = map(_register_endpoint, self.api.get_mid_endpoints()) return async_all(promise_list, True)
def _check_notification_uri(self): # TODO(rst): TS-004 7.3.8.2.1 # 5. If the notificationURI is not the Originator, the Hosting CSE # should send a Notify request primitive to the notificationURI with # verificationRequest parameter set as TRUE (clause 7.4.1.2.2). # debug only if self.request.originator is None: return try: self.logger.debug("Checking notificationURI: %s", self.request.content.notificationURI) uris = [uri for uri in self.request.content.notificationURI if not uri.startswith(self.request.originator)] # TODO(rst): change the check that it should be a valid AE-ID # for uri in uris: # if not urlparse(uri).scheme: # raise CSESyntaxError("Invalid notificationURI") except KeyError: raise CSESyntaxError("Invalid notificationURI") # a. If the Hosting CSE cannot send the Notify request primitive, the # Hosting CSE shall return the Notify response primitive with a Response # Status Code indicating "SUBSCRIPTION_VERIFICATION_INITIATION_FAILED" # error. def send_verification(notify_uri): notification = Notification( verificationRequest=True, creator=self.request.originator ) send_notify_request = OneM2MRequest(OneM2MOperation.notify, notify_uri, None, MetaInformation(None), notification) return self.api.send_onem2m_request(send_notify_request) # b. If the Hosting CSE sent the primitive, the Hosting CSE shall # check if the Notify response primitive contains a Response Status Code # indicating "SUBSCRIPTION_CREATOR_HAS_NO_PRIVILEGE" or # "SUBSCRIPTION_HOST_HAS_NO_PRIVILEGE" error. If so, the Hosting CSE # shall return the Create response primitive with a Response Status Code # indicating the same error from the Notify response primitive to the # Originator. def handle_error(error): self.logger.info("Subscription verification failed: %s", error) raise CSEError # TODO(rst): check subscription error # if error.status_code in [ # STATUS_REQUEST_TIMEOUT, # STATUS_BAD_GATEWAY, # STATUS_SERVICE_UNAVAILABLE, # STATUS_GATEWAY_TIMEOUT # ]: # raise CannotInitiateSubscriptionVerification(error) # elif error.status_code == STATUS_SUBSCRIPTION_VERIFICATION_FAILED: # raise SubscriptionVerificationFailed(error) # else: # raise CSEBadGateway(error) try: async_all(map(send_verification, uris), fulfill_with_none=True).get() except Exception as error: handle_error(error)
def _handle_created(self, instance, req_ind): """ #example: instance:M2mPoc(path='/m2m/scls/gscl/m2mPocs/m2mPocnRIjsAAZmqm1U49j', name='m2mPocnRIjsAAZmqm1U49j') req_ind:RequestIndication: { path: /m2m/scls/gscl/m2mPocs, method: create, typename: m2mPoc, resource: { 'creationTime': datetime.datetime(2014, 7, 11, 13, 37, 40, 385438, tzinfo=<openmtc.util.Utc object at 0x7f4d9bf68e50>), 'expirationTime': datetime.datetime(2014, 7, 11, 13, 43, 40, tzinfo=<FixedOffset '+00:00'>), 'onlineStatus': 'ONLINE', 'contactInfo': 'http://[2001:638:806:65:f4bf:ccb0:cad5:a203]:5000', 'lastModifiedTime': datetime.datetime(2014, 7, 11, 13, 37, 40, 385438, tzinfo=<openmtc.util.Utc object at 0x7f4d9bf68e50>) } } """ self.logger.debug("_handle_created: instance:%s req_ind:%s", instance, req_ind) resource = req_ind.resource poc_path = instance.path scl_path = req_ind.path[:-8] online_status = resource['onlineStatus'] if self.pocs_info.get(scl_path) is None: self.pocs_info[scl_path] = {'onlineStatus': online_status} self.pocs_info[scl_path][poc_path] = { 'onlineStatus': online_status } else: self.pocs_info[scl_path][poc_path] = { 'onlineStatus': online_status } has_offline = False has_online = False for key, value in self.pocs_info.get(scl_path).items(): if key != 'onlineStatus': if value['onlineStatus'] == 'ONLINE': has_online = True elif value['onlineStatus'] == 'OFFLINE': has_offline = True if has_online: self.pocs_info[scl_path]['onlineStatus'] = "ONLINE" elif has_offline: self.pocs_info[scl_path]['onlineStatus'] = "OFFLINE" else: self.pocs_info[scl_path]['onlineStatus'] = "NOT_REACHABLE" self.logger.debug("_handle_created: self.pocs_info: %s", self.pocs_info) onlinestatus_path = scl_path + "/onlineStatus" online_status = { "onlineStatus": self.pocs_info[scl_path]['onlineStatus'] } rq = UpdateRequestIndication(onlinestatus_path, resource=online_status, typename="scl") rq.internal = True serverCapability_path = scl_path + "/serverCapability" serverCapability = {"serverCapability": True} rq2 = UpdateRequestIndication(serverCapability_path, resource=serverCapability, typename="scl") rq2.internal = True promises = [self._update_scl(scl_path, self.pocs_info[scl_path]), self.api.handle_request_indication(rq), \ self.api.handle_request_indication(rq2)] return async_all(promises, fulfill_with_none=True)
def _update_announcements(self, resource, add_list): old_resource = self._announcements[resource.path]['resource'] uris = self._announcements[resource.path]['uris'] attributes_changed = False try: if (resource.expirationTime != old_resource.expirationTime or resource.searchStrings != old_resource.searchStrings or resource.accessRightID != old_resource.accessRightID): attributes_changed = True except AttributeError: if (resource.expirationTime != old_resource.expirationTime or resource.searchStrings != old_resource.searchStrings): attributes_changed = True if attributes_changed: annc_model = get_resource_type(resource.typename + "Annc") def send_update_annc_pre(scl_uri): try: if not resource.accessRightID: return send_update_annc(scl_uri) except AttributeError: return send_update_annc(scl_uri) return send_update_annc(scl_uri, self.api.is_local_path( resource.accessRightID)) def send_update_annc(scl_uri, local_ar=False): endpoint = self.api.get_mid_uri(urlparse(scl_uri).scheme) annc = annc_model() # link hast to be set annc.link = urljoin(endpoint, resource.path) # * searchStrings from the original resource; annc.searchStrings = resource.searchStrings # * accessRightID from the original resource; if local_ar: annc.accessRightID = urljoin(endpoint, urlparse( resource.accessRightID).path) else: annc.accessRightID = resource.accessRightID # * expirationTime handling is to the discretion of the SCL # implementation. It is the responsibility of the local SCL to # keep the announced resource in sync with the lifetime of the # original resource, as long as the announcement is active. One # strategy to minimize signalling would be to request the same # expiration from the original resource. If this is accepted by # the remote SCL, then no explicit de-announce is needed in case # of expiration of the original resource; annc.expirationTime = resource.expirationTime update_req_ind = UpdateRequestIndication( uris[scl_uri], annc, requestingEntity=endpoint) # todo investigate response for not accepted expirationTime return self.api.send_request_indication(update_req_ind) old_resource.searchStrings = resource.searchStrings try: old_resource.accessRightID = resource.accessRightID except AttributeError: pass old_resource.expirationTime = resource.expirationTime scl_list = resource.announceTo.sclList # TODO: conversion to set() is questionable update_list = [x for x in scl_list if x not in set(add_list)] return async_all(map(send_update_annc_pre, update_list)) return None
def send_anncs(scl_list): # i) For each unsuccessful # createXXXAnnouncementResourceResponseIndication, the remote SCL is # removed from the sclList in the announceTo attribute. def handle_create_err(res): return res.scl_uri # ii) For each successful # createXXXAnnouncementResourceResponseIndication, the local SCL # shall internally store the resourceURI of the created announced # resource. This URI is needed for delete the resource later on. def handle_create(res): if isinstance(res.res_con, ErrorResponse): return handle_create_err(res) self._announcements[resource.path]['uris'][ res.scl_uri] = res.res_con.resourceURI return False # iii) For each unsuccessful # deleteXXXAnnouncementResourceRequestIndication with the statusCode # STATUS_NOT_FOUND, the remote SCL is removed from the sclList in # the announceTo attribute. # For all other statusCode value, no action is performed. def handle_delete_err(res): try: if res.res_con.statusCode != 'STATUS_NOT_FOUND': return res.scl_uri finally: del self._announcements[resource.path]['uris'][res.scl_uri] return False # iv) For each successful # deleteXXXAnnouncementResourceRequestIndication, the remote SCL is # removed from the sclList in the announceTo attribute. def handle_delete(res): if isinstance(res.res_con, ErrorResponse): return handle_delete_err(res) del self._announcements[resource.path]['uris'][res.scl_uri] return False create_list = [x for x in scl_list if x not in set(old_scl_list)] delete_list = [x for x in old_scl_list if x not in set(scl_list)] filtered_scls = [x for x in db_scl_list if x not in set(scl_list)] # links the send funcs with the handle result funcs create_func = lambda s: send_create_annc_pre(s).then( lambda r: handle_create(AnncResult(s, r)), lambda r: handle_create_err(AnncResult(s, r))) delete_func = lambda s: send_delete_annc(s).then( lambda r: handle_delete(AnncResult(s, r)), lambda r: handle_delete_err(AnncResult(s, r))) # filters out all False in the list def filter_func(l): return filter(None, l) return async_all([ (async_all(map(create_func, create_list)).then(filter_func) .then(lambda l: l + filtered_scls)), async_all(map(delete_func, delete_list)).then(filter_func) ])
def start_plugins(): logger.info("Starting plugins") async_all([plugin.start() for plugin in _plugins]).get()
def init_plugins(): logger.info("Initializing plugins") async_all([plugin.initialize() for plugin in _plugins]).get()
def _update_announcements(self, resource, add_list): old_resource = self._announcements[resource.path]['resource'] uris = self._announcements[resource.path]['uris'] attributes_changed = False try: if resource.expirationTime != old_resource.expirationTime or \ resource.labels != old_resource.labels or \ resource.accessRightID != old_resource.accessRightID: attributes_changed = True except AttributeError: if resource.expirationTime != old_resource.expirationTime or \ resource.labels != old_resource.labels: attributes_changed = True if attributes_changed: annc_model = get_onem2m_type(resource.typename + "Annc") def send_update_annc_pre(cse_uri): # TODO_oneM2M: Needs updating try: if not resource.accessRightID: return send_update_annc(cse_uri) except AttributeError: return send_update_annc(cse_uri) return self.api.is_local_path(resource.accessRightID) \ .then(lambda local_ar: send_update_annc(cse_uri, local_ar)) def send_update_annc(cse_uri, local_ar=None): # TODO_oneM2M: Update to oneM2M # endpoint = self.api.get_endpoint('mid', # urlparse(cse_uri).scheme) endpoint = self.config.get('endpoint', '') annc = annc_model() # link hast to be set annc.link = urljoin(endpoint, resource.path) # * labels from the original resource; annc.labels = resource.labels # * accessRightID from the original resource; if local_ar: annc.accessRightID = urljoin(endpoint, urlparse( resource.accessRightID).path) elif local_ar is None: annc.accessRightID = local_ar else: annc.accessRightID = resource.accessRightID # * expirationTime handling is to the discretion of the CSE # implementation. It is the responsibility of the local CSE to # keep the announced resource in sync with the lifetime of the # original resource, as long as the announcement is active. One # strategy to minimize signalling would be to request the same # expiration from the original resource. If this is accepted by # the remote CSE, then no explicit de-announce is needed in case # of expiration of the original resource; annc.expirationTime = resource.expirationTime update_req_ind = UpdateRequestIndication(uris[cse_uri], annc) # todo investigate response for not accepted expirationTime return self.api.send_request_indication(update_req_ind) old_resource.labels = resource.labels try: old_resource.accessRightID = resource.accessRightID except AttributeError: pass old_resource.expirationTime = resource.expirationTime cse_list = resource.announceTo # .get('cseList', {}).get('reference') # TODO: conversion to set() is questionable update_list = [x for x in cse_list if x not in set(add_list)] return async_all(map(send_update_annc_pre, update_list)) self.logger.debug('No attributes changed, returning None') return None