def make_subdata_cmd(self, prefix, dataname, seq, lifetime=None, subinfo: SubInfo = None) -> (str, Any): """ make subdata command :param prefix: datarn_prefix :type prefix: str :param dataname: dataname :type dataname: str :param seq: sequence no. :type seq: int :param subinfo: subinfo :type subinfo: SubInfo :return: command, interest_param, app_param """ # make a subdatareq command name with args #command = Name.to_str(prefix + "/" + CMD_SUBDATAREQ + dataname + f'/{seq:d}') command = prefix + "/" + PSKCmd.commands[ "CMD_SD"] + dataname + "/" + str(seq) # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = (lifetime if lifetime else INT_LT_10) # make a app_params for subscription param = PSKParameters(subinfo=subinfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def make_irdel_cmd(self, prefix, dataname, rawpacket: BinaryStr = None) -> (str, Any): """ make irdel command :param prefix: ir_prefix :type prefix: str :param dataname: dataname :type dataname: str :param rawpacket: raw interest packet :type bytes: :return: command, interest_param, app_param """ # make a irmod command name with args command = prefix + "/" + PSKCmd.commands["CMD_MD"] + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_4 # make app_param for Infomation Registry (raw interest packet) str_rawpacket = rawpacket.decode('utf-8') param = PSKParameters(rawpacket=str_rawpacket) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def make_pubdata_cmd(self, prefix, dataname, seq, pubdatainfo: PubDataInfo = None) -> (str, Any): """ make pubdata command :param prefix: network_prefix :type prefix: str :param dataname: dataname for publishing data :type dataname: str :param seq: sequence no. :type seq: int :param pubed_data: pubed data :type pubed_data: any :return: command, interest_param, app_param """ # make a pubdata command name with args command = prefix + "/" + PSKCmd.commands[ "CMD_PD"] + dataname + '/' + str(seq) # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_4 param = PSKParameters(pubdatainfo=pubdatainfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def make_subtopic_cmd(self, prefix, dataname, subinfo: SubInfo = None) -> (str, Any): """ make subtopic command :param prefix: network_prefix or topicrn_prefix :type prefix: str :param dataname: topic name :type dataname: str :param subinfo: subscription information :type subinfo: SubInfo :return: command, interest_param, app_param """ # make a subtopic command name with args command = prefix + "/" + PSKCmd.commands["CMD_ST"] + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_10 # make a app_params for subscription param = PSKParameters(subinfo=subinfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def make_pubadv_cmd(self, prefix: str, dataname: str, pubadvinfo: PubAdvInfo = None, irinfo: IRInfo = None, rninfo: RNInfo = None) -> (str, Any): """ make pubadv command :param prefix: network_prefix or broker_prefix :type prefix: str :param dataname: dataname for publishing data :type dataname: str :param pubinfo: pubadvinfo :type pubinfo: PubAdvInfo :param irinfo: irinfo :type irinfo: IRInfo :param rninfo: rninfo :type rninfo: RNInfo :return: command, interest_param, app_param """ # make a pubadv command name with args #command = Name.to_str(prefix + "/" + CMD_PUBADV + dataname) command = prefix + "/" + PSKCmd.commands["CMD_PA"] + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_10 param = PSKParameters(pubadvinfo=pubadvinfo, irinfo=irinfo, rninfo=rninfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
async def add(self, data_name: str, hash: str, desired_copies: int = 3): try: sql_command = "INSERT INTO data (data_name, hash, desired_copies) VALUES ({0}, {1}, {2});".format( data_name, hash, desired_copies) name = self.catalog_prefix + "/" + sql_command + "/" + str( gen_nonce()) data_name, meta_info, content = await self.app.express_interest( name, must_be_fresh=True, can_be_prefix=False, lifetime=1000) print(f'Received Data Name: {Name.to_str(data_name)}') print(meta_info) print(bytes(content) if content else None) except InterestNack as e: # A NACK is received print(f'Nacked with reason={e.reason}') except InterestTimeout: # Interest times out print(f'Timeout') except InterestCanceled: # Connection to NFD is broken print(f'Canceled') except ValidationFailure: # Validation failure print(f'Data failed to validate') finally: self.app.shutdown()
async def _check(self, repo_name: str, catalog_name: str, method: str): cmd_param = CatalogRequestParameter() cmd_param.data_name = 'data1' cmd_param_bytes = cmd_param.encode() name = Name.from_str(catalog_name) name += [method] name += [str(gen_nonce())] try: _, _, data_bytes = await self.app.express_interest( name, app_param=cmd_param_bytes, must_be_fresh=True, can_be_prefix=False, lifetime=10000) data_recvd = bytes(data_bytes) assert bytes(repo_name) == data_recvd except InterestNack: print(">>>NACK") return None except InterestTimeout: print(">>>TIMEOUT") return None finally: app.shutdown()
def make_generic_cmd(self, command: str, prefix: str, dataname: str = "/_", pubadvinfo: PubAdvInfo = None, irinfo: IRInfo = None, rninfo: RNInfo = None, **kwargs) -> (str, Any): """ make generic command :param prefix: network_prefix or broker_prefix :type prefix: str :param dataname: dataname for publishing data :type dataname: str :param pubinfo: pubadvinfo :type pubinfo: PubAdvInfo :param irinfo: irinfo :type irinfo: IRInfo :param rninfo: rninfo :type rninfo: RNInfo :return: command, interest_param, app_param """ command = prefix + "/" + command + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_10 param = PSKParameters(pubadvinfo=pubadvinfo, irinfo=irinfo, rninfo=rninfo, **kwargs) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
async def delete_file(self, prefix: NonStrictName, start_block_id: int = None, end_block_id: int = None) -> int: """ Delete from repo packets between "<name_at_repo>/<start_block_id>" and\ "<name_at_repo>/<end_block_id>" inclusively. :param prefix: NonStrictName. The name of the file stored in the remote repo. :param start_block_id: int. Default value is 0. :param end_block_id: int. If not specified, repo will attempt to delete all data packets\ with segment number starting from `start_block_id` continously. :return: Number of deleted packets. """ # send command interest cmd_param = RepoCommandParameter() cmd_param.name = prefix cmd_param.start_block_id = start_block_id cmd_param.end_block_id = end_block_id cmd_param.register_prefix = prefix process_id = gen_nonce() cmd_param.process_id = process_id cmd_param_bytes = cmd_param.encode() # publish msg to repo's delete topic await self.pb.wait_for_ready() self.pb.publish(self.repo_name + ['delete'], cmd_param_bytes) # wait until repo delete all data return await self._wait_for_finish(process_id)
async def send(app: NDNApp, name: FormalName): logging.info('Interest Sent: {}'.format(Name.to_str(name))) try: data_name, meta_info, content = await app.express_interest( name, must_be_fresh=True, can_be_prefix=False, nonce=gen_nonce(), lifetime=1000) # Print out Data Name, MetaInfo and its conetnt. logging.info('Data Received: {}'.format(Name.to_str(data_name))) except InterestNack as e: # A NACK is received logging.warning(f'Interest Nacked with reason={e.reason}\n') except InterestTimeout: # Interest times out logging.warning(f'Interest Timeout\n') finally: app.shutdown()
async def insert_file(self, file_path: str, name_at_repo: NonStrictName, segment_size: int, freshness_period: int, cpu_count: int) -> int: """ Insert a file to remote repo. :param file_path: Local FS path to file to insert. :param name_at_repo: NonStrictName. Name used to store file at repo. :param segment_size: Max size of data packets. :param freshness_period: Freshness of data packets. :param cpu_count: Cores used for converting file to TLV format. :return: Number of packets inserted. """ self._prepare_data(file_path, name_at_repo, segment_size, freshness_period, cpu_count) num_packets = len(self.encoded_packets) if num_packets == 0: return # Register prefix for responding interests from repo await self.app.register(name_at_repo, self._on_interest) # construct insert cmd msg cmd_param = RepoCommandParameter() cmd_param.name = name_at_repo cmd_param.start_block_id = 0 cmd_param.end_block_id = num_packets - 1 cmd_param.register_prefix = name_at_repo process_id = gen_nonce() cmd_param.process_id = process_id cmd_param_bytes = cmd_param.encode() # publish msg to repo's insert topic await self.pb.wait_for_ready() self.pb.publish(self.repo_name + ['insert'], cmd_param_bytes) logging.info('published an insert msg') # wait until finish so that repo can finish fetching the data return await self._wait_for_finish(process_id)
async def _check(self, method: str, catalog_name: str): cmd_param = CatalogCommandParameter() cmd_param.repo_name = self.prefix cmd_param_bytes = cmd_param.encode() name = Name.from_str(catalog_name) name += [method] name += [str(gen_nonce())] print(">>>>>>>>>", Name.to_str(name)) try: _, _, data_bytes = await self.app.express_interest( name, app_param=cmd_param_bytes, must_be_fresh=True, can_be_prefix=True) print(">>> ACK RECVD: ", bytes(data_bytes)) except InterestNack: print(">>>NACK") return None except InterestTimeout: print(">>>TIMEOUT") return None
async def _publish_helper(self, topic: NonStrictName, msg: bytes): """ Async helper for `subscribe()``. """ logging.info(f'publishing a message to topic: {Name.to_str(topic)}') # generate a nonce for each message nonce = gen_nonce() self.nonce_to_msg[nonce] = msg # prepare notify interest int_name = topic + ['notify'] app_param = PubSub.NotifyAppParam() app_param.publisher_prefix = self.prefix app_param.nonce = nonce if self.forwarding_hint: app_param.forwarding_hint = self.forwarding_hint aio.ensure_future(self._erase_state_after(nonce, 5)) # express notify interest try: logging.debug(f'sending notify interest: {Name.to_str(int_name)}') data_name, meta_info, content = await self.app.express_interest( int_name, app_param.encode(), must_be_fresh=False, can_be_prefix=False) except InterestNack as e: logging.debug(f'Nacked with reason: {e.reason}') return except InterestTimeout: logging.debug(f'Timeout') return # if receiving notify response, the subscriber has finished fetching msg logging.debug(f'received notify response: {data_name}') await self._erase_state_after(nonce, 0)
async def run(self): await aio.sleep(1) # wait for repo to startup # respond to interest from repo def on_int(int_name, _int_param, _app_param): self.app.put_data(int_name, b'foobar', freshness_period=1000) await self.app.register('test_name', on_int) # construct insert parameter cmd_param = RepoCommandParameter() cmd_param.name = 'test_name' cmd_param.start_block_id = None cmd_param.end_block_id = None process_id = gen_nonce() cmd_param.process_id = process_id cmd_param_bytes = cmd_param.encode() pb = PubSub(self.app, Name.from_str('/putfile_client')) await pb.wait_for_ready() pb.publish(Name.from_str(repo_name) + ['insert'], cmd_param_bytes) # insert_num should be 1 checker = CommandChecker(self.app) n_retries = 3 while n_retries > 0: response = await checker.check_insert(Name.from_str(repo_name), process_id) if response.status_code == 404: n_retries -= 1 elif response.status_code != 300: assert response.status_code == 200 assert response.insert_num == 1 break await aio.sleep(1) self.app.shutdown()
def make_pubunadv_cmd(self, prefix, dataname, pubadvinfo: PubAdvInfo = None) -> (str, Any): """ make pubunadv command :param prefix: network_prefix or broker_prefix :type prefix: str :param dataname: dataname for unpublishing data :type dataname: str :param pubadvinfo: pub information :type pubadvinfo: :return: command, interest_param, app_param """ # make a pubunadv command name with args command = prefix + "/" + PSKCmd.commands["CMD_PU"] + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_10 param = PSKParameters(pubadvinfo=pubadvinfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
async def send_repo_command(self, node_prefix : NonStrictName, verb : str , datainfo : DatainfoTlvModel): # "/a/b" -> list of bytearrays name = Name.normalize(node_prefix) # "/a/b" -> "/a/b/insert" name.append(Component.from_str(verb)) datainfo_name_component = Component.from_bytes(datainfo.encode()) name.append(datainfo_name_component) logging.info('Interest Sent: {}'.format(Name.to_str(name))) try: data_name, meta_info, content = await self.app.express_interest(name, must_be_fresh=True, can_be_prefix=False, nonce=gen_nonce(), lifetime=1000) logging.info('Data Received: {}\n'.format(Name.to_str(data_name))) # print(meta_info) # print(bytes(content) if content else None) except InterestNack as e: # A NACK is received logging.warning(f'Interest Nacked with reason={e.reason}\n') return 0 except InterestTimeout: # Interest times out logging.warning(f'Interest Timeout\n') return 0 # results = self.parse_results(content) # logging.info(results) return 1
def express_interest( self, name: NonStrictName, app_param: Optional[BinaryStr] = None, validator: Optional[Validator] = None, need_raw_packet: bool = False, **kwargs ) -> Coroutine[Any, None, Tuple[FormalName, MetaInfo, Optional[BinaryStr]]]: r""" Express an Interest packet. The Interest packet is sent immediately and a coroutine used to get the result is returned. Awaiting on what is returned will block until the Data is received and return that Data. An exception is raised if unable to receive the Data. :param name: the Name. :type name: :any:`NonStrictName` :param app_param: the ApplicationParameters. :type app_param: Optional[:any:`BinaryStr`] :param validator: the Validator used to verify the Data received. :type validator: Optional[:any:`Validator`] :param need_raw_packet: if True, return the raw Data packet with TL. :type need_raw_packet: bool :param kwargs: :ref:`label-keyword-arguments`. :return: A tuple of (Name, MetaInfo, Content) after ``await``. If need_raw_packet is True, return a tuple (Name, MetaInfo, Content, RawPacket). :rtype: Coroutine[Any, None, Tuple[:any:`FormalName`, :any:`MetaInfo`, Optional[:any:`BinaryStr`]]] The following exception is raised by ``express_interest``: :raises NetworkError: the face to NFD is down before sending this Interest. The following exceptions are raised by the coroutine returned: :raises InterestNack: an NetworkNack is received. :raises InterestTimeout: time out. :raises ValidationFailure: unable to validate the Data packet. :raises InterestCanceled: the face to NFD is shut down after sending this Interest. """ if not self.face.running: raise NetworkError('cannot send packet before connected') if 'signer' in kwargs: signer = kwargs['signer'] elif app_param is not None: signer = self.keychain.get_signer(kwargs) else: signer = None if 'interest_param' in kwargs: interest_param = kwargs['interest_param'] else: if 'nonce' not in kwargs: kwargs['nonce'] = gen_nonce() interest_param = InterestParam.from_dict(kwargs) interest, final_name = make_interest(name, interest_param, app_param, signer=signer, need_final_name=True) future = aio.get_event_loop().create_future() node = self._int_tree.setdefault(final_name, InterestTreeNode()) node.append_interest(future, interest_param) self.face.send(interest) return self._wait_for_data(future, interest_param.lifetime, final_name, node, validator, need_raw_packet)