def parse_command(self, name) -> Dict: """ parse command from name part of packet :param name: name part of packet :type name: FormalName :return: Dict {(command, dataname, seq} """ # assume following name # /prefix/opcode/dataname/params-sha256 # convert FormalName to NonStrictName str_name = Name.to_str(name) # remove params-sha256 for Application Parameter oname = str_name.split("/params-sha256")[0] # split name part parts = oname.split("/")[1:] # check prefix command = "ERROR" cmd_list = list(PSKCmd.commands.values()) if Name.is_prefix(self.net_name, oname): nname_cnt = len(self.net_name.split('/')[1:]) if parts[nname_cnt] in cmd_list: command = parts[nname_cnt] d_begin = nname_cnt + 1 else: command = parts[1] d_begin = 2 elif Name.is_prefix(self.bro_name, oname): bname_cnt = len(self.bro_name.split('/')[1:]) if parts[bname_cnt] in list(PSKCmd.commands.values()): command = parts[bname_cnt] d_begin = bname_cnt + 1 else: command = parts[1] d_begin = 2 seq = None wseq = 0 # last index is sequence no. if command == PSKCmd.commands["CMD_PD"] or command == PSKCmd.commands[ "CMD_SD"]: seq = parts[len(parts) - 1] wseq = 1 # make dataname datas = parts[d_begin:(len(parts) - wseq)] dataname = "/" + "/".join(datas) # replace %xx escapes by their single-character equivalent udataname = urllib.parse.unquote(dataname) # if seq is Null, OK? return {"command": command, "dataname": udataname, "seq": seq}
def test_is_prefix(): assert Name.is_prefix(Name.from_str('/'), Name.from_str('/')) assert Name.is_prefix(Name.from_str('/'), Name.from_str('/3=D')) assert Name.is_prefix(Name.from_str('/'), Name.from_str('/F')) assert Name.is_prefix(Name.from_str('/'), Name.from_str('/21426=AA')) assert Name.is_prefix(Name.from_str('/B'), Name.from_str('/B')) assert Name.is_prefix(Name.from_str('/B'), Name.from_str('/B/3=D')) assert Name.is_prefix(Name.from_str('/B'), Name.from_str('/B/F')) assert Name.is_prefix(Name.from_str('/B'), Name.from_str('/B/21426=AA')) assert not Name.is_prefix(Name.from_str('/C'), Name.from_str('/')) assert not Name.is_prefix(Name.from_str('/C'), Name.from_str('/3=D')) assert not Name.is_prefix(Name.from_str('/C'), Name.from_str('/F')) assert not Name.is_prefix(Name.from_str('/C'), Name.from_str('/21426=AA'))
async def _process_insert(self, cmd_param: RepoCommandParameter): """ Process segmented insertion command. Return to client with status code 100 immediately, and then start data fetching process. """ try: name = cmd_param.name start_block_id = cmd_param.start_block_id end_block_id = cmd_param.end_block_id process_id = cmd_param.process_id if cmd_param.register_prefix: register_prefix = cmd_param.register_prefix.name else: register_prefix = None # support only 1 forwarding hint now if cmd_param.forwarding_hint and cmd_param.forwarding_hint.name: forwarding_hint = [(0x0, cmd_param.forwarding_hint.name)] else: forwarding_hint = None check_prefix = cmd_param.check_prefix.name except AttributeError: return logging.info( f'Write handle processing insert command: {Name.to_str(name)}, {start_block_id}, {end_block_id}' ) # rejects any data that overlaps with repo's own namespace if Name.is_prefix(self.prefix, name) or Name.is_prefix( name, self.prefix): logging.warning('Inserted data name overlaps with repo prefix') return elif self.normalize_params_or_reject(cmd_param) == False: logging.warning('Insert command malformed') return # Reply to client with status code 100 self.m_process_id_to_status[process_id] = RepoCommandResponse() self.m_process_id_to_status[process_id].process_id = process_id self.m_process_id_to_status[process_id].insert_num = 0 self.m_process_id_to_check_prefix[process_id] = check_prefix # Remember the prefixes to register if register_prefix: is_existing = CommandHandle.add_registered_prefix_in_storage( self.storage, register_prefix) # If repo does not register root prefix, the client tells repo what to register if not self.register_root and not is_existing: self.m_read_handle.listen(register_prefix) # Remember the files inserted, this is useful for enumerating all inserted files CommandHandle.add_inserted_filename_in_storage(self.storage, name) # Start data fetching process self.m_process_id_to_status[process_id].status_code = 300 insert_num = 0 is_success = False if start_block_id != None: # Fetch data packets with block ids appended to the end insert_num = await self.fetch_segmented_data( name, start_block_id, end_block_id, forwarding_hint) if end_block_id is None or start_block_id + insert_num - 1 == end_block_id: is_success = True else: # Both start_block_id and end_block_id are None, fetch a single data packet insert_num = await self.fetch_single_data(name, forwarding_hint) if insert_num == 1: is_success = True if is_success: self.m_process_id_to_status[process_id].status_code = 200 logging.info( 'Insertion success, {} items inserted'.format(insert_num)) else: self.m_process_id_to_status[process_id].status_code = 400 logging.info( 'Insertion failure, {} items inserted'.format(insert_num)) self.m_process_id_to_status[process_id].insert_num = insert_num # Delete process state after some time await self._delete_process_state_after(process_id, 60)
async def _process_insert(self, cmd_param: RepoCommandParameter): """ Process segmented insertion command. Return to client with status code 100 immediately, and then start data fetching process. """ name = cmd_param.name start_block_id = cmd_param.start_block_id end_block_id = cmd_param.end_block_id process_id = cmd_param.process_id register_prefix = cmd_param.register_prefix logging.info( f'Write handle processing insert command: {Name.to_str(name)}, {start_block_id}, {end_block_id}' ) # rejects any data that overlaps with repo's own namespace if Name.is_prefix(self.prefix, name) or Name.is_prefix( name, self.prefix): logging.warning('Inserted data name overlaps with repo prefix') return elif self.is_valid_param(cmd_param) == False: logging.warning( 'Insert command malformed: only end_block_id is specified') return # Reply to client with status code 100 self.m_processes[process_id] = RepoCommandResponse() self.m_processes[process_id].process_id = process_id self.m_processes[process_id].insert_num = 0 # If repo does not register root prefix, the client tells repo what to register if not self.register_root: if not CommandHandle.add_prefixes_in_storage( self.storage, register_prefix): self.m_read_handle.listen(register_prefix) # Start data fetching process self.m_processes[process_id].status_code = 300 insert_num = 0 is_success = False if start_block_id != None: # Fetch data packets with block ids appended to the end insert_num = await self.fetch_segmented_data( name, start_block_id, end_block_id) if end_block_id is None or start_block_id + insert_num - 1 == end_block_id: is_success = True else: # Both start_block_id and end_block_id are None, fetch a single data packet insert_num = await self.fetch_single_data(name) if insert_num == 1: is_success = True if is_success: self.m_processes[process_id].status_code = 200 logging.info( 'Insertion success, {} items inserted'.format(insert_num)) #$ Trigger an Catalog Add Command else: self.m_processes[process_id].status_code = 400 logging.info( 'Insertion failure, {} items inserted'.format(insert_num)) self.m_processes[process_id].insert_num = insert_num # Delete process state after some time await self.schedule_delete_process(process_id)
async def insert_file(self, file_path: str, name_at_repo: NonStrictName, segment_size: int, freshness_period: int, cpu_count: int, forwarding_hint: Optional[NonStrictName] = None, register_prefix: Optional[NonStrictName] = None, check_prefix: Optional[NonStrictName] = None) -> 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. :param forwarding_hint: NonStrictName. The forwarding hint the repo uses when fetching data. :param register_prefix: NonStrictName. If repo is configured with ``register_root=False``,\ it registers ``register_prefix`` after receiving the insertion command. :param check_prefix: NonStrictName. The repo will publish process check messages under\ ``<check_prefix>/check``. It is necessary to specify this value in the param, instead\ of using a predefined prefix, to make sure the subscriber can register this prefix\ under the NDN prefix registration security model. If not specified, default value is\ the client prefix. :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[Name.to_str(name_at_repo)]) if num_packets == 0: return 0 # If the uploaded file has the client's name as prefix, set an interest filter # for handling corresponding Interests from the repo if Name.is_prefix(self.prefix, name_at_repo): self.app.set_interest_filter(name_at_repo, self._on_interest) else: # Otherwise, register the file name as prefix for responding interests from the repo logging.info( f'Register prefix for file upload: {Name.to_str(name_at_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.forwarding_hint = ForwardingHint() cmd_param.forwarding_hint.name = forwarding_hint cmd_param.start_block_id = 0 cmd_param.end_block_id = num_packets - 1 process_id = os.urandom(4) cmd_param.process_id = process_id cmd_param.register_prefix = RegisterPrefix() cmd_param.register_prefix.name = register_prefix if check_prefix == None: check_prefix = self.prefix cmd_param.check_prefix = CheckPrefix() cmd_param.check_prefix.name = check_prefix cmd_param_bytes = cmd_param.encode() # publish msg to repo's insert topic await self.pb.wait_for_ready() is_success = await self.pb.publish(self.repo_name + ['insert'], cmd_param_bytes) if is_success: logging.info( 'Published an insert msg and was acknowledged by a subscriber') else: logging.info( 'Published an insert msg but was not acknowledged by a subscriber' ) # wait until finish so that repo can finish fetching the data insert_num = 0 if is_success: insert_num = await self._wait_for_finish(check_prefix, process_id) return insert_num