diff --git a/Readme.md b/Readme.md index 2751bc8..d1fd361 100644 --- a/Readme.md +++ b/Readme.md @@ -108,6 +108,154 @@ curl -H "Content-Type: application/json" -X POST -d '{"regex": "AMPLT|PHASE"}' h ] ``` + + +## Channel Configurations + +It is possible to query channel configurations like type etc.. + +The following configuration queries provide the latest known configuration of the channels (see [here](Readme.md#channel_configuration_history) on how to query the channel configuration history). + + + + +### Query Channel Configurations + +### Request + +``` +POST https://:/channels/config +``` + +#### Data + +```json +{ + "regex":"^SINEG.*PHASE$", + "backends":[ + "sf-databuffer" + ], + "ordering":"none", + "sourceRegex":"LLRF" +} +``` + +##### Explanation + +- **regex**: Reqular expression used to filter channel names. In case this value is undefined, no filter will be applied. Filtering is done using JAVA's [Pattern](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html), more precisely [Matcher.find()](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#find--)). +- **backends**: Array of backends to access (values: sf-databuffer|sf-imagebuffer|sf-archiverappliance). In case this value is undefined, all backends will be queried for their channels. +- **ordering**: The ordering of the channel names (values: **none**|asc|desc). +- **sourceRegex**: Reqular expression used to filter source names (like e.g. tcp://SINEG01-CVME-LLRF1:20000). In case this value is undefined, no filter will be applied. Filtering is done using JAVA's [Pattern](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html), more precisely [Matcher.find()](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#find--)). + +### Example + +#### Command + +```bash +curl -H "Content-Type: application/json" -X POST -d '{"regex": "AMPLT|PHASE|CAM"}' https://data-api.psi.ch/sf/channels/config | python -m json.tool +``` + +#### Response + +```json +[ + { + "backend":"sf-databuffer", + "channels":[ + { + "name":"Channel_01_AMPLT", + "type":"UInt16", + "shape":[2048], + "modulo":1, + "offset":0, + "backend":"sf-databuffer", + "source":"tcp://SINEG01-CVME-LLRF1:20000" + }, + { + "name":"Channel_01_PHASE_AVG", + "type":"Float64", + "shape":[1], + "modulo":1, + "offset":0, + "backend":"sf-databuffer", + "source":"tcp://SINEG01-CVME-LLRF1:20000" + } + ] + }, + { + "backend":"sf-imagebuffer", + "channels":[ + { + "name":"Helges_CAM", + "type":"UInt16", + "shape":[1024,2048], + "modulo":1, + "offset":0, + "backend":"sf-imagebuffer", + "source":"tcp://HELGE_COMPI:9999" + } + ] + } +] +``` + + + +### Query Specific Channel Configuration + +### Request + +``` +POST https://:/channel/config +``` +or + +``` +GET https://:/channel/config/{channel} +``` + +#### Data + +```json +{ + "name":"SINEG01-RCIR-PUP10:SIG-AMPLT", + "backend":"sf-databuffer" +} +``` + +##### Explanation + +- **name**: The channel name (see [here](https://github.psi.ch/sf_daq/ch.psi.daq.queryrest#define-channel-names) on how name clashes will be resolved). +- **backend**: The backend of the channel. + +### Example + +#### Command + +```bash +curl -H "Content-Type: application/json" -X POST -d '{"name": "SINEG01-RCIR-PUP10:SIG-AMPLT", "backend":"sf-databuffer"}' https://data-api.psi.ch/sf/channel/config | python -m json.tool +``` + +or + +```bash +curl -H "Content-Type: application/json" -X GET https://data-api.psi.ch/sf/channel/config/SINEG01-RCIR-PUP10:SIG-AMPLT | python -m json.tool +``` + +#### Response + +```json +{ + "name":"SINEG01-RCIR-PUP10:SIG-AMPLT", + "type":"UInt16", + "shape":[2048], + "modulo":1, + "offset":0, + "backend":"sf-databuffer", + "source":"tcp://SINEG01-CVME-LLRF1:20000" +} +``` + ## Query Data @@ -198,7 +346,7 @@ The simplest way to define channels is to use an array of channel name Strings. ] ``` -The query interface will automatically select the backend which contains the channel (e.g., *sf-databuffer* for *Channel_02* and *sf-archiverappliance* for *Channel_04*). In case name clashes exist, the query interface will use following order of priority: *sf-databuffer* and then *sf-archiverappliance*. +The query interface will automatically select the backend which contains the channel (e.g., *sf-databuffer* for *Channel_02* and *sf-archiverappliance* for *Channel_04*). In case name clashes exist, the query interface will use following order of priority: *sf-databuffer*, *sf-imagebuffer*, and then *sf-archiverappliance*. It is also possible to explicitly define the backend to overcome name clashes. @@ -283,7 +431,7 @@ Queries are applied to a range. The following types of ranges are supported. ] ``` -- **fields**: Array of requested fields (see [here](https://github.psi.ch/sf_daq/ch.psi.daq.domain/blob/master/src/main/java/ch/psi/daq/domain/query/operation/QueryField.java) for possible values). +- **fields**: Array of requested fields (see [here](https://github.psi.ch/sf_daq/ch.psi.daq.domain/blob/master/src/main/java/ch/psi/daq/domain/query/operation/EventField.java) for possible values of data queries and [here](https://github.psi.ch/sf_daq/ch.psi.daq.domain/blob/master/src/main/java/ch/psi/daq/domain/query/operation/ConfigField.java) for possible values of config queries). It is possible to request the time in seconds (since midnight, January 1, 1970 UTC (the UNIX epoch) as a decimal value including fractional seconds - using fields *globalSeconds* and *iocSeconds*), in milliseconds (since midnight, January 1, 1970 UTC (the JAVA epoch) - using fields *globalMillis* and *iocMillis*) or as a ISO8601 formatted String - using fields *globalDate* and *iocDate* (such as 1997-07-16T19:20:30.123456789+02:00). @@ -1245,3 +1393,50 @@ With *provide-as-is*, the response will contain all available data. In case *dro ``` + + +### Query Channel Configuration History + +### Request + +``` +POST https://:/query/config +``` + +#### Request body + +A request is performed by sending a valid JSON object in the HTTP request body. The JSON query defines the channels to be queried and the range. + +#### Data + +```json +{ + "channels":[ + "Channel_01" + ], + "range":{ + "startPulseId":0, + "endPulseId":3 + }, + "ordering":"asc", + "fields":[ + "pulseId", + "globalDate", + "type" + ], + "response":{ + "format":"json", + "compression":"none" + } +} +``` + +##### Explanation + +The query format is equivalent to the data query (see [here](Readme.md#query_data) for further explanations). + +##### Command + +```bash +curl -H "Content-Type: application/json" -X POST -d '{"range":{"startDate":"2017-01-01T01:00:00.000","endDate":"2017-11-01T01:00:00.030"},"channels":["Channel_01"]}' https://data-api.psi.ch/sf/query/config | python -m json.tool +``` diff --git a/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java b/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java index 4663f4f..f649447 100644 --- a/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java +++ b/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java @@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.validation.DirectFieldBindingResult; import org.springframework.validation.Errors; @@ -39,6 +40,7 @@ import com.google.common.collect.Lists; import ch.psi.daq.common.ordering.Ordering; import ch.psi.daq.domain.backend.Backend; import ch.psi.daq.domain.config.DomainConfig; +import ch.psi.daq.domain.events.ChannelConfiguration; import ch.psi.daq.domain.json.ChannelName; import ch.psi.daq.domain.query.DAQConfigQuery; import ch.psi.daq.domain.query.DAQConfigQueryElement; @@ -176,12 +178,23 @@ public class QueryRestController implements ApplicationContextAware { produces = {MediaType.APPLICATION_JSON_VALUE}) public void getChannelConfiguration(@RequestBody final ChannelName channelName, final HttpServletResponse res) throws Throwable { - ((AbstractHTTPResponse) defaultResponse).respond( - context, - res, - null, - queryManager.getChannelConfiguration(channelName), - historicConfigFormatter); + try { + final ChannelConfiguration config = queryManager.getChannelConfiguration(channelName); + + if (config != null) { + ((AbstractHTTPResponse) defaultResponse).respond( + context, + res, + null, + config, + historicConfigFormatter); + } else { + res.setStatus(HttpStatus.NOT_FOUND.value()); + } + } catch (Throwable t) { + LOGGER.warn("Failed to get channel configuration.", t); + throw t; + } } @RequestMapping(