def request_capture_stop(self, req, product_id): """Signals that an observation is has stopped Publishes a message to the 'alerts' channel of the form: capture-stop:product_id The product_id should match what what was sent in the ?configure request This alert should notify all backend processes (such as beamformer) that they should stop collecting data now """ msg = "capture-stop:{}".format(product_id) success = publish_to_redis(self.redis_server, REDIS_CHANNELS.alerts, msg) if success: return ("ok", ) else: return ("fail", "Failed to publish to our local redis server")
def request_deconfigure(self, req, product_id): """Signals that the current data product is done. Deconfigure the BLUSE instance that was created by the call to ?configure with the corresponding product_id. Note: CAM is expected to have sent a ?capture-done request before deconfiguring, in order to ensure that all data has been written. If BLUSE uses an instance of katportalclient to get information from CAM for this BLUSE instance, then it should disconnect at this time. Publishes a message to the 'alerts' channel of the form: deconfigure:product_id The product_id should match what what was sent in the ?configure request This alert should notify all backend processes (such as beamformer) that their data streams are ending """ msg = "deconfigure:{}".format(product_id) success = publish_to_redis(self.redis_server, REDIS_CHANNELS.alerts, msg) if success: return ("ok", ) else: return ("fail", "Failed to publish to our local redis server")
def request_configure(self, req, product_id, antennas_csv, n_channels, streams_json, proxy_name): """Receive metadata for upcoming observation. In order to allow BLUSE to make an estimate of its ability to process a particular data product, this command should be used to configure a BLUSE instance when a new subarray is activated. Args: product_id (str): This is a name for the data product, which is a useful tag to include in the data, but should not be analysed further. For example "array_1_bc856M4k". This value will be unique across all subarrays. However, it is not a globally unique identifier for the lifetime of the telescope. The exact same value may be provided at a later time when the same subarray is activated again. antennas_csv (str): A comma separated list of physical antenna names used in particular sub-array to which the data products belongs. n_channels (int): The integer number of frequency channels provided by the CBF. streams_json (str) is a JSON struct containing config keys and values describing the streams. For example: {'stream_type1': { 'stream_name1': 'stream_address1', 'stream_name2': 'stream_address2', ...}, 'stream_type2': { 'stream_name1': 'stream_address1', 'stream_name2': 'stream_address2', ...}, ...} The steam type keys indicate the source of the data and the type, e.g. cam.http. stream_address will be a URI. For SPEAD streams, the format will be spead://<ip>[+<count>]:<port>, representing SPEAD stream multicast groups. When a single logical stream requires too much bandwidth to accommodate as a single multicast group, the count parameter indicates the number of additional consecutively numbered multicast group ip addresses, and sharing the same UDP port number. stream_name is the name used to identify the stream in CAM. A Python example is shown below, for five streams: One CAM stream, with type cam.http. The camdata stream provides the connection string for katportalclient (for the subarray that this BLUSE instance is being configured on). One F-engine stream, with type: cbf.antenna_channelised_voltage. One X-engine stream, with type: cbf.baseline_correlation_products. Two beam streams, with type: cbf.tied_array_channelised_voltage. The stream names ending in x are horizontally polarised, and those ending in y are vertically polarised. proxy_name (str): The CAM name for the instance of the BLUSE data proxy that is being configured. For example, "BLUSE_3". This can be used to query sensors on the correct proxy. Note that for BLUSE there will only be a single instance of the proxy in a subarray. Returns: None... but replies with "ok" or "fail" and logs either info or error Writes: - subbarry1_abc65555:timestamp" -> "1534657577373.23423" :: Redis String - subarray1_abc65555:antennas" -> [1,2,3,4] :: Redis List - subarray1_abc65555:n_channels" -> "4096" :: Redis String - subarray1_abc65555:proxy_name "-> "BLUSE_whatever" :: Redis String - subarray1_abc65555:streams" -> {....} :: Redis Hash !!!CURRENTLY A STRING!!! - current:obs:id -> "subbary1_abc65555" Publishes: redis-channel: 'alerts' <-- "configure" Examples: > ?configure array_1_bc856M4k a1,a2,a3,a4 128000 {"cam.http":{"camdata":"http://monctl.devnmk.camlab.kat.ac.za/api/client/2"},"stream_type2":{"stream_name1":"stream_address1","stream_name2":"stream_address2"}} BLUSE_3 """ try: antennas_list = antennas_csv.split(",") json_dict = unpack_dict(streams_json) cam_url = json_dict['cam.http']['camdata'] except Exception as e: log.error(e) return ("fail", e) statuses = [] statuses.append( write_pair_redis(self.redis_server, "{}:timestamp".format(product_id), time.time())) statuses.append( write_list_redis(self.redis_server, "{}:antennas".format(product_id), antennas_list)) statuses.append( write_pair_redis(self.redis_server, "{}:n_channels".format(product_id), n_channels)) statuses.append( write_pair_redis(self.redis_server, "{}:proxy_name".format(product_id), proxy_name)) statuses.append( write_pair_redis(self.redis_server, "{}:streams".format(product_id), json.dumps(json_dict))) statuses.append( write_pair_redis(self.redis_server, "{}:cam:url".format(product_id), cam_url)) statuses.append( write_pair_redis(self.redis_server, "current:obs:id", product_id)) msg = "configure:{}".format(product_id) statuses.append( publish_to_redis(self.redis_server, REDIS_CHANNELS.alerts, msg)) if all(statuses): return ("ok", ) else: return ("fail", "Failed to publish to our local redis server")