def delete_dataset(self, dataset_hash): """ Remove one dataset from the scene. Args: dataset_hash: The unique identifier for the dataset we want to delete. Returns: list: The remaining datasets in the scene. Raises: TypeError: If ``type(dataset_hash)`` is not `str`. ValueError: If `dataset_hash` does not fit any dataset in the scene. """ if not isinstance(dataset_hash, str): raise TypeError('dataset_hash is {}, expected str'.format( type(dataset_hash).__name__)) try: self._dataset_list.pop(dataset_hash) # Delegate returning of the remainder to the standard method return self.list_datasets() except KeyError as e: bl.debug_warning( 'dataset_hash does not fit any dataset in scene: {}'.format(e)) raise ValueError('dataset_hash does not fit any dataset in scene')
def dataset(self, dataset_hash): """ Return a dataset object for working with. Args: dataset_hash: The unique identifier for the dataset we want to access. Returns: _DatasetPrototype: The dataset that we want to access. Raises: TypeError: If ``type(dataset_hash)`` is not `str`. """ if not isinstance(dataset_hash, str): raise TypeError('dataset_hash is {}, expected str'.format( type(dataset_hash).__name__)) try: # Return the object return self._dataset_list[dataset_hash] except KeyError as e: bl.debug_warning( 'dataset_hash does not fit any dataset in scene: {}'.format(e)) raise ValueError('dataset_hash does not fit any dataset in scene')
def new_scene(self, dataset_list): """ Create a new scene with an object. This adds a ScenePrototype to `self._scene_list`. Args: dataset_list (list (of str)): The path to the datasets we want to instantiate a new scene with. Returns: None, dict: `None` if no dataset could be added to a new scene and a dict with information what could be added and what not in the case that we could add dataset(s) to a new scene. Raises: TypeError: If ``type(object_path)`` is not `list`. Todo: Make it impossible to create an empty scene. """ # Type checking for dataset_list if not isinstance(dataset_list, list): raise TypeError('dataset_list is {}, expected list'.format( type(dataset_list).__name__)) # Do nothing if the dataset list is empty if len(dataset_list) == 0: return None # See which datasets are valid valid_datasets = [] available_datasets = ( self.list_available_datasets()['availableDatasets']) for dataset in dataset_list: if dataset in available_datasets: valid_datasets.append(dataset) # If there are no valid datasets to be added return None if len(valid_datasets) == 0: return None try: # Get a new instance of a scene new_scene = _ScenePrototype(source_dict=self.source) new_scene_hash = new_scene.name() self._scene_list[new_scene_hash] = new_scene # Here still dataset_list, so we can have a addDatasetFail entry return_dict = self.add_datasets(new_scene_hash, dataset_list) return return_dict except (ValueError, TypeError) as e: bl.debug_warning("Exception when creating new scene: {}".format(e)) return None
def delete_loaded_dataset(self, scene_hash, dataset_hash): """ Remove a dataset from a scene. If all datasets are gone the scene is to be deleted. Args: scene_hash (str): The hash of the scene from which we want to delete a dataset. dataset_hash (str): The hash of the dataset we want to delete. """ if not isinstance(scene_hash, str): raise TypeError('scene_hash is {}, expected str'.format( type(scene_hash).__name__)) if not isinstance(dataset_hash, str): raise TypeError('dataset_hash is {}, expected str'.format( type(dataset_hash).__name__)) # If the scene does not exist if scene_hash not in self._scene_list: return None target_scene = self.scene(scene_hash) try: remaining_datasets = target_scene.delete_dataset(dataset_hash) except ValueError as e: bl.debug_warning( "Exception in delete_loaded_dataset: {}".format(e)) # The dataset does not exist return None # If there are no more datasets left delete the scene if remaining_datasets == []: self.delete_scene(scene_hash) # We should probably return something else so we can distinguish # between errors and deleted scenes. return None return_dict = { 'datasetDeleted': dataset_hash, 'href': '/scenes/{}'.format(scene_hash) } return return_dict
def scene(self, scene_hash): """ Return a scene object. Args: scene_hash (str): The unique identifier of the scene that we want to return. Returns: None or _ScenePrototype object: None if no scene with a matching hash could be found, otherwise return the scene object. Raises: TypeError: If ``type(scene_hash)`` is not `str`. See Also: :py:class:`backend.scenes_scene_prototype._ScenePrototype` """ if not isinstance(scene_hash, str): raise TypeError('scene_hash is {}, expected str'.format( type(scene_hash).__name__)) try: # See which index fits to the provided scene id index = list(self._scene_list.keys()).index(scene_hash) # Get all the scene objects out of the _scene_list scenes = list(self._scene_list.values()) return scenes[index] except ValueError as e: bl.debug_warning("Scene with hash {} not found: {}".format( scene_hash, e)) return None
def timestep_data(self, timestep, field, elementset, hash_dict=None): """ Return the data for a given timestep and field and save it. Args: timestep (str): The timestep from which we want to get data. field (dict): The field from which we want to get data. Structure is {'type': TYPE (str), 'name': NAME (str)}. elementset (dict): The elementset we want to parse. Can be empty. If empty we just parse everything. hash_dict (bool, optional, defaults to False): Read the data again, even if we already have data corresponding to the selected timestep and field. Has fields 'mesh' and 'field'. Returns: dict or None: The data for the timestep or None, if the field could not be found. """ return_dict = { 'hash_dict': { 'mesh': None, 'field': None }, 'nodes': { 'data': None }, 'tets': { 'data': None }, 'nodes_center': None, 'field': { 'data': None }, 'wireframe': { 'data': None }, 'free_edges': { 'data': None } } try: mesh_dict = self._geometry_data(timestep, field, elementset, current_hash=hash_dict['mesh']) except (TypeError, KeyError) as e: bl.debug_warning("No mesh for given hash_dict found: {}".format(e)) mesh_dict = self._geometry_data(timestep, field, elementset, current_hash=None) if field is not None: try: field_dict = self._field_data(timestep, field, elementset, current_hash=hash_dict['field']) except (TypeError, KeyError) as e: bl.debug_warning( "No field for given hash_dict found: {}".format(e)) field_dict = self._field_data(timestep, field, elementset, current_hash=None) else: # Corner case for unsetting the fields once they were set field_dict = None # no field_dict means we are showing a blank field if field_dict is None: field_type = 'nodal' else: field_type = field_dict['type'] return_dict['hash_dict']['mesh'] = mesh_dict['hash'] mesh_nodes = mesh_dict['nodes'] mesh_elements = mesh_dict['elements'] mesh_skins = mesh_dict["skins"] return_object_keys = mesh_dict[ "object_key_list"] # gets modified later if mesh_elements is not None: self._mesh_elements = mesh_elements if mesh_nodes is not None: elementset_data = self._elementset_data(elementset) self._compressed_model_surface = dm.model_surface( mesh_elements, mesh_nodes, mesh_skins, elementset_data) self._nodal_field_map_dict[mesh_dict[ 'hash']] = self._compressed_model_surface['nodal_field_map'] self._blank_field_node_count_dict[mesh_dict[ 'hash']] = self._compressed_model_surface['old_max_node_index'] self._surface_triangulation_dict[ mesh_dict['hash']] = self._compressed_model_surface[ 'surface_triangulation'] return_dict['nodes'] = self._compressed_model_surface['nodes'] return_dict['nodes_center'] = self._compressed_model_surface[ 'nodes_center'] return_dict['tets'] = self._compressed_model_surface['triangles'] return_dict['wireframe'] = self._compressed_model_surface[ 'wireframe'] return_dict['free_edges'] = self._compressed_model_surface[ 'free_edges'] # field does not exist if field_dict is None: node_count = self._blank_field_node_count_dict[mesh_dict['hash']] field_values = self._blank_field(node_count)['data']['nodal'] # this is necessary so we parse a new field when we need it field_hash = None field_hash = self._string_hash(str(node_count), update=field_hash) # update the mesh hash with the selected elementset if self.source_type == 'local': for element_type in elementset: # add every elementset elementset_path = elementset[element_type] field_hash = self._file_hash(elementset_path, update=field_hash) if self.source_type == 'external': for element_type in elementset: # add every elementset elementset_sha1 = elementset[element_type]['sha1sum'] field_hash = self._string_hash(elementset_sha1, update=field_hash) return_dict['hash_dict']['field'] = field_hash # field dict is not None else: return_object_keys += field_dict["object_key_list"] if field_type == 'nodal': field_values = field_dict['data']['nodal'] if field_type == 'elemental': elemental_field_dict = field_dict['data']['elemental'] field_values = dm.expand_elemental_fields( elemental_field_dict, self._mesh_elements, self._surface_triangulation_dict[mesh_dict['hash']]) return_dict['hash_dict']['field'] = field_dict['hash'] if field_values is not None: if field_type == 'nodal': return_dict['field'] = dm.model_surface_fields_nodal( self._nodal_field_map_dict[mesh_dict['hash']], field_values) if field_type == 'elemental': return_dict['field'] = dm.model_surface_fields_elemental( field_values) return_dict["object_key_list"] = return_object_keys return return_dict
def _geometry_data_external(self, timestep, field, elementset, current_hash=list()): """ Get data from the gateway. Procedure is as follows: * try to calculate the hash from the index (in fixed order) * if this fails (e.g. a single hash is missing) we download every file from the gateway * if this succeeds and the hash is identical to current_hash return None -> no action necessary * if this succeeds and the hash is NOT identical to current_hash we download every file from the gateway * we downloaded all files -> calculate the hash (in fixed order) * if the hash is identical to current_hash return None -> no action necessary * if the hash is NOT identical to current_hash return downloaded data Fixed order for hash calculation is (if existent) * nodes * elements (sorted by dictionary) * skins (sorted by dictionary) We don't download elementsets here. """ return_dict = dict() # This is so dumb. import backend.global_settings as gloset ext_index = gloset.scene_manager.ext_src_dataset_index( update=False, dataset=self._dataset_name) try: dest_field_name = field["name"] except TypeError: dest_field_name = "__no__field__" ta_ma = list(ext_index[self._dataset_name][timestep].keys()) if len(ta_ma) == 1: timestep_dict = ext_index[self._dataset_name][timestep]["ta"] elif "ma" in ta_ma: if dest_field_name in ext_index[ self._dataset_name][timestep]["ma"]: timestep_dict = ext_index[self._dataset_name][timestep]["ma"] else: timestep_dict = ext_index[self._dataset_name][timestep]["ta"] else: timestep_dict = ext_index[self._dataset_name][timestep]["ta"] # parse nodes nodes_key = timestep_dict['nodes']['object_key'] nodes_hash = timestep_dict['nodes']['sha1sum'] nodes_format = binary_formats.nodes() # parse elements elements = {} elements_types = list(timestep_dict['elements'].keys()) for elements_type in elements_types: if elements_type in binary_formats.valid_element_types(): current_elem = timestep_dict['elements'] elements_format = getattr(binary_formats, elements_type)() elements[elements_type] = {} elements[elements_type]['key'] = current_elem[elements_type][ 'object_key'] elements[elements_type]['hash'] = current_elem[elements_type][ 'sha1sum'] elements[elements_type]['fmt'] = elements_format skins = {} try: skin_element_types = list(timestep_dict["skin"].keys()) current_skin = timestep_dict['skin'] skin_format = binary_formats.skin() for element_type in skin_element_types: if element_type in binary_formats.valid_element_types(): skins[element_type] = {} skins[element_type]['key'] = current_skin[element_type][ 'object_key'] skins[element_type]['hash'] = current_skin[element_type][ 'sha1sum'] skins[element_type]['fmt'] = skin_format except KeyError as e: bl.debug_warning("No skins found: {}".format(e)) # calculate the hash if we have the sha1sums in the index, else just # get everything for every timestep hash_list = list() hash_list.append(nodes_hash) for element in elements: hash_list.append(elements[element]['hash']) # for element_type in elementset: # hash_list.append(elementset[element_type]['sha1sum']) for skin in skins: hash_list.append(skins[element_type]['hash']) calc_hashes = True for one_hash in hash_list: if one_hash == "": calc_hashes = False # init to None mesh_checksum = None if calc_hashes: for one_hash in hash_list: mesh_checksum = self._string_hash(one_hash, update=mesh_checksum) object_key_list = [] fmt_list = [] object_key_list.append(nodes_key) fmt_list.append(nodes_format) for element in elements: object_key_list.append(elements[element]['key']) fmt_list.append(elements[element]['fmt']) for skin in skins: object_key_list.append(skins[skin]['key']) fmt_list.append(skins[skin]['fmt']) return_dict["object_key_list"] = object_key_list if (current_hash is list() or mesh_checksum is None or mesh_checksum not in current_hash): # reset mesh checksum mesh_checksum = None geom_dict_data = self._read_binary_data_external( object_key_list, fmt_list) geom_data = list() for d in geom_dict_data: geom_data.append(d["contents"]) mesh_checksum = self._string_hash(d["sha1sum"], update=mesh_checksum) if mesh_checksum in current_hash: return_dict['hash'] = mesh_checksum return_dict['nodes'] = None return_dict['elements'] = None return_dict['skins'] = None return return_dict return_dict['hash'] = mesh_checksum return_dict['nodes'] = {} return_dict['nodes']['fmt'] = nodes_format return_dict['nodes']['data'] = geom_data[0] return_dict['elements'] = {} for it, element in enumerate(elements): element_path = elements[element]['key'] return_dict['elements'][element] = {} return_dict['elements'][element]['fmt'] = elements[element][ 'fmt'] return_dict['elements'][element]['data'] = geom_data[it + 1] return_dict["skins"] = {} for it, skin in enumerate(skins): skin_path = skins[skin]['key'] return_dict["skins"][skin] = {} return_dict["skins"][skin]['fmt'] = skins[skin]['fmt'] return_dict["skins"][skin]['data'] = geom_data[it + 1 + len(elements)] else: return_dict['hash'] = mesh_checksum return_dict['nodes'] = None return_dict['elements'] = None return_dict['skins'] = None return return_dict
def add_datasets(self, scene_hash, dataset_list): """ Add one or multiple dataset(s) to the scene. Args: scene_hash (str): The hash of the scene to which we want to add datasets. dataset_list (list (of str)): The relative path to the object root, relative to `data_dir`. Raises: TypeError: If ``type(scene_hash)`` is not `str`. TypeError: If an entry in `dataset_list` is not `str`. TypeError: If ``type(dataset_list)`` is not `list`. ValueError: If ``len(dataset_list)`` is `0`. Returns: None or dict: None if we could not add any datasets to the scene, or a dict if some or all datasets could be added. Notes: See FIXME in code. """ if not isinstance(scene_hash, str): raise TypeError('scene_hash is {}, expected str'.format( type(scene_hash).__name__)) target_scene = self.scene(scene_hash) if not isinstance(dataset_list, list): raise TypeError('dataset_list is {}, expected list'.format( type(dataset_list).__name__)) if len(dataset_list) == 0: raise ValueError('dataset_list is empty') # Encode the scene hash into the return_dict return_dict = { 'sceneHash': '{}'.format(scene_hash), 'href': '/scenes/{}'.format(scene_hash), 'addDatasetsSuccess': [] } # Add each object for one_dataset in dataset_list: try: if not isinstance(one_dataset, str): raise TypeError('one_dataset is {}, expected str'.format( type(one_dataset).__name__)) dataset_hash = target_scene.add_dataset(one_dataset) dataset_meta = target_scene._dataset_list[dataset_hash].meta() return_dict['addDatasetsSuccess'].append(dataset_meta) self.ext_src_dataset_index(update=True, dataset=one_dataset) # Catch everything that could have gone wrong and just report that # the dataset could not be added. NOTE: This also catches the case # that an entry in the list was not a string, so we might run in to # trouble? But it came from a list, so it can also go back into a # list I guess... Maybe FIXME. except (TypeError, ValueError) as e: bl.debug_warning("Exception when adding dataset {}: {}".format( one_dataset, e)) try: return_dict['addDatasetsFail'].append(one_dataset) except KeyError as f: bl.debug_warning("Further exception: {}".format(e)) return_dict['addDatasetsFail'] = [] return_dict['addDatasetsFail'].append(one_dataset) # If we have nothing to return.. if len(return_dict['addDatasetsSuccess']) == 0: return None else: return return_dict
def elementset_dict(self): """ Get a list of elementsets for the selected timestep. Args: None: No args. Returns: dict: A dict with two lists of elementsets, one for elemental and one for nodal elementsets. Todo: Make this more resilient against non exising directories via try except. """ # results return_dict = {} if self.source_type == 'local': timestep_dir = self.dataset_path / 'fo' / self._selected_timestep elset_names = [] all_elsets = timestep_dir.glob('*.elset.*.bin') elset_groups = [] for elset in all_elsets: filename = elset.parts[-1] elset_name = re.match('(.+)\.elset\.', filename).groups()[0] return_dict[elset_name] = {} elset_names.append(elset_name) for elset_name_key in return_dict: elset_groups.append( timestep_dir.glob('{}.elset.*.bin'.format(elset_name_key))) for elset_group in elset_groups: for elset in elset_group: filename = elset.parts[-1] elset_type = re.search('elset\.(.+)\.bin', filename).groups()[0] elset_name = re.search('(.+)\.elset\.', filename).groups()[0] return_dict[elset_name][elset_type] = elset if self.source_type == 'external': import backend.global_settings as gloset ext_index = gloset.scene_manager.ext_src_dataset_index( update=False, dataset=self.dataset_name) try: return_dict = ext_index[self.dataset_name][ self._selected_timestep]['elset'] except KeyError as e: bl.debug_warning( "KeyError in field_dict (return_dict): {}".format(e)) return_dict = dict() elset_keys = [] for elset_name_key in return_dict: elset_keys.append(elset_name_key) # dummy for parsing it all return_dict['__all__'] = {} elset_keys.append('__all__') # return_dict = {'elementsets': [key1, key2, ...], 'key1': {...}, 'key2': {...}} return_dict['elementsets'] = sorted(elset_keys) return return_dict
def field_dict(self): """ Get a list of fields for the selected timestep. Args: None: No args. Returns: dict: A dict with two lists of fields, one for elemental and one for nodal fields. Todo: Make this more resilient against non exising directories via try except. """ elemental_fields = [] nodal_fields = [] if self.source_type == 'local': timestep_dir = self.dataset_path / 'fo' / self._selected_timestep elemental_field_dir = timestep_dir / 'eo' elemental_field_paths = sorted(elemental_field_dir.glob('*.bin')) for field in elemental_field_paths: elemental_fields.append( field.stem) # just append the file name # cut the element type from the field name try: elemental_fields = [ field.rsplit('.', 1) for field in elemental_fields ] elemental_fields = sorted( np.unique(np.asarray(elemental_fields)[:, 0])) except IndexError as e: bl.debug_warning("IndexError in field_dict: {}".format(e)) raise nodal_field_dir = timestep_dir / 'no' nodal_field_paths = sorted(nodal_field_dir.glob('*.bin')) for field in nodal_field_paths: nodal_fields.append(field.stem) # just append the file name if self.source_type == 'external': import backend.global_settings as gloset ext_index = gloset.scene_manager.ext_src_dataset_index( update=False, dataset=self.dataset_name) timestep_dict = ext_index[self.dataset_name][ self._selected_timestep] # elemental_fields = [] # nodal_fields = [] try: elemental_fields += list( timestep_dict["ta"]['elemental'].keys()) # thermal fields except KeyError as e: bl.debug_warning( "KeyError in thermal field_dict (elemental_fields): {}". format(e)) try: elemental_fields += list( timestep_dict["ma"] ['elemental'].keys()) # mechanical fields except KeyError as e: bl.debug_warning( "KeyError in mechanical field_dict (elemental_fields): {}". format(e)) try: nodal_fields += list( timestep_dict["ta"]['nodal'].keys()) # thermal fields except KeyError as e: bl.debug_warning( "KeyError in thermal field_dict (nodal_fields): {}".format( e)) try: nodal_fields += list( timestep_dict["ma"]['nodal'].keys()) # mechanical fields except KeyError as e: bl.debug_warning( "KeyError in mechanical field_dict (nodal_fields): {}". format(e)) # sorting from... # https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/ # neat. convert = lambda text: int(text) if text.isdigit() else text.lower() alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] return_dict = { 'elemental': sorted(elemental_fields, key=alphanum_key), 'nodal': sorted(nodal_fields, key=alphanum_key) } return return_dict
async def _subscription_crawler_coro(shutdown_event): """ Iterate over all subscriptions and see if the required files are available. """ global LI_LOCK global LOCAL_INDEX global SUBSCRIPTION_DICT global SD_LOCK # done here because of circular import stuff import backend.global_settings as gloset while True: await asyncio.sleep(1) # wait one second with SD_LOCK: for subscription in list(SUBSCRIPTION_DICT.keys()): # make a list so we can modify the original dictionary try: delete = SUBSCRIPTION_DICT[subscription]["delete"] except KeyError: pass else: del SUBSCRIPTION_DICT[subscription] bl.debug("Deleted {} from subscription dict".format(subscription)) with SD_LOCK: for subscription in SUBSCRIPTION_DICT.keys(): bl.debug("Checking subscription {}".format(subscription)) value = SUBSCRIPTION_DICT[subscription] try: _ = value["delete"] bl.debug("Skipping {}, delete flag detected".format(subscription)) except KeyError: bl.debug("Handling subscription {}".format(subscription)) namespace = value["namespace"] scene_hash = value["scene_hash"] dataset_hash = subscription with LI_LOCK: bl.debug("Obtaining available timesteps") avail_timesteps = list(LOCAL_INDEX[namespace].keys()) bl.debug("... found {}".format(len(avail_timesteps))) # sorting from... # https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/ # neat. convert = lambda text: int(text) if text.isdigit() else text.lower() alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] sorted_timesteps = sorted(avail_timesteps, key=alphanum_key) bl.debug("Timesteps sorted") # if current timestep is in sorted_timesteps ... current_timestep = value["dataset_object"].timestep() try: index = sorted_timesteps.index(current_timestep) # index = sorted_timesteps.index(value["timestep"]) bl.debug("Found {} in timestep list at position {}".format(current_timestep, index)) except ValueError: # current timestep is not in list... weird # go back to start of loop bl.debug("Could not find {} in timestep list".format(current_timestep)) continue # check the last and second to last timestep last_timestep = sorted_timesteps[-1] bl.debug("Last timestep is {}".format(last_timestep)) # ... and not the last position if sorted_timesteps[index] == last_timestep: # is last in timestep list, nothing to do bl.debug("Index position {} is the last timestep, no update required".format(index)) continue check_dicts = list() # check if the files we need are in the most recent timestep for object_dict in value["object_dicts"]: target = {namespace: {last_timestep: object_dict}} check_dicts.append(target) data_avail = True with LI_LOCK: for check_dict in check_dicts: bl.debug("Checking for {} in local index".format(check_dict)) avail = ndc.contains(LOCAL_INDEX, check_dict) if not avail: bl.debug_warning("Not found, can't update to most recent timestep") data_avail = False if data_avail: # set the timestep bl.debug("Found all necessary files for most recent timestep") dataset_timesteps = gloset.scene_manager.dataset_timesteps( scene_hash, dataset_hash, set_timestep=last_timestep) continue else: bl.debug("Did not find all necessary files for most recent timestep, checking for files in second to last timestep") try: second_last_timestep = sorted_timesteps[-2] except: bl.debug_warning("Could not find second to last timestep") continue # ... and not the second to last position if sorted_timesteps[index] == second_last_timestep: # is second to last in timestep list, nothing to do bl.debug("We are already at the second to last timestep, nothing to do") continue check_dicts = list() # check if the files we need are in the most recent timestep for object_dict in value["object_dicts"]: check_dicts.append({namespace: {second_last_timestep: object_dict}}) second_data_avail = True with LI_LOCK: for check_dict in check_dicts: bl.debug("Checking for {} in local index".format(check_dict)) avail = ndc.contains(LOCAL_INDEX, check_dict) if not avail: bl.debug_warning("Not found, can't update to most recent timestep") second_data_avail = False if second_data_avail: bl.debug("Found all necessary files for second to last timestep") dataset_timesteps = gloset.scene_manager.dataset_timesteps( scene_hash, dataset_hash, set_timestep=second_last_timestep)
def scenes( self, scene_hash=None, dataset_hash=None, dataset_operation=None, mesh_operation=None ): """ Contains the logic for manipulating scenes over the API. Distributes the call parameters to subfunctions. """ # Parse the HTTP method http_method = cherrypy.request.method # Init the output output = None # server busy stuff ################################################## if scene_hash is not None: # if POSTing or PATCHing we have to check if we block or not if (http_method == 'POST' or http_method == 'PATCH'): try: if self.is_scene_locked(scene_hash): raise cherrypy.HTTPError(503, 'scene is locked, try again later') except KeyError as e: bl.debug_warning("KeyError: {}".format(e)) self.lock_scene_if_unlocked(scene_hash) ################################################## if ( scene_hash is None and dataset_hash is None and dataset_operation is None and mesh_operation is None ): # GET if http_method == 'GET': # There is nothing to parse output = self.get_scenes() # POST if http_method == 'POST': # Parse datasetsToAdd from JSON try: json_input = cherrypy.request.json datasets = json_input['datasetsToAdd'] output = self.post_scenes(datasets) except (KeyError, TypeError) as e: bl.debug_warning("KeyError/TypeError: {}".format(e)) output = None ################################################## if ( scene_hash is not None and dataset_hash is None and dataset_operation is None and mesh_operation is None ): # GET if http_method == 'GET': output = self.get_scenes_scenehash(scene_hash) # POST if http_method == 'POST': # Parse datasetsToAdd from JSON try: json_input = cherrypy.request.json datasets = json_input['datasetsToAdd'] output = self.post_scenes_scenehash(scene_hash, datasets) except (KeyError, TypeError) as e: bl.debug_warning("KeyError/TypeError: {}".format(e)) output = None # DELETE if http_method == 'DELETE': output = self.delete_scenes_scenehash(scene_hash) ################################################## if ( scene_hash is not None and dataset_hash is not None and dataset_operation is None and mesh_operation is None ): if dataset_hash == 'colorbar': # GET if http_method == 'GET': output = self.get_dataset_scenes_scenehash_colorbar( scene_hash) # PATCH if http_method == 'PATCH': try: colorbar_information = cherrypy.request.json output = self.patch_dataset_scenes_scenehash_colorbar( scene_hash, colorbar_information) except (KeyError, TypeError) as e: bl.debug_warning("KeyError/TypeError: {}".format(e)) output = None else: # GET if http_method == 'GET': output = self.get_dataset_scenes_scenehash_datasethash( scene_hash, dataset_hash) # DELETE if http_method == 'DELETE': output = self.delete_dataset_scenes_scenehash_datasethash( scene_hash, dataset_hash) ################################################## if ( scene_hash is not None and dataset_hash is not None and dataset_operation is not None and mesh_operation is None ): # GET if http_method == 'GET': if dataset_operation == 'orientation': output = self.get_scenes_scenehash_datasethash_orientation( scene_hash, dataset_hash) ################################################## if dataset_operation == 'timesteps': output = self.get_scenes_scenehash_datasethash_timesteps( scene_hash, dataset_hash) ################################################## if dataset_operation == 'fields': output = self.get_scenes_scenehash_datasethash_fields( scene_hash, dataset_hash) ################################################## if dataset_operation == 'elementsets': output = self.get_scenes_scenehash_datasethash_elementsets( scene_hash, dataset_hash) ################################################## if dataset_operation == 'mesh': output = self.get_scenes_scenehash_datasethash_mesh( scene_hash, dataset_hash) ################################################## if dataset_operation == 'tracking': output = self.get_scenes_scenehash_datasethash_tracking( scene_hash, dataset_hash) # PATCH if http_method == 'PATCH': if dataset_operation == 'orientation': # Parse datasetsToAdd from JSON try: json_input = cherrypy.request.json orientation = json_input['datasetOrientation'] output = ( self. patch_scenes_scenehash_datasethash_orientation( scene_hash, dataset_hash, new_orientation=orientation) ) except (KeyError, TypeError) as e: bl.debug_warning("KeyError/TypeError: {}".format(e)) output = None ################################################## if dataset_operation == 'timesteps': # Parse datasetsToAdd from JSON try: json_input = cherrypy.request.json timestep = json_input['datasetTimestepSelected'] output = ( self.patch_scenes_scenehash_datasethash_timesteps( scene_hash, dataset_hash, new_timestep=timestep) ) except (KeyError, TypeError) as e: bl.debug_warning("KeyError/TypeError: {}".format(e)) output = None ################################################## if dataset_operation == 'fields': # Parse datasetsToAdd from JSON try: json_input = cherrypy.request.json field = json_input['datasetFieldSelected'] output = ( self.patch_scenes_scenehash_datasethash_fields( scene_hash, dataset_hash, new_field=field) ) except (KeyError, TypeError) as e: bl.debug_warning("KeyError/TypeError: {}".format(e)) output = None ################################################## if dataset_operation == 'elementsets': # Parse datasetsToAdd from JSON try: json_input = cherrypy.request.json elementset = json_input['datasetElementsetSelected'] output = ( self.patch_scenes_scenehash_datasethash_elementsets( scene_hash, dataset_hash, new_elementset=elementset) ) except (KeyError, TypeError) as e: bl.debug_warning("KeyError/TypeError: {}".format(e)) output = None ################################################## if dataset_operation == 'tracking': output = ( self.patch_scenes_scenehash_datasethash_tracking( scene_hash, dataset_hash) # this is just a toggle ) ################################################## if ( scene_hash is not None and dataset_hash is not None and dataset_operation is not None and mesh_operation is not None ): # GET if http_method == 'GET': if dataset_operation == 'mesh': if mesh_operation == 'hash': output = self.get_scenes_scenehash_datasethash_mesh_hash( scene_hash, dataset_hash) if mesh_operation == 'geometry': output = self.get_scenes_scenehash_datasethash_mesh_geometry( scene_hash, dataset_hash) if mesh_operation == 'field': output = self.get_scenes_scenehash_datasethash_mesh_field( scene_hash, dataset_hash) ################################################## # server busy stuff ################################################## if scene_hash is not None: # maybe we need to unblock the server if (http_method == 'POST' or http_method == 'PATCH'): self.unlock_scene_if_locked(scene_hash) return output
def simulation_file(source_dict=None, namespace=None, object_key_list=[]): """ Obtain a simulation file from the ceph cluster. Note: this is an async function so that we can perform this action in parallel. """ bl.debug("Requesting {} in namespace {}".format(object_key_list, namespace)) expectation_list = list() for item in object_key_list: expectation_list.append("{}/{}".format(namespace, item)) occurence_dict = dict() comm_dict = source_dict["external"]["comm_dict"] file_request_queue = comm_dict["file_request_queue"] file_request_answer_queue = comm_dict["file_contents_name_hash_queue"] before_qsize = file_request_answer_queue.qsize() if (before_qsize > 0): bl.debug_warning("Data return queue is not empty, contains {} " "objects".format(before_qsize)) # see if we have the data downloaded already, if not make the gateway client get it for obj in object_key_list: object_descriptor = "{}/{}".format(namespace, obj) with GW_LOCK: if object_descriptor in GATEWAY_DATA: bl.debug( "Found {} in downloaded data, updating timestamp".format( object_descriptor)) GATEWAY_DATA[object_descriptor]["timestamp"] = time.time() else: bl.debug("Downloading {}".format(object_descriptor)) req = {"namespace": namespace, "key": obj} file_request_queue.put(req) # keep track how often we try to get data from the dictionary counter = 0 # wait until we have everything downloaded while True: # wait a fraction of a second (rate throttling) time.sleep(.1) # do we have every file? all_present = True # get a list of keys in the GATEWAY_DATA with GW_LOCK: keys = list(GATEWAY_DATA.keys()) for object_descriptor in expectation_list: if not object_descriptor in keys: all_present = False # update timestamp if object_descriptor in keys: with GW_LOCK: GATEWAY_DATA[object_descriptor]["timestamp"] = time.time() # break the loop if all_present: bl.debug("Data complete") break counter += 1 if (counter > 1000): # very large meshes take some time bl.warning("Too many iterations. Could not get data from gateway.") return # prepare output of function res_bin = [None] * len(object_key_list) for object_descriptor in expectation_list: with GW_LOCK: GATEWAY_DATA[object_descriptor]["timestamp"] = time.time() request_dict = GATEWAY_DATA[object_descriptor]["request_dict"] obj_namespace = request_dict["namespace"] obj_key = request_dict["object"] bl.debug("Loading {}/{}".format(obj_namespace, obj_key)) index = object_key_list.index(obj_key) res_bin[index] = request_dict return res_bin