def send_map_layers_to_samp(maps, defer_cleanup_s=5): client = SAMPIntegratedClient() client.connect() params = {} message = {"samp.mtype": "jhv.load.image", "samp.params": params} tmp_files = [] for energy_band in maps: params["url"] = [] for i in range(len(maps[energy_band])): f = NamedTemporaryFile(delete=False, suffix=".fits") f.close() maps[energy_band][i].save(f.name) tmp_files.append(f.name) # use file:/// workaround for windows as JHV currently can't handle windows paths params["url"].append(("file:///" + f.name.replace("\\", "/") ) if f.name.find("\\") >= 0 else f.name) client.notify_all( message ) # message holds a reference to params which is updated in the loop client.disconnect() time.sleep( defer_cleanup_s ) # wait to make sure JHV could read the files before they're removed for filename in tmp_files: del_file(filename) # cleanup
class SAMP4JHVClient: def __init__(self): self.client = SAMPIntegratedClient() self.tmp_files = [] def send_image_maps(self, maps): """ Takes a list of SunPy Map objects, saves them to disk one by one and sends the file-locations to JHV """ params = {} params["url"] = [] for m in maps: f = NamedTemporaryFile(delete=False, suffix=".fits") f.close() m.save(f.name) self.tmp_files.append(f.name) # use file:/// workaround for windows as JHV currently can't handle windows paths params["url"].append(("file:///" + f.name.replace("\\", "/") ) if f.name.find("\\") >= 0 else f.name) self.client.connect() self.client.notify_all({ "samp.mtype": "jhv.load.image", "samp.params": params }) self.client.disconnect() def remove_tmp_files(self): """ Removes temporary files that were created for JHV to be read. Mind that after calling this function, the images might not be available in JHV anymore due to JHVs internal memory management, that might require to re-read the files at some point. """ for f in self.tmp_files: del_file(f) # cleanup
class A2p2SampClient(): # TODO watch hub disconnection def __init__(self): self.sampClient = SAMPIntegratedClient("A2P2 samp relay") # TODO get title from main program class instead of HardCoded value def __del__(self): self.disconnect() def connect(self): self.sampClient.connect() # an error is thrown here if no hub is present # TODO get samp client name and display it in the UI # Instantiate the receiver self.r = Receiver(self.sampClient) # Listen for any instructions to load a table self.sampClient.bind_receive_call("ob.load.data", self.r.receive_call) self.sampClient.bind_receive_notification("ob.load.data", self.r.receive_notification) # TODO fix next call which thwrows an execption # <class 'astropy.samp.errors.SAMPProxyError'>, # <Fault 1: 'java.lang.IllegalArgumentException: Bad arguments: samp.hub.notifyAll[string, map] got [string, string]'> self.sampClient.notify_all("hello") def disconnect(self): self.sampClient.disconnect() def is_connected(self): # Workarround the 'non' reliable is_connected attribute # this helps to reconnect after hub connection lost try: return self.sampClient.is_connected and (self.sampClient.ping() or self.sampClient.is_connected) except: # consider connection refused exception as not connected state return False def get_status(self): if self.is_connected(): return "connected [%s]" % (self.sampClient.get_public_id()) else: return "not connected" def has_message(self): return self.is_connected() and self.r.received def clear_message(self): return self.r.clear() def get_ob_url(self): url = self.r.params['url'] if url.startswith("file:///"): return url[7:] elif url.startswith("file:/"): # work arround bugged file urls return url[5:] return url
class AladinViaSAMP(object): def __init__(self): self._client = SAMPIntegratedClient() def send_file(self, infile=str()): """Sending a file (image or table) to Aladin Sky Atlas using the SAMPIntegratedClient class. http://docs.astropy.org/en/stable/vo/samp/example_table_image.html """ self._client.connect() params = {} if sys.version > '3': params["url"] = urllib.parse.urljoin('file:', os.path.abspath(infile)) else: params["url"] = urlparse.urljoin('file:', os.path.abspath(infile)) message = {} message[ "samp.mtype" ] = "image.load.fits" message[ "samp.params" ] = params self._client.notify_all(message) self._client.disconnect() def move(self, script=str()): """Sending a script to Aladin Sky Atlas using the SAMPIntegratedClient class. http://docs.astropy.org/en/stable/vo/samp/example_table_image.html """ self._client.connect() params = {} message = {} message[ "samp.mtype" ] = "coord.pointAt.sky" message[ "samp.params" ] = { "script" : script } self._client.notify_all(message) self._client.disconnect() def send_script_command(self, script=str()): """Sending a script to Aladin Sky Atlas using the SAMPIntegratedClient class. http://docs.astropy.org/en/stable/vo/samp/example_table_image.html """ self._client.connect() params = {} message = {} message[ "samp.mtype" ] = "script.aladin.send" message[ "samp.params" ] = { "script" : script } self._client.notify_all(message) self._client.disconnect()
parser.add_argument("-i", "--input", required=True, metavar="file", help="input JHV request file") parser.add_argument("-value", help="Send request as message value", action="store_true") args = parser.parse_args() input_file = os.path.abspath(args.input) client = SAMPIntegratedClient() client.connect() params = {} if args.value: with open(input_file, "r") as f: params["value"] = f.read() else: params["url"] = input_file message = {} message["samp.mtype"] = "jhv.load.request" message["samp.params"] = params client.notify_all(message) client.disconnect()
class SAMPManager(): __client = None __received = False __params = {} __hub = None __server_name = "frastro server" __server_description = "frastro Web client" __server_description_html = "<h1>frastro Web client</h1>" __author = "Camilo E. Jimenez-Angel" __instritution = "IAC" __email_contact = "*****@*****.**" __url_icon = "http://localhost:8000/static/img/frastro_icon.jpg" def __init__(self, server_name=""): # Instantiate the client and connect to the hub self.__server_name = server_name if server_name != "" else self.__server_name self.connect() def starHubServer(self, web_profile=True): if self.__hub is None: self.__hub = SAMPHubServer(web_profile=web_profile, label=self.__server_name) self.__hub.start() def receive_call(self, private_key, sender_id, msg_id, mtype, params, extra): self.__params = params self.__received = True self.__client.reply(msg_id, { "samp.status": "samp.ok", "samp.result": {} }) def receive_notification(self, private_key, sender_id, mtype, params, extra): self.__params = params self.__received = True def bind_to_server(self): # Listen for any instructions to load a table self.__client.bind_receive_call("table.load.votable", self.receive_call) self.__client.bind_receive_notification("table.load.votable", self.receive_notification) def sampMetadata(self): meta = { "samp.name": self.__server_name, "samp.description.text": self.__server_description, "samp.description.html": self.__server_description_html, "samp.icon.url": self.__url_icon, "author.affiliation": self.__instritution, "author.name": self.__author, "author.email": self.__email_contact } return meta def getRegisteredClients(self): clients = self.__client.get_registered_clients() run_clients = {} for client in clients: client_data = self.getMetadata(client) run_clients[client] = client_data return run_clients def getMetadata(self, client_id): return self.__client.get_metadata(client_id) def sendTable(self, message, recipient="all"): if recipient == "all": self.__client.notify_all(message) else: self.__client.notify(recipient, message) def connect(self): self.__client = SAMPIntegratedClient(name=self.__server_name, metadata=self.sampMetadata()) self.__client.connect() self.bind_to_server() def sendImage(self, params, id=""): message = {} message["samp.mtype"] = "image.load.fits" message["samp.params"] = params if id == "" or id == "all": self.__client.notify_all(message) else: self.__client.notify(recipient_id=id, message=message) def sendMessage(self, params, id=""): message = {} message["samp.mtype"] = "table.load.votable" message["samp.params"] = params if id == "" or id == "all": self.__client.notify_all(message) else: self.__client.notify(recipient_id=id, message=message) def disconnect(self): self.__client.disconnect() def __del__(self): self.disconnect()
class SAMPState(State): status = CallbackProperty('Not connected to SAMP Hub') connected = CallbackProperty(False) clients = CallbackProperty([]) highlight_is_selection = CallbackProperty(False) def __init__(self): super(SAMPState, self).__init__() self.hub = SAMPHubServer() self.client = SAMPIntegratedClient() self.add_callback('connected', self.on_connected) def start_samp(self): if not self.client.is_connected: try: self.client.connect() except SAMPHubError: try: self.hub.start() self.client.connect() except Exception: self.connected = False self.status = 'Could not connect to Hub' else: self.connected = True self.status = 'Connected to (glue) SAMP Hub' except: self.connected = False self.status = 'Could not connect to Hub' else: self.connected = True self.status = 'Connected to SAMP Hub' def stop_samp(self): if self.client.is_connected: self.client.disconnect() if self.hub.is_running: self.hub.stop() self.connected = False self.status = 'Not connected to SAMP Hub' def on_connected(self, *args): if self.connected: metadata = { 'author.email': '*****@*****.**', 'author.name': 'Thomas Robitaille', 'home.page': 'http://www.glueviz.org', 'samp.description.text': 'Multi-dimensional linked data exploration', 'samp.documentation.url': 'http://www.glueviz.org', 'samp.icon.url': 'file://' + ICON_PATH, 'samp.name': 'glueviz', 'glue.version': glue_version } self.client.declare_metadata(metadata) self.on_client_change() def on_client_change(self): clients = [] for client in self.client.get_registered_clients(): metadata = self.client.get_metadata(client) clients.append((client, metadata.get('samp.name', client))) self.clients = clients def send_data(self, layer=None, client=None): filename = tempfile.mktemp() message = {} message["samp.params"] = {} if isinstance(layer, Data): if layer.ndim == 1: table = data_to_astropy_table(layer) table.write(filename, format='votable') message["samp.mtype"] = "table.load.votable" if 'samp-table-id' not in layer.meta: layer.meta['samp-table-id'] = layer.label message["samp.params"]['table-id'] = layer.meta[ 'samp-table-id'] elif layer.ndim == 2: fits_writer(filename, layer) message["samp.mtype"] = "image.load.fits" if 'samp-image-id' not in layer.meta: layer.meta['samp-image-id'] = layer.label message["samp.params"]['image-id'] = layer.meta[ 'samp-image-id'] else: return message["samp.params"]['name'] = layer.label message["samp.params"]['url'] = 'file://' + os.path.abspath( filename) else: message['samp.mtype'] = 'table.select.rowList' if layer.ndim == 1: message["samp.params"]['table-id'] = layer.data.meta[ 'samp-table-id'] message["samp.params"]['row-list'] = np.nonzero( layer.to_mask())[0].astype(str).tolist() else: return if client is None: self.client.notify_all(message) else: # Make sure client is subscribed otherwise an exception is raised subscriptions = self.client.get_subscriptions(client) for mtype in subscriptions: if fnmatch(message['samp.mtype'], mtype): self.client.notify(client, message) return else: return