diff --git a/showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.html b/showcase-dev/examples/datasource-consysapi/datasource-consysapi.html similarity index 100% rename from showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.html rename to showcase-dev/examples/datasource-consysapi/datasource-consysapi.html diff --git a/showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.js b/showcase-dev/examples/datasource-consysapi/datasource-consysapi.js similarity index 76% rename from showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.js rename to showcase-dev/examples/datasource-consysapi/datasource-consysapi.js index 4ee4225ca1..199a296213 100644 --- a/showcase-dev/examples/datasource-sweapifetch/datasource-sweapifetch.js +++ b/showcase-dev/examples/datasource-consysapi/datasource-consysapi.js @@ -1,9 +1,9 @@ import {EventType} from 'osh-js/core/event/EventType'; -// #region snippet_datasource_sweapifetch -import SweApiFetch from "osh-js/core/datasource/sweapi/SweApi.datasource.js"; +// #region snippet_datasource_consysapi +import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js"; import {Mode} from "osh-js/core/datasource/Mode"; -let gpsDataSource = new SweApiFetch("android-GPS", { +let gpsDataSource = new ConSysApi("android-GPS", { endpointUrl: 'api.georobotix.io/ogc/t18/api', resource: '/datastreams/o7pce3e60s0ie/observations', tls: true, @@ -15,7 +15,7 @@ let gpsDataSource = new SweApiFetch("android-GPS", { mode : Mode.REAL_TIME }); -// #endregion snippet_datasource_sweapifetch +// #endregion snippet_datasource_consysapi gpsDataSource.subscribe(async (message) => { let dataEvent; diff --git a/showcase-dev/examples/datasource-sweapifetch/package.json b/showcase-dev/examples/datasource-consysapi/package.json similarity index 100% rename from showcase-dev/examples/datasource-sweapifetch/package.json rename to showcase-dev/examples/datasource-consysapi/package.json diff --git a/showcase-dev/examples/datasource-sweapifetch/webpack.config.js b/showcase-dev/examples/datasource-consysapi/webpack.config.js similarity index 90% rename from showcase-dev/examples/datasource-sweapifetch/webpack.config.js rename to showcase-dev/examples/datasource-consysapi/webpack.config.js index bbda5fc140..2ca343f4d5 100644 --- a/showcase-dev/examples/datasource-sweapifetch/webpack.config.js +++ b/showcase-dev/examples/datasource-consysapi/webpack.config.js @@ -8,10 +8,10 @@ const CopyWebpackPlugin = require("copy-webpack-plugin"); module.exports = { // Tell Webpack which file kicks off our app. - entry: path.resolve(__dirname,'./datasource-sweapifetch.js'), + entry: path.resolve(__dirname,'./datasource-consysapi.js'), // Tell Weback to output our bundle to ./dist/bundle.js output: { - filename: 'bundle.datasource.sweapifetch.js', + filename: 'bundle.datasource.consysapi.js', path: path.resolve(__dirname, 'dist') }, // Tell Webpack which directories to look in to resolve import statements. @@ -53,7 +53,7 @@ module.exports = { compress: true, port: 9000, hot: true, - index: 'datasource-sweapifetch.html', + index: 'datasource-consysapi.html', https:true }, devtool: 'source-map', @@ -74,8 +74,8 @@ module.exports = { // by the Webpack dev server. We can give it a template file (written in EJS) // and it will handle injecting our bundle for us. new HtmlWebpackPlugin({ - filename: "datasource-sweapifetch.html", - template: path.resolve(__dirname, 'datasource-sweapifetch.html') + filename: "datasource-consysapi.html", + template: path.resolve(__dirname, 'datasource-consysapi.html') }), new CopyWebpackPlugin([ { from: path.resolve(__dirname,'data'), to: 'data'} diff --git a/showcase-dev/examples/datasynchronizer-dynamic-add-remove-realtime/datasynchronizer-dynamic-add-remove-realtime.js b/showcase-dev/examples/datasynchronizer-dynamic-add-remove-realtime/datasynchronizer-dynamic-add-remove-realtime.js index 912a8a3b6a..901610e7a4 100644 --- a/showcase-dev/examples/datasynchronizer-dynamic-add-remove-realtime/datasynchronizer-dynamic-add-remove-realtime.js +++ b/showcase-dev/examples/datasynchronizer-dynamic-add-remove-realtime/datasynchronizer-dynamic-add-remove-realtime.js @@ -1,5 +1,5 @@ import {EventType} from 'osh-js/core/event/EventType'; -import SweApiDatasource from "osh-js/core/datasource/sweapi/SweApi.datasource.js"; +import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js"; import {Mode} from "osh-js/core/datasource/Mode"; import DataSynchronizer from "../../../source/core/timesync/DataSynchronizer"; @@ -14,19 +14,19 @@ const commonDatasourceOpts = { }, }; -const ds0 = new SweApiDatasource('MISB Drone - Video', { +const ds0 = new ConSysApi('MISB Drone - Video', { ...commonDatasourceOpts, resource: '/datastreams/h225hesual08g/observations', responseFormat: 'application/swe+binary', }); -const ds1 = new SweApiDatasource('MISB UAS - Platform Location', { +const ds1 = new ConSysApi('MISB UAS - Platform Location', { ...commonDatasourceOpts, resource: '/datastreams/o7pce3e60s0ie/observations', responseFormat: 'application/swe+json', }); -const ds2 = new SweApiDatasource('MISB UAS - Platform Attitude', { +const ds2 = new ConSysApi('MISB UAS - Platform Attitude', { ...commonDatasourceOpts, resource: '/datastreams/mlme3gtdfepvc/observations', responseFormat: 'application/swe+json', diff --git a/showcase-dev/examples/datasynchronizer-dynamic-add-remove-replay/datasynchronizer-dynamic-add-remove-replay.js b/showcase-dev/examples/datasynchronizer-dynamic-add-remove-replay/datasynchronizer-dynamic-add-remove-replay.js index 5be98782da..2097f31666 100644 --- a/showcase-dev/examples/datasynchronizer-dynamic-add-remove-replay/datasynchronizer-dynamic-add-remove-replay.js +++ b/showcase-dev/examples/datasynchronizer-dynamic-add-remove-replay/datasynchronizer-dynamic-add-remove-replay.js @@ -1,5 +1,5 @@ import {EventType} from 'osh-js/core/event/EventType'; -import SweApiDatasource from "osh-js/core/datasource/sweapi/SweApi.datasource.js"; +import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js"; import {Mode} from "osh-js/core/datasource/Mode"; import DataSynchronizer from "../../../source/core/timesync/DataSynchronizer"; @@ -18,19 +18,19 @@ const commonDatasourceOpts = { prefetchBatchSize: 50 }; -const ds0 = new SweApiDatasource('MISB Drone - Video', { +const ds0 = new ConSysApi('MISB Drone - Video', { ...commonDatasourceOpts, resource: '/datastreams/8ni90dbu4uf0g/observations', responseFormat: 'application/swe+binary', }); -const ds1 = new SweApiDatasource('MISB UAS - Platform Location', { +const ds1 = new ConSysApi('MISB UAS - Platform Location', { ...commonDatasourceOpts, resource: '/datastreams/fled6eics1cl4/observations', responseFormat: 'application/swe+json', }); -const ds2 = new SweApiDatasource('MISB UAS - Platform Attitude', { +const ds2 = new ConSysApi('MISB UAS - Platform Attitude', { ...commonDatasourceOpts, resource: '/datastreams/adheadf9nghts/observations', responseFormat: 'application/swe+json', diff --git a/showcase-dev/examples/mqtt-utility/mqtt-utility.js b/showcase-dev/examples/mqtt-utility/mqtt-utility.js index c6046f97a1..51c73b2784 100644 --- a/showcase-dev/examples/mqtt-utility/mqtt-utility.js +++ b/showcase-dev/examples/mqtt-utility/mqtt-utility.js @@ -1,6 +1,6 @@ import MqttProvider from "osh-js/core/mqtt/MqttProvider"; import {randomUUID} from "osh-js/core/utils/Utils"; -import ObservationFilter from "../../../source/core/sweapi/observation/ObservationFilter"; +import ObservationFilter from "../../../source/core/consysapi/observation/ObservationFilter"; const textAreaElement0 = document.getElementById("data-container0"); const textAreaElement1 = document.getElementById("data-container1"); diff --git a/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.html b/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.html index 19afc9fbcc..e786514090 100644 --- a/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.html +++ b/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.html @@ -29,7 +29,7 @@ <select name="services" id="services" size="1"> <option value=""></option> <option value="sos">sos</option> - <option value="sweapi">sweapi</option> + <option value="consysapi">consysapi</option> </select> <button id="replay">Replay</button> <button id="realtime">RealTime</button> diff --git a/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.js b/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.js index 02fe90a551..1f760b8206 100644 --- a/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.js +++ b/showcase-dev/examples/switch-realtime-batch/switch-realtime-batch.js @@ -4,7 +4,7 @@ import CurveLayer from 'osh-js/core/ui/layer/CurveLayer.js'; import SosGetResult from 'osh-js/core/datasource/sos/SosGetResult.datasource.js'; import {Mode} from 'osh-js/core/datasource/Mode'; import DataSynchronizer from "../../../source/core/timesync/DataSynchronizer"; -import SweApiDatasource from "../../../source/core/datasource/sweapi/SweApi.datasource"; +import ConSysApi from "../../../source/core/datasource/consysapi/ConSysApi.datasource"; import {EventType} from "../../../source/core/event/EventType"; function getRandomArbitrary(min, max) { @@ -17,7 +17,7 @@ const dataContentElt = document.getElementById("data-content"); const masterTimeElt = document.getElementById("master-time"); let initSos = false; -let initSweapi = false; +let initConsysapi = false; let chartDataSource = new SosGetResult("weather", { endpointUrl: "sensiasoft.net/sensorhub/sos", @@ -38,7 +38,7 @@ const sosDataSynchronizer = new DataSynchronizer({ }); async function startSosExample() { - await sweapiDataSynchronizer.disconnect(); + await consysapiDataSynchronizer.disconnect(); replayButtonElt.onclick = async () => { await sosDataSynchronizer.setTimeRange( new Date(Date.now() - 60 * 1000 * 60 * 2).toISOString(), @@ -105,19 +105,19 @@ const commonDatasourceOpts = { prefetchBatchSize: 250 }; -const droneLocationDataSource = new SweApiDatasource('MISB UAS - Platform Location', { +const droneLocationDataSource = new ConSysApi('MISB UAS - Platform Location', { ...commonDatasourceOpts, resource: '/datastreams/fled6eics1cl4/observations', responseFormat: 'application/swe+json', }); -const droneOrientationDataSource = new SweApiDatasource('MISB UAS - Platform Attitude', { +const droneOrientationDataSource = new ConSysApi('MISB UAS - Platform Attitude', { ...commonDatasourceOpts, resource: '/datastreams/adheadf9nghts/observations', responseFormat: 'application/swe+json', }); -const sweapiDataSynchronizer = new DataSynchronizer({ +const consysapiDataSynchronizer = new DataSynchronizer({ replaySpeed: 2, masterTimeRefreshRate: 250, startTime: START_TIME, @@ -125,11 +125,11 @@ const sweapiDataSynchronizer = new DataSynchronizer({ dataSources: [droneOrientationDataSource, droneLocationDataSource] }); -async function startSweApiExample() { +async function startConSysApiExample() { await sosDataSynchronizer.disconnect(); replayButtonElt.onclick = async () => { - await sweapiDataSynchronizer.setMode(Mode.REPLAY); - // await sweapiDataSynchronizer.setTimeRange( + await consysapiDataSynchronizer.setMode(Mode.REPLAY); + // await consysapiDataSynchronizer.setTimeRange( // START_TIME, // END_TIME, // 2.0, @@ -138,12 +138,12 @@ async function startSweApiExample() { // ); replayButtonElt.disabled = true; realtimeButtonElt.disabled = false; - await sweapiDataSynchronizer.connect(); + await consysapiDataSynchronizer.connect(); } realtimeButtonElt.onclick = async () => { - await sweapiDataSynchronizer.setMode(Mode.REAL_TIME); - // await sweapiDataSynchronizer.setTimeRange( + await consysapiDataSynchronizer.setMode(Mode.REAL_TIME); + // await consysapiDataSynchronizer.setTimeRange( // 'now', // '2055-01-01', // 1.0, @@ -153,11 +153,11 @@ async function startSweApiExample() { realtimeButtonElt.disabled = true; replayButtonElt.disabled = false; - await sweapiDataSynchronizer.connect(); + await consysapiDataSynchronizer.connect(); } - sweapiDataSynchronizer.subscribe(message => displayData(message), [EventType.DATA]); - sweapiDataSynchronizer.subscribe(message => displayMasterTime(message), [EventType.MASTER_TIME]); + consysapiDataSynchronizer.subscribe(message => displayData(message), [EventType.DATA]); + consysapiDataSynchronizer.subscribe(message => displayMasterTime(message), [EventType.MASTER_TIME]); } const listBoxElement = document.getElementById('services'); @@ -165,8 +165,8 @@ listBoxElement.onchange = (event) => { let value = event.target.value; if(value === 'sos') { startSosExample(); - } else if(value === 'sweapi') { - startSweApiExample() + } else if(value === 'consysapi') { + startConSysApiExample() } } diff --git a/showcase-dev/index.js b/showcase-dev/index.js index b5190e2cf1..a1ae7c7c47 100644 --- a/showcase-dev/index.js +++ b/showcase-dev/index.js @@ -21,13 +21,13 @@ var samples = [ url: "datasource-file" }, { - name: "DataSource SweApiFetch", - description: "Display GPS data using the SweApiFetch datasource", - url: "datasource-sweapifetch" + name: "Connected Systems DataSource", + description: "Display GPS data using the ConSysApi datasource", + url: "datasource-consysapi" }, { - name: "DataSource SweApiFetch Json", - description: "Display data using the SweApiFetch datasource in JSON format", + name: "SOS DataSource Swe Json", + description: "Display data using the SOS datasource in SWE JSON format", url: "datasource-swejson" }, { @@ -56,8 +56,8 @@ var samples = [ url: "multi-datasources-synchronized" }, { - name: 'Switch between Replay & realtime using SOS or SWEAPI service', - description: 'Switch between Replay & realtime using SOS or SWEAPI service', + name: 'Switch between Replay & realtime using SOS or Connected Systems API service', + description: 'Switch between Replay & realtime using SOS or Connected Systems API service', url: 'switch-realtime-batch' }, { diff --git a/showcase-dev/webpack.config.js b/showcase-dev/webpack.config.js index 6868f0d1ea..29f0ec0e49 100644 --- a/showcase-dev/webpack.config.js +++ b/showcase-dev/webpack.config.js @@ -77,7 +77,7 @@ module.exports = [{ let directories = [ 'datasource-audio', 'datasource-file', - 'datasource-sweapifetch', + 'datasource-consysapi', 'datasource-swejson', 'datasource-video', 'datasources-synchronized', diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/.browserslistrc b/showcase/examples/chart-archive-realtime-synchronized-consysapi/.browserslistrc similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/.browserslistrc rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/.browserslistrc diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/.eslintignore b/showcase/examples/chart-archive-realtime-synchronized-consysapi/.eslintignore similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/.eslintignore rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/.eslintignore diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/.eslintrc.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/.eslintrc.js similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/.eslintrc.js rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/.eslintrc.js diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/.gitignore b/showcase/examples/chart-archive-realtime-synchronized-consysapi/.gitignore similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/.gitignore rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/.gitignore diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/README.md b/showcase/examples/chart-archive-realtime-synchronized-consysapi/README.md similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/README.md rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/README.md diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/babel.config.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/babel.config.js similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/babel.config.js rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/babel.config.js diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/chart-archive-realtime-synchronized-sweapi.html b/showcase/examples/chart-archive-realtime-synchronized-consysapi/chart-archive-realtime-synchronized-consysapi.html similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/chart-archive-realtime-synchronized-sweapi.html rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/chart-archive-realtime-synchronized-consysapi.html diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/chart-archive-realtime-synchronized-sweapi.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/chart-archive-realtime-synchronized-consysapi.js similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/chart-archive-realtime-synchronized-sweapi.js rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/chart-archive-realtime-synchronized-consysapi.js diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/favicon.ico b/showcase/examples/chart-archive-realtime-synchronized-consysapi/favicon.ico similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/favicon.ico rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/favicon.ico diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-192x192.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-192x192.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-192x192.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-192x192.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-512x512.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-512x512.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-512x512.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-512x512.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-maskable-192x192.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-maskable-192x192.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-maskable-192x192.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-maskable-192x192.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-maskable-512x512.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-maskable-512x512.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/android-chrome-maskable-512x512.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/android-chrome-maskable-512x512.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-120x120.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-120x120.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-120x120.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-120x120.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-152x152.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-152x152.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-152x152.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-152x152.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-180x180.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-180x180.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-180x180.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-180x180.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-60x60.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-60x60.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-60x60.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-60x60.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-76x76.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-76x76.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon-76x76.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon-76x76.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/apple-touch-icon.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/apple-touch-icon.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/favicon-16x16.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/favicon-16x16.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/favicon-16x16.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/favicon-16x16.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/favicon-32x32.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/favicon-32x32.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/favicon-32x32.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/favicon-32x32.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/msapplication-icon-144x144.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/msapplication-icon-144x144.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/msapplication-icon-144x144.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/msapplication-icon-144x144.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/mstile-150x150.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/mstile-150x150.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/mstile-150x150.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/mstile-150x150.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/safari-pinned-tab.svg b/showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/safari-pinned-tab.svg similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/img/icons/safari-pinned-tab.svg rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/img/icons/safari-pinned-tab.svg diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/main.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/main.js similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/main.js rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/main.js diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/package.json b/showcase/examples/chart-archive-realtime-synchronized-consysapi/package.json similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/package.json rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/package.json diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/patches/nouislider+14.4.0.patch b/showcase/examples/chart-archive-realtime-synchronized-consysapi/patches/nouislider+14.4.0.patch similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/patches/nouislider+14.4.0.patch rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/patches/nouislider+14.4.0.patch diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/robots.txt b/showcase/examples/chart-archive-realtime-synchronized-consysapi/robots.txt similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/robots.txt rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/robots.txt diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/App.vue b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/App.vue similarity index 94% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/src/App.vue rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/src/App.vue index a97607cb1b..c28dd9a64e 100644 --- a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/App.vue +++ b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/App.vue @@ -18,7 +18,7 @@ import TimeController from 'osh-js/vue/components/TimeController.vue'; import DataSynchronizer from 'osh-js/core/timesync/DataSynchronizer'; import {Mode} from 'osh-js/core/datasource/Mode'; -import SweApiDatasource from "osh-js/core/datasource/sweapi/SweApi.datasource"; +import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js"; export default { components: { @@ -55,7 +55,7 @@ export default { prefetchBatchSize: 250 }; - const chartDataSource1 = new SweApiDatasource('Simulated Weather Sensor - weather', { + const chartDataSource1 = new ConSysApi('Simulated Weather Sensor - weather', { ...commonDatasourceOpts, resource: '/datastreams/0tsop3f16nvp8/observations', responseFormat: 'application/swe+json', diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/assets/logo.png b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/assets/logo.png similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/src/assets/logo.png rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/src/assets/logo.png diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/config/index.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/config/index.js similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/src/config/index.js rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/src/config/index.js diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/src/main.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/src/main.js similarity index 100% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/src/main.js rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/src/main.js diff --git a/showcase/examples/chart-archive-realtime-synchronized-sweapi/webpack.config.js b/showcase/examples/chart-archive-realtime-synchronized-consysapi/webpack.config.js similarity index 90% rename from showcase/examples/chart-archive-realtime-synchronized-sweapi/webpack.config.js rename to showcase/examples/chart-archive-realtime-synchronized-consysapi/webpack.config.js index c8e2b0315f..9c2d627a55 100644 --- a/showcase/examples/chart-archive-realtime-synchronized-sweapi/webpack.config.js +++ b/showcase/examples/chart-archive-realtime-synchronized-consysapi/webpack.config.js @@ -8,9 +8,9 @@ const path = require('path'); // Now, using the cesiumConfig in your real configuration const config = { - entry: path.resolve(__dirname,'chart-archive-realtime-synchronized-sweapi.js'), + entry: path.resolve(__dirname,'chart-archive-realtime-synchronized-consysapi.js'), output: { - filename: 'bundle.chart-archive-realtime-synchronized-sweapi.js', + filename: 'bundle.chart-archive-realtime-synchronized-consysapi.js', path: path.resolve(__dirname, 'dist'), }, @@ -85,15 +85,15 @@ const config = { compress: true, port: 9000, hot: true, - index: 'chart-archive-realtime-synchronized-sweapi.html', + index: 'chart-archive-realtime-synchronized-consysapi.html', https:true }, plugins: [ new VueLoaderPlugin(), new CleanWebpackPlugin(), new HtmlWebpackPlugin({ - template: path.resolve(__dirname, 'chart-archive-realtime-synchronized-sweapi.html'), - filename: './chart-archive-realtime-synchronized-sweapi.html', + template: path.resolve(__dirname, 'chart-archive-realtime-synchronized-consysapi.html'), + filename: './chart-archive-realtime-synchronized-consysapi.html', favicon: path.resolve(__dirname,'favicon.ico') }), new DefinePlugin({ diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.browserslistrc b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/.browserslistrc similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.browserslistrc rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/.browserslistrc diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.eslintignore b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/.eslintignore similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.eslintignore rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/.eslintignore diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.eslintrc.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/.eslintrc.js similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.eslintrc.js rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/.eslintrc.js diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.gitignore b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/.gitignore similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/.gitignore rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/.gitignore diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/README.md b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/README.md similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/README.md rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/README.md diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/babel.config.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/babel.config.js similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/babel.config.js rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/babel.config.js diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/favicon.ico b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/favicon.ico similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/favicon.ico rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/favicon.ico diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-192x192.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-192x192.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-192x192.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-192x192.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-512x512.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-512x512.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-512x512.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-512x512.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-192x192.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-192x192.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-192x192.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-192x192.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-512x512.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-512x512.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-512x512.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/android-chrome-maskable-512x512.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-120x120.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-120x120.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-120x120.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-120x120.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-152x152.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-152x152.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-152x152.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-152x152.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-180x180.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-180x180.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-180x180.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-180x180.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-60x60.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-60x60.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-60x60.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-60x60.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-76x76.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-76x76.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-76x76.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon-76x76.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/apple-touch-icon.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/favicon-16x16.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/favicon-16x16.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/favicon-16x16.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/favicon-16x16.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/favicon-32x32.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/favicon-32x32.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/favicon-32x32.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/favicon-32x32.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/msapplication-icon-144x144.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/msapplication-icon-144x144.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/msapplication-icon-144x144.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/msapplication-icon-144x144.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/mstile-150x150.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/mstile-150x150.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/mstile-150x150.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/mstile-150x150.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/safari-pinned-tab.svg b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/safari-pinned-tab.svg similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/img/icons/safari-pinned-tab.svg rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/img/icons/safari-pinned-tab.svg diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/main.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/main.js similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/main.js rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/main.js diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/package.json b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/package.json similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/package.json rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/package.json diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/patches/nouislider+14.4.0.patch b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/patches/nouislider+14.4.0.patch similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/patches/nouislider+14.4.0.patch rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/patches/nouislider+14.4.0.patch diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/robots.txt b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/robots.txt similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/robots.txt rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/robots.txt diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/App.vue b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/App.vue similarity index 93% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/App.vue rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/App.vue index 4d505c0e22..08a7919ccd 100644 --- a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/App.vue +++ b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/App.vue @@ -19,7 +19,7 @@ import TimeController from 'osh-js/vue/components/TimeController.vue'; import FFMPEGView from 'osh-js/core/ui/view/video/FFMPEGView'; import DataSynchronizer from 'osh-js/core/timesync/DataSynchronizer'; -import SweApiFetch from 'osh-js/core/datasource/sweapi/SweApi.datasource.js'; +import ConSysApi from 'osh-js/core/datasource/consysapi/ConSysApi.datasource.js'; import {Mode} from 'osh-js/core/datasource/Mode'; import VideoView from 'osh-js/core/ui/view/video/VideoView'; import VideoDataLayer from 'osh-js/core/ui/layer/VideoDataLayer'; @@ -49,19 +49,19 @@ export default { prefetchBatchSize: 250 }; - const dataSource0 = new SweApiFetch("drone-Video", { + const dataSource0 = new ConSysApi("drone-Video", { ...opts }); - const dataSource1 = new SweApiFetch("drone-Video1", { + const dataSource1 = new ConSysApi("drone-Video1", { ...opts }); - const dataSource2 = new SweApiFetch("drone-Video2", { + const dataSource2 = new ConSysApi("drone-Video2", { ...opts }); - const dataSource3 = new SweApiFetch("drone-Video3", { + const dataSource3 = new ConSysApi("drone-Video3", { ...opts }); diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/assets/logo.png b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/assets/logo.png similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/assets/logo.png rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/assets/logo.png diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/config/index.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/config/index.js similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/config/index.js rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/config/index.js diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/main.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/main.js similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/src/main.js rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/src/main.js diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.html b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.html similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.html rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.html diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.js similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.js rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/video-with-control-vuejs-synchronized.js diff --git a/showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/webpack.config.js b/showcase/examples/consysapi-video-with-control-vuejs-synchronized/webpack.config.js similarity index 100% rename from showcase/examples/sensorwebapi-video-with-control-vuejs-synchronized/webpack.config.js rename to showcase/examples/consysapi-video-with-control-vuejs-synchronized/webpack.config.js diff --git a/showcase/examples/mqtt/mqtt.js b/showcase/examples/mqtt/mqtt.js index e7fd0c9a61..a11c67f40a 100644 --- a/showcase/examples/mqtt/mqtt.js +++ b/showcase/examples/mqtt/mqtt.js @@ -1,5 +1,5 @@ // create data source for Android phone GPS -import SweApiFetch from 'osh-js/core/datasource/sweapi/SweApi.datasource.js'; +import ConSysApi from 'osh-js/core/datasource/consysapi/ConSysApi.datasource.js'; import PointMarkerLayer from 'osh-js/core/ui/layer/PointMarkerLayer.js'; import LeafletView from 'osh-js/core/ui/view/map/LeafletView.js'; import ChartJsView from 'osh-js/core/ui/view/chart/ChartJsView'; @@ -16,7 +16,7 @@ const mqttProps = { password: 'WR6zlso9h#' }; -let gpsDataSource = new SweApiFetch("android-GPS", { +let gpsDataSource = new ConSysApi("android-GPS", { endpointUrl: 'api.georobotix.io/ogc/t18/api', resource: '/datastreams/rbnag2hrc04mm/observations', tls: true, @@ -25,7 +25,7 @@ let gpsDataSource = new SweApiFetch("android-GPS", { mode: Mode.REAL_TIME }); -const isaDataSource = new SweApiFetch("ISA-bio-sensor", { +const isaDataSource = new ConSysApi("ISA-bio-sensor", { endpointUrl: 'api.georobotix.io/ogc/t18/api', resource: '/datastreams/b4runsn23q66o/observations', tls: true, diff --git a/showcase/examples/tasking/tasking.js b/showcase/examples/tasking/tasking.js index 79453ab3db..f21d037123 100644 --- a/showcase/examples/tasking/tasking.js +++ b/showcase/examples/tasking/tasking.js @@ -1,10 +1,10 @@ -import Systems from "osh-js/core/sweapi/system/Systems"; +import Systems from "osh-js/core/consysapi/system/Systems"; import {EventType} from "osh-js/core/event/EventType"; -import ControlFilter from "osh-js/core/sweapi/control/ControlFilter"; -import SweApiFetch from "osh-js/core/datasource/sweapi/SweApi.datasource"; +import ConSysApi from "osh-js/core/datasource/consysapi/ConSysApi.datasource.js"; import PointMarkerLayer from "osh-js/core/ui/layer/PointMarkerLayer"; import LeafletView from "osh-js/core/ui/view/map/LeafletView"; import PolylineLayer from "osh-js/core/ui/layer/PolylineLayer"; +import ControlStreamFilter from "../../../source/core/consysapi/controlstream/ControlStreamFilter"; var prevTime = 0; @@ -22,7 +22,7 @@ const mqttProps = { password: password }; -let gpsDataSource = new SweApiFetch("supersonic drone GPS", { +let gpsDataSource = new ConSysApi("supersonic drone GPS", { resource: `/api/datastreams/${posDsId}/observations`, endpointUrl: 'api.georobotix.io/ogc/t18/api', protocol: 'ws', @@ -101,9 +101,9 @@ async function startListening() { gpsDataSource.connect(); const system = await systems.getSystemById(systemId); - const control = await system.getControlById(cmdStreamId); + const control = await system.getControlStreamById(cmdStreamId); - control.streamStatus(new ControlFilter({}), async (message) =>{ + control.streamStatus(new ControlStreamFilter({}), async (message) =>{ textCommandElt.innerHTML = ""; const status = message; textStatusElt.innerHTML = JSON.stringify(status, null, 2); diff --git a/showcase/index.html b/showcase/index.html index 72adfd3df4..90d1bae864 100644 --- a/showcase/index.html +++ b/showcase/index.html @@ -201,6 +201,14 @@ height: 64px; width: 64px; } + + span.badge { + background-color: red; + color: white; + padding: 4px 8px; + text-align: center; + border-radius: 0px; + } </style> </head> @@ -224,13 +232,13 @@ <div id="card-template" hidden="true" aria-hidden="true"> <div class="col-md-4 p-3 d-flex"> <div class="card shadow-sm flex-fill"> + <span id="badge" class="badge">helo</span> <img class="bd-placeholder-img card-img-top" src=""/> <div class="card-body"> <p class="card-text" style="margin-bottom:50px">sample description</p> <div class="d-flex justify-content-between align-items-center" style="position:absolute; bottom:20px"> <div class="btn-group"> <button role="button" class="btn btn-sm btn-outline-secondary">View</button> - <!--<button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>--> </div> </div> </div> diff --git a/showcase/index.js b/showcase/index.js index 2efdf27a73..0ef3665a47 100644 --- a/showcase/index.js +++ b/showcase/index.js @@ -7,163 +7,193 @@ var Normalizer = require('prismjs/plugins/normalize-whitespace/prism-normalize-w var samples = [{ name: "FOI Locations (CesiumJS)", description: "Display the location of several features of interest on a CesiumJS globe.", - url: "cesium-fois" + url: "cesium-fois", + datasourceType: 'SOS', }, { name: "Moving Location (CesiumJS)", description: "Display a moving marker on a CesiumJS globe, tracking the current location of a vehicle.", - url: "cesium-location" + url: "cesium-location", + datasourceType: 'SOS', }, { name: "Moving Location with custom viewer properties(CesiumJS)", description: "Display a moving marker on a CesiumJS globe, tracking the current location of a vehicle and define some custom cesium viewer properties.", - url: "cesium-location-opts" + url: "cesium-location-opts", + datasourceType: 'SOS', }, { name: "Moving Location + path (CesiumJS)", description: "Display a moving marker and a polyline on a CesiumJS map, showing both the current location of a vehicle and the historical track.", - url: "cesium-location-path" + url: "cesium-location-path", + datasourceType: 'SOS', }, { name: "Moving Location (Deck.gl)", description: "Display a moving marker on a Deck.gl canvas, tracking the current location of a vehicle.", - url: "deckgl-location" + url: "deckgl-location", + datasourceType: 'SOS', }, { name: "Simple Chart (Chart.js)", description: "Display a chart with time series of weather measurements.", - url: "chart" + url: "chart", + datasourceType: 'SOS', }, { name: "Moving Location (Leaflet)", description: "Display a moving marker on a Leaflet map, tracking the current location of a vehicle.", - url: "leaflet-location" + url: "leaflet-location", + datasourceType: 'SOS', }, { name: "FOI Locations (Leaflet)", description: "Display the location of several features of interest on a Leaflet map.", url: "leaflet-location-fois", - screenshot: "images/screenshots/leaflet-fois.png" + screenshot: "images/screenshots/leaflet-fois.png", + datasourceType: 'SOS', }, { name: "Moving Location + Heading (Leaflet)", description: "Display a moving marker on a Leaflet map, tracking the current location and heading of a vehicle.", - url: "leaflet-location-heading" + url: "leaflet-location-heading", + datasourceType: 'SOS', }, { name: "Moving Location + Path (Leaflet)", description: "Display a moving marker and a polyline on a Leaflet map, showing both the current location of a vehicle and the historical track.", - url: "leaflet-location-path" + url: "leaflet-location-path", + datasourceType: 'SOS', }, { name: "Moving Location (OpenLayers)", description: "Display a moving marker on an OpenLayers map, tracking the current location of a vehicle.", - url: "openlayers-location" + url: "openlayers-location", + datasourceType: 'SOS', }, { name: "Moving Location + Heading (OpenLayers)", description: "Display a moving marker on an OpenLayers map, tracking the current location and heading of a vehicle.", - url: "openlayers-location-heading" + url: "openlayers-location-heading", + datasourceType: 'SOS', }, { name: "Moving Location + Path + Heading (Mapbox)", description: "Display a moving marker and a polyline on a Mapbox map, showing both the current location of a vehicle and the historical track.", - url: "mapbox-location-path-heading" + url: "mapbox-location-path-heading", + datasourceType: 'SOS', }, { name: "Moving Location + Heading + Video (Leaflet)", description: "Display a moving marker on an Leaflet map, tracking the current location of a vehicle and its corresponding" + "video. Create duplicated dataSources running at different time to check there is no collision between data. The " + "2 datasets are using a DataSynchronizer object. Each one should be independent.", - url: "video-map-multiple-datasource" + url: "video-map-multiple-datasource", + datasourceType: 'SOS', }, { name: "Z-Index ordering", description: "Display a moving marker on an Leaflet, DeckGl,Cesium and Openlayers map using a z-Index between markers", - url: "zIndex-location-path" + url: "zIndex-location-path", + datasourceType: 'SOS', }, { name: "Resizable H264 Video", description: "Display an H264 video in a simple resizable DIV using our FFMPEG-JS decoder.", - url: "video-h264" + url: "video-h264", + datasourceType: 'SOS', }, { name: "H264 Video using WebCodecAPI", description: "Display an H264 video in a simple DIV using Experimental Hardware WebCodecAPI decoder.", - url: "video-h264-webcodec-api" + url: "video-h264-webcodec-api", + datasourceType: 'SOS', }, { name: "H264 Image draping Video", description: "Display an H264 video in a simple DIV using our FFMPEG-JS decoder and drap the decoded frame onto the terrain.", - url: "video-h264-draping" + url: "video-h264-draping", + datasourceType: 'SOS', }, { name: "Resizable MJPEG Video", description: "Display an MJPEG video in a simple resizable DIV.", - url: "video-mjpeg" + url: "video-mjpeg", + datasourceType: 'SOS', }, { name: 'VueJs component: Multiple Video with control', description: 'Display multiple videos using forward/pause/play/backward control using the same DataSynchronizer', url: 'video-with-control-vuejs-synchronized', - code: 'vue/App_examples/video-with-control-vuejs-synchronized.vue' + code: 'vue/App_examples/video-with-control-vuejs-synchronized.vue', + datasourceType: 'SOS', }, { name: 'AVL data using multiple ids', description: 'Display multiple markers corresponding to a unique id provided by the same DataSource', - url: 'avl' + url: 'avl', + datasourceType: 'SOS', }, { name: 'AVL data using multiple ids and Time controller in VueJS', description: 'Display multiple markers corresponding to a unique id provided by the same DataSource with a Time controller in VueJS', url: 'avl-with-control-vuejs', - code: 'vue/App_examples/avl-with-control-vuejs.vue' + code: 'vue/App_examples/avl-with-control-vuejs.vue', + datasourceType: 'SOS', }, { name: 'ISA Biological & MISB UAS sensor data using MQTT protocol', description: 'Display biological and GPS sensors from ISA Biological Sensor & MISB UAS using MQTT protocol', - url: 'mqtt' + url: 'mqtt', + datasourceType: 'Connected Systems', }, { name: "Chart with Time controller (Chart.js)", description: "Display a chart with time series of weather measurements and time controller.", url: "chart-archive-realtime", - code: 'vue/App_examples/chart-archive-realtime.vue' + code: 'vue/App_examples/chart-archive-realtime.vue', + datasourceType: 'SOS', }, { name: "Chart with Time controller (Chart.js) in batch mode", description: "Display a chart using full batch mode with time series of weather measurements and time controller.", url: "chart-archive-realtime-batch", - code: 'vue/App_examples/chart-archive-realtime-batch.vue' + code: 'vue/App_examples/chart-archive-realtime-batch.vue', + datasourceType: 'SOS', }, { name: "Chart with Time controller and Synchronizer (Chart.js)", description: "Display a chart with time series of weather measurements and time controller.", url: "chart-archive-realtime-synchronized", - code: 'vue/App_examples/chart-archive-realtime-synchronized.vue' + code: 'vue/App_examples/chart-archive-realtime-synchronized.vue', + datasourceType: 'SOS', }, { name: "Chart with Time controller and Synchronizer using 'trackRealtime' option(Chart.js)", description: "Display a chart with time series of weather measurements and time controller and tracking realtime.", - url: "chart-archive-realtime-synchronized-sweapi", - code: 'vue/App_examples/chart-archive-realtime-synchronized-sweapi.vue' + url: "chart-archive-realtime-synchronized-consysapi", + code: 'vue/App_examples/chart-archive-realtime-synchronized-consysapi.vue', + datasourceType: 'Connected Systems', }, { name: "Audio WebCodec/FFmpeg.js decoding", description: "Listen audio stream using WebCodec/FFmpeg.js", - url: "audio" + url: "audio", + datasourceType: 'SOS', }, { name: "Audio WebCodec/FFmpeg.js decoding with time controller", description: "Listen audio stream using WebCodec/FFmpeg.js with time controller", url: 'audio-with-control-vuejs', - code: 'vue/App_examples/audio-with-control-vuejs.vue' + code: 'vue/App_examples/audio-with-control-vuejs.vue', + datasourceType: 'SOS', }, { name: "Audio & Video WebCodec/FFmpeg.js decoding with time controller", description: "Listen audio stream using WebCodec/FFmpeg.js with time controller and associated Video", url: 'audio-video-synchronized-with-control-vuejs', - code: 'vue/App_examples/audio-video-synchronized-with-control-vuejs.vue' + code: 'vue/App_examples/audio-video-synchronized-with-control-vuejs.vue', + datasourceType: 'SOS', } ]; @@ -172,6 +202,10 @@ var currentSample; samples.forEach(s => { var $newElt = $($("#card-template").html()); $("p.card-text", $newElt).html(s.description); + + $("span.badge", $newElt).text(s.datasourceType); + $("span.badge", $newElt).css("background-color", s.datasourceType === "SOS" ? "gray" : "red"); + $("img", $newElt) .on("error", e => e.target.src = "https://opensensorhub.files.wordpress.com/2017/08/opensensorhub-logo2.png") .attr("title", s.name) diff --git a/showcase/webpack.config.js b/showcase/webpack.config.js index d84c80b186..7eda5d1c08 100644 --- a/showcase/webpack.config.js +++ b/showcase/webpack.config.js @@ -102,7 +102,7 @@ let directories = [ 'chart-archive-realtime', 'chart-archive-realtime-batch', 'chart-archive-realtime-synchronized', - 'chart-archive-realtime-synchronized-sweapi', + 'chart-archive-realtime-synchronized-consysapi', 'audio', 'audio-with-control-vuejs', 'audio-video-synchronized-with-control-vuejs', diff --git a/source/core/OSH.js b/source/core/OSH.js index 9a7b051afe..69f753a723 100644 --- a/source/core/OSH.js +++ b/source/core/OSH.js @@ -9,6 +9,7 @@ export { default as DataSynchronizer } from './timesync/DataSynchronizer.js'; export { default as DataSource } from './datasource/DataSource.js'; export { default as SosGetResult } from './datasource/sos/SosGetResult.js'; export { default as SweApiFetch } from './datasource/sweapi/SweApiFetch.js'; +export { default as ConSysApi } from './datasource/consysapi/ConSysApi.datasource.js' export { default as OrientationQuaternion } from '../ext/datasource/OrientationQuaternion.js'; export { default as SosGetFois } from './datasource/sos/SosGetFois.js'; export { default as TimeSeriesDataSource } from './datasource/TimeSeriesDataSource.js'; @@ -50,31 +51,59 @@ export { default as AudioFrequencyChartJsVisualizer } from './ui/view/audio/vis export { default as AudioSpectrogramVisualizer } from './ui/view/audio/visualizer/spectrogram/AudioSpectrogramVisualizer.js'; export { default as AudioRollingSpectrogramCanvasVisualizer } from './ui/view/audio/visualizer/spectrogram/AudioRollingSpectrogramCanvasVisualizer.js'; export { default as View } from './ui/view/View.js'; -export { default as Command } from './sweapi/command/Command.js'; -export { default as Commands } from './sweapi/command/Commands.js'; -export { default as CommandFilter } from './sweapi/command/CommandFilter.js'; -export { default as Control } from './sweapi/control/Control.js'; -export { default as Controls } from './sweapi/control/Controls.js'; -export { default as ControlFilter } from './sweapi/control/ControlFilter.js'; -export { default as DataStream } from './sweapi/datastream/DataStream.js'; -export { default as DataStreams } from './sweapi/datastream/DataStreams.js'; -export { default as DataStreamFilter } from './sweapi/datastream/DataStreamFilter.js'; -export { default as Event } from './sweapi/event/Event.js'; -export { default as Events } from './sweapi/event/Events.js'; -export { default as EventFilter } from './sweapi/event/EventFilter.js'; -export { default as FeatureOfInterest } from './sweapi/featureofinterest/FeatureOfInterest.js'; -export { default as FeatureOfInterests } from './sweapi/featureofinterest/FeatureOfInterests.js'; -export { default as FeatureOfInterestFilter } from './sweapi/featureofinterest/FeatureOfInterestFilter.js'; -export { default as SystemHistoryFilter } from './sweapi/history/SystemHistoryFilter.js'; -export { default as Observation } from './sweapi/observation/Observation.js'; -export { default as Observations } from './sweapi/observation/Observations.js'; -export { default as ObservationFilter } from './sweapi/observation/ObservationFilter.js'; -export { default as System } from './sweapi/system/System.js'; -export { default as Systems } from './sweapi/system/Systems.js'; -export { default as SystemFilter } from './sweapi/system/SystemFilter.js'; -export { default as Collection } from './sweapi/Collection.js'; -export { default as ObservationsCollection } from './sweapi/ObservationsCollection.js'; -export { default as SensorWebApi } from './sweapi/SensorWebApi.js'; +// SWE API +// export { default as Command } from './sweapi/command/Command.js'; +// export { default as Commands } from './sweapi/command/Commands.js'; +// export { default as CommandFilter } from './sweapi/command/CommandFilter.js'; +// export { default as Control } from './sweapi/control/Control.js'; +// export { default as Controls } from './sweapi/control/Controls.js'; +// export { default as ControlFilter } from './sweapi/control/ControlFilter.js'; +// export { default as DataStream } from './sweapi/datastream/DataStream.js'; +// export { default as DataStreams } from './sweapi/datastream/DataStreams.js'; +// export { default as DataStreamFilter } from './sweapi/datastream/DataStreamFilter.js'; +// export { default as Event } from './sweapi/event/Event.js'; +// export { default as Events } from './sweapi/event/Events.js'; +// export { default as EventFilter } from './sweapi/event/EventFilter.js'; +// export { default as FeatureOfInterest } from './sweapi/featureofinterest/FeatureOfInterest.js'; +// export { default as FeatureOfInterests } from './sweapi/featureofinterest/FeatureOfInterests.js'; +// export { default as FeatureOfInterestFilter } from './sweapi/featureofinterest/FeatureOfInterestFilter.js'; +// export { default as SystemHistoryFilter } from './sweapi/history/SystemHistoryFilter.js'; +// export { default as Observation } from './sweapi/observation/Observation.js'; +// export { default as Observations } from './sweapi/observation/Observations.js'; +// export { default as ObservationFilter } from './sweapi/observation/ObservationFilter.js'; +// export { default as System } from './sweapi/system/System.js'; +// export { default as Systems } from './sweapi/system/Systems.js'; +// export { default as SystemFilter } from './sweapi/system/SystemFilter.js'; +// export { default as Collection } from './sweapi/Collection.js'; +// export { default as ObservationsCollection } from './sweapi/ObservationsCollection.js'; +// export { default as SensorWebApi } from './sweapi/SensorWebApi.js'; +// Connected Systems API +export { default as Command } from './consysapi/command/Command.js'; +export { default as Commands } from './consysapi/command/Commands.js'; +export { default as CommandFilter } from './consysapi/command/CommandFilter.js'; +export { default as ControlStream } from './consysapi/controlstream/ControlStream.js'; +export { default as ControlStreams } from './consysapi/controlstream/ControlStreams.js'; +export { default as ControlStreamFilter } from './consysapi/controlstream/ControlStreamFilter.js'; +export { default as DataStream } from './consysapi/datastream/DataStream.js'; +export { default as DataStreams } from './consysapi/datastream/DataStreams.js'; +export { default as DataStreamFilter } from './consysapi/datastream/DataStreamFilter.js'; +export { default as Event } from './consysapi/event/Event.js'; +export { default as Events } from './consysapi/event/Events.js'; +export { default as EventFilter } from './consysapi/event/EventFilter.js'; +export { default as SamplingFeature } from './consysapi/samplingfeature/SamplingFeature.js'; +export { default as SamplingFeatures } from './consysapi/samplingfeature/SamplingFeatures.js'; +export { default as SamplingFeatureFilter } from './consysapi/samplingfeature/SamplingFeatureFilter.js'; +export { default as SystemHistoryFilter } from './consysapi/history/SystemHistoryFilter.js'; +export { default as Observation } from './consysapi/observation/Observation.js'; +export { default as Observations } from './consysapi/observation/Observations.js'; +export { default as ObservationFilter } from './consysapi/observation/ObservationFilter.js'; +export { default as System } from './consysapi/system/System.js'; +export { default as Systems } from './consysapi/system/Systems.js'; +export { default as SystemFilter } from './consysapi/system/SystemFilter.js'; +export { default as Collection } from './consysapi/Collection.js'; +export { default as ObservationsCollection } from './consysapi/ObservationsCollection.js'; +export { default as ConnectedSystemsApi } from './consysapi/ConnectedSystemsApi.js'; + export { default as File } from '../ext/datasource/File.js'; export { default as FileConnector } from '../ext/connector/FileConnector.js'; diff --git a/source/core/connector/MqttConnector.js b/source/core/connector/MqttConnector.js index 59a8494c48..f49ff5846c 100644 --- a/source/core/connector/MqttConnector.js +++ b/source/core/connector/MqttConnector.js @@ -15,10 +15,9 @@ ******************************* END LICENSE BLOCK ***************************/ import DataConnector from "./DataConnector"; -import {assertDefined, isDefined, randomUUID} from "../utils/Utils"; +import {isDefined, randomUUID} from "../utils/Utils"; import {Status} from "./Status"; import MqttProvider from "../mqtt/MqttProvider"; -import ObservationFilter from "../sweapi/observation/ObservationFilter"; /** * Defines the MqttConnector to connect to a remote server by creating a Mqtt channel. diff --git a/source/core/consysapi/Collection.js b/source/core/consysapi/Collection.js new file mode 100644 index 0000000000..61dd9bd149 --- /dev/null +++ b/source/core/consysapi/Collection.js @@ -0,0 +1,135 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2021 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import SweCollectionDataParser from "../parsers/consysapi/collection/SweCollectionDataParser"; + +class Collection { + /** + * + */ + constructor(url, filter, pageSize, parser, responseFormat = 'json') { + this.url = url; + this.filter = filter; + this.pageSize = pageSize; + this.parser = parser; + this.pageOffset = 0; + this.init = false; + this.total = 0; + this.collectionDataParser = new SweCollectionDataParser(filter.props.format); + this.responseFormat = responseFormat; + this.currentPage = -1; + } + + /** + * Check if has next page + * @return {boolean} + */ + hasNext() { + return this.pageOffset !== -1; + } + + async fetchData(offset) { + const queryString = `${this.filter.toQueryString()}&offset=${offset}&limit=${this.pageSize}`; + const fullUrl = this.url + '?' + queryString; + + const jsonResponse = await fetch(fullUrl, { + method: 'GET', + credentials: 'include', + headers: {} + }).then((response) => { + if (!response.ok) { + const err = new Error(`Got ${response.status} response from ${fullUrl}`); + err.response = response; + throw err; + } + if (this.responseFormat === 'json') { + return response.json(); + } else if (this.responseFormat === 'arraybuffer') { + return response.arrayBuffer(); + } + }); + + return this.parseResponse(jsonResponse); + } + + async parseResponse(jsonResponse) { + const items = this.collectionDataParser.parseData(jsonResponse); + const data = []; + if (Array.isArray(items)) { + for (let item of items) { + data.push(this.parser.parseData(item)); + } + } else { + data.push(items); + } + return data; + } + + /** + * Fetches next page. + * @param page - the number of page to fetch + * @return {Promise<Array>} + */ + async nextPage() { + if (this.hasNext()) { + this.currentPage++; + this.pageOffset = this.currentPage * this.pageSize; + const data = await this.fetchData(this.pageOffset); + if (data.length === 0 || data.length < this.pageSize) { + this.pageOffset = -1; + } + return data; + } else { + throw Error('Has no more pages'); + } + } + + async page(page) { + this.currentPage = page; + this.pageOffset = this.currentPage * this.pageSize; + const data = await this.fetchData(this.pageOffset); + if (data.length === 0 || data.length < this.pageSize) { + this.pageOffset = -1; + } + return data; + } + + /** + * Fetches previous page. + * @param page - the number of page to fetch + * @return {Promise<Array>} + */ + async previousPage() { + if (this.hasPrevious()) { + this.currentPage--; + this.pageOffset = this.currentPage * this.pageSize; + return this.fetchData(this.pageOffset); + } else { + throw Error('Has no more pages'); + } + } + + /** + * Check if has previous page + * @return {boolean} + */ + hasPrevious() { + return this.currentPage > 0; + } + +} + +export default Collection; diff --git a/source/core/consysapi/ConnectedSystemsApi.js b/source/core/consysapi/ConnectedSystemsApi.js new file mode 100644 index 0000000000..6ddcf0d891 --- /dev/null +++ b/source/core/consysapi/ConnectedSystemsApi.js @@ -0,0 +1,160 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import WebSocketConnector from "../connector/WebSocketConnector"; +import {assertDefined, isDefined} from "../utils/Utils"; +import MqttTopicConnector from "../connector/MqttTopicConnector"; +import MqttConnector from "../connector/MqttConnector"; + +class ConnectedSystemsApi { + + /** + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + * @param {Object} networkProperties.connectorOpts - Specific connector options + */ + constructor(networkProperties) { + assertDefined(networkProperties.endpointUrl, 'endpointUrl'); + this.networkProperties = networkProperties; + + let endpoint = networkProperties.endpointUrl; + if (endpoint.endsWith('/')) { + endpoint = endpoint.substring(0, endpoint.length - 1); + } + + const tls = (networkProperties.tls) ? 's' : ''; + this.url = 'http' + tls + '://' + endpoint; + + this._network = {} + if (isDefined(networkProperties.connector)) { + this._network.stream = { + connector: networkProperties.connector, + }; + } else if(isDefined(networkProperties.streamProtocol)){ + this._network.stream = { + connector: this.createStreamConnector(networkProperties) + } + } else { + // default Stream to WS + this._network.stream = { + connector: this.createStreamConnector({ + ...networkProperties, + streamProtocol: 'ws' + }) + } + } + } + + baseUrl() { + return this.url; + } + + stream() { + return this._network.stream.connector; + } + + createStreamConnector(networkProperties) { + assertDefined(networkProperties.streamProtocol, 'streamProtocol'); + + let endpoint = networkProperties.endpointUrl; + if(networkProperties.streamProtocol === 'mqtt' && isDefined(networkProperties.mqttOpts)) { + endpoint = networkProperties.mqttOpts.endpointUrl; + } + + if (endpoint.endsWith('/')) { + endpoint = endpoint.substring(0, endpoint.length - 1); + } + + const tls = (networkProperties.tls) ? 's' : ''; + const url = networkProperties.streamProtocol + tls + '://' + endpoint; + + if(networkProperties.streamProtocol === 'mqtt') { + // return new MqttConnector(url, networkProperties); + return new MqttTopicConnector(networkProperties.mqttOpts.bcId, networkProperties); + } else if(networkProperties.streamProtocol === 'ws') { + return new WebSocketConnector(url); + } + } + + connect() { + this._network.stream.connector.connect(); + } + + getHeaders() { + const headers = { + }; + + if('connectorOpts' in this.networkProperties){ + if('username' in this.networkProperties.connectorOpts && 'password' in this.networkProperties.connectorOpts) { + headers['Authorization'] = 'Basic ' + + btoa(this.networkProperties.connectorOpts.username + ":" + this.networkProperties.connectorOpts.password); + } else { + for(let key in this.networkProperties.connectorOpts) { + headers[key] = this.networkProperties.connectorOpts[key]; + } + } + } + return headers; + } + + fetchAsJson(apiUrl, queryString) { + const fullUrl = this.baseUrl() + apiUrl + '?' +queryString; + + const headers = this.getHeaders(); + + return fetch(fullUrl, { + method: 'GET', + credentials: 'include', + headers: headers + } + ).then(function (response) { + if (!response.ok) { + const err = new Error(`Got ${response.status} response from ${this.baseUrl()}`); + err.response = response; + throw err; + } + return response.json(); + }); + } + + postAsJson(apiUrl, jsonPayload) { + const fullUrl = this.baseUrl() + apiUrl; + + const headers = this.getHeaders(); + + headers['Accept'] = 'application/json'; + headers['Content-Type'] = 'application/json'; + + fetch(fullUrl, { + method: 'POST', + headers: headers, + credentials: 'include', + body: jsonPayload + }).then(function (response) { + if (!response.ok) { + const err = new Error(`Got ${response.status} response from ${fullUrl}`); + err.response = response; + throw err; + } + }); + } +} +export default ConnectedSystemsApi; diff --git a/source/core/consysapi/Filter.js b/source/core/consysapi/Filter.js new file mode 100644 index 0000000000..36c78abc74 --- /dev/null +++ b/source/core/consysapi/Filter.js @@ -0,0 +1,58 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2021 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import {isDefined} from "../utils/Utils"; + +class ConnectedSystemsApiFilter { + constructor(props) { + this.props = props; + } + + /** + * + * @param {string[]} [includes=[]] list of parameters to include - all if omitted + * @param {string[]} [excludes=[]] list of parameters to exclude - none if omitted + * @return {string} + */ + toQueryString(includes= [], excludes = []) { + let queryString = ''; + let separator = ''; + excludes.push('replaySpeed'); + for (let queryParameter in this.props) { + if(excludes.includes(queryParameter)) { + continue; + } + if((includes.length === 0 || includes.includes(queryParameter)) && isDefined(this.props[queryParameter])) { + // if(Array.isArray(this.props[queryParameter])) { + // queryString += separator + queryParameter + '=' + encodeURIComponent(this.props[queryParameter].join()); + /*} else*/ if(queryParameter === 'f' + || queryParameter === 'format' + || queryParameter === 'responseFormat' + || queryParameter === 'obsFormat' + ) { + queryString += separator + queryParameter + '=' + this.props[queryParameter].replaceAll('+','%2B'); + // } else { + // queryString += separator + queryParameter + '=' + encodeURIComponent(this.props[queryParameter]); + } else { + queryString += separator + queryParameter + '=' + this.props[queryParameter]; + } + separator = '&'; + } + } + return queryString; + } +} +export default ConnectedSystemsApiFilter; diff --git a/source/core/consysapi/ObservationsCollection.js b/source/core/consysapi/ObservationsCollection.js new file mode 100644 index 0000000000..f24f09d315 --- /dev/null +++ b/source/core/consysapi/ObservationsCollection.js @@ -0,0 +1,32 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2021 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import Collection from "./Collection"; + +class ObservationsCollection extends Collection { + /** + * + */ + constructor(url, filter, pageSize, parser) { + super(url,filter ,pageSize ,parser, 'arraybuffer'); + } + + async parseResponse(encodedResponse) { + return this.parser.parseDataBlock(encodedResponse,this.filter.props.format); + } +} + +export default ObservationsCollection; diff --git a/source/core/consysapi/command/Command.js b/source/core/consysapi/command/Command.js new file mode 100644 index 0000000000..0d4ddf9e59 --- /dev/null +++ b/source/core/consysapi/command/Command.js @@ -0,0 +1,82 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import Collection from "../Collection"; +import API from "../routes.conf"; +import CommandFilter from "./CommandFilter"; +import SweCollectionDataParser from "../../parsers/consysapi/collection/SweCollectionDataParser"; +import ConSysApiResultControlStreamParser from "../../parsers/consysapi/observations/ConSysApiResult.controlstream.parser"; + +class Command extends ConnectedSystemsApi { + /** + * @param {Object} properties - the properties of the object + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(properties, networkProperties) { + super(networkProperties); // network properties + this.properties = properties; + this.jsonParser = new SweCollectionDataParser(networkProperties); + this.sweParser = new ConSysApiResultControlStreamParser(this); + } + + /** + * Get all status messages associated to a specific command + * route: /systems/{sysid}/controlstreams/{csid}/commands/{cmdid}/status + * @param {CommandFilter} [commandFilter== new CommandFilter()] - default Command filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<JSON>>} - response as JSON + */ + async searchStatus(commandFilter = new CommandFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.commands.status.replace('{sysid}',this.properties['system@id']) + .replace('{csid}', this.properties['controlstream@id']) + .replace('{cmdid}', this.properties.id), + commandFilter, + pageSize, + this.jsonParser + ); + } + + /** + * Stream all status messages associated to a specific command + * route: /systems/{sysid}/controlstreams/{csid}/commands/{cmdid}/status + * @param {CommandFilter} [commandFilter== new CommandFilter()] - default Command filter + * @param {Function} callback + */ + streamStatus(commandFilter = new CommandFilter(), callback = function(){}) { + this.stream().onMessage = async (message) => { + const dataBlock = await this.sweParser.parseDataBlock(message,commandFilter.props.format); + callback(dataBlock); + }; + + this.stream().doRequest( + API.commands.status.replace('{sysid}',this.properties['system@id']) + .replace('{csid}', this.properties['controlstream@id']) + .replace('{cmdid}', this.properties.id), + commandFilter.toQueryString(), + 'arraybuffer' + ); + } +} + +export default Command; diff --git a/source/core/consysapi/command/CommandFilter.js b/source/core/consysapi/command/CommandFilter.js new file mode 100644 index 0000000000..3ddb972f97 --- /dev/null +++ b/source/core/consysapi/command/CommandFilter.js @@ -0,0 +1,52 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2021 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApiFilter from "../Filter"; + +class CommandFilter extends ConnectedSystemsApiFilter { + /** + * + * @param {Object} properties - object properties + * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search + * @param {string[]} [properties.actuableProperty=undefined] - Comma separated list of actuable property URIs to filter command streams + * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude) + * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for + * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response. + * @param {string} [properties.issueTime=undefined] - ISO 8601 time range to filter commands on their issue time. When this parameter is omitted, + * no filtering on "issueTime" is applied. + * @param {string} [properties.executionTime=undefined] - ISO 8601 time range to filter commands on their execution time. + * When this parameter is omitted, no filtering on "executionTime" is applied + * @param {string} [properties.reportTime=undefined] - ISO 8601 time range to filter status messages on their report time. When this parameter is omitted, + * no filtering on "reportTime" is applied. + * @param {string[]} [properties.statusCode=undefined] - Comma separated list of status codes: PENDING, ACCEPTED, REJECTED, SCHEDULED, UPDATED, CANCELED, EXECUTING, FAILED, COMPLETED + */ + constructor(properties) { + super({ + q: undefined, + actuableProperty: undefined, + select: undefined, + foi: undefined, + format: 'application/json', + issueTime: undefined, + executionTime: undefined, + reportTime: undefined, + statusCode: undefined, + ...properties // merge defined properties + }); + //TODO: assertions + } +} +export default CommandFilter; diff --git a/source/core/consysapi/command/Commands.js b/source/core/consysapi/command/Commands.js new file mode 100644 index 0000000000..2db48b3e38 --- /dev/null +++ b/source/core/consysapi/command/Commands.js @@ -0,0 +1,66 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConSysApiFetchCommandParser from "../../parsers/consysapi/collection/ConSysApiFetchCommand.parser"; +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import Collection from "../Collection"; +import API from "../routes.conf"; +import CommandFilter from "./CommandFilter"; + +class Commands extends ConnectedSystemsApi { + /** + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(networkProperties) { + super(networkProperties); // network properties + this.conSysApiCommandParser = new ConSysApiFetchCommandParser(networkProperties, undefined); + } + + /** + * List or search all commands available through this API. + * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<Command>>} - A Collection of Command + */ + async searchCommands(commandFilter = new CommandFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.commands.search, + commandFilter, + pageSize, + this.conSysApiCommandParser + ); + } + + /** + * Get a specific command resource by ID + * @param {string} commandId - ID of requested command + * @return {Promise<Command>} - The corresponding Command + */ + async getCommandById(commandId) { + const apiUrl = API.commands.by_id.replace('{cmdid}',commandId); + const jsonData = await this.fetchAsJson(apiUrl, undefined); + return this.conSysApiCommandParser.parseData(jsonData); + } + +} + +export default Commands; diff --git a/source/core/consysapi/controlstream/ControlStream.js b/source/core/consysapi/controlstream/ControlStream.js new file mode 100644 index 0000000000..82c1c16bf6 --- /dev/null +++ b/source/core/consysapi/controlstream/ControlStream.js @@ -0,0 +1,179 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import CommandFilter from "../command/CommandFilter"; +import Collection from "../Collection"; +import API from "../routes.conf"; +import ControlStreamFilter from "./ControlStreamFilter"; +import ObservationsCollection from "../ObservationsCollection"; +import ConSysApiFetchCommandParser from "../../parsers/consysapi/collection/ConSysApiFetchCommand.parser"; +import ConSysApiResultCollectionControlStreamParser + from "../../parsers/consysapi/observations/ConSysApiResult.collection.controlstream.parser"; +import ConSysApiResultControlStreamParser from "../../parsers/consysapi/observations/ConSysApiResult.controlstream.parser"; +import ConSysApiControlStreamStatusParser from "../../parsers/consysapi/collection/ConSysApiControlStreamStatus.parser"; + +class ControlStream extends ConnectedSystemsApi { + /** + * @param {Object} properties - the properties of the object + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(properties, networkProperties) { + super(networkProperties); // network properties + this.properties = properties; + this.commandParser = new ConSysApiFetchCommandParser(networkProperties, this.properties['system@id']); + this.conSysApiResultCollectionControlStreamParser = new ConSysApiResultCollectionControlStreamParser(this); + this.conSysApiResultControlStreamParser = new ConSysApiResultControlStreamParser(this); + this.conSysApiControlStreamStatusParser = new ConSysApiControlStreamStatusParser(); + } + + /** + * Get the list of commands received by a particular control interface + * route: /systems/{sysid}/controlstreams/{csid}/commands + * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<JSON>>} - result as JSON + */ + async searchCommands(commandFilter = new CommandFilter(), pageSize= 10) { + return new ObservationsCollection( + this.baseUrl() + API.controlstreams.commands.replace('{sysid}', + this.properties['system@id']).replace('{csid}',this.properties.id), + commandFilter, + pageSize, + this.conSysApiResultCollectionControlStreamParser + ); + } + + /** + * Stream all commands received by a particular control interface + * route: /systems/{sysid}/controlstreams/{csid}/commands + * @param {ControlStreamFilter} [controlStreamFilter= new ControlStreamFilter()] - default ControlStreamStream filter + * @param {Function} callback - A callback to get observations + */ + streamCommands(controlStreamFilter = new ControlStreamFilter(), callback = function(){}) { + this.stream().onMessage = async (message) => { + const dataBlock = await this.conSysApiResultControlStreamParser.parseDataBlock(message,controlStreamFilter.props.format); + callback(dataBlock); + }; + + this.stream().doRequest( + API.controlstreams.commands.replace('{sysid}',this.properties['system@id']).replace('{csid}',this.properties.id), + controlFilter.toQueryString(), + 'arraybuffer' + ); + } + + /** + * Get a specific command resource by ID. + * route: /systems/{sysid}/controlstreams/{csid}/commands/{cmdid} + * @param {String} commandId - the ID of the Command resource + * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter + * @returns {Promise<Command>} - The corresponding Command + */ + async getCommandById(commandId,commandFilter = new CommandFilter()) { + const apiUrl = API.controlstreams.command_by_id + .replace('{sysid}',this.properties['system@id']) + .replace('{csid}', this.properties.id) + .replace('{cmdid}', commandId); + const queryString = commandFilter.toQueryString(['select', 'obsFormat']); //TODO: check useless obsFormat + const jsonData = await this.fetchAsJson(apiUrl, queryString); + return this.commandParser.parseData(jsonData); + } + + /** + * Send a new command to this control interface + * route: /systems/{sysid}/controlstreams/{csid}/commands + * @param {JSON} jsonPayload - the JSON payload + * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter specifying the 'sysid' and 'csid' + */ + postCommand(jsonPayload, commandFilter = new CommandFilter()) { + const apiUrl = API.controlstreams.commands + .replace('{sysid}',this.properties['system@id']) + .replace('{csid}', this.properties.id); + this.postAsJson(apiUrl, jsonPayload); + } + + /** + * Send a new command to this control interface using streaming protocol such like WS or MQTT + * route: /systems/{sysid}/controlstreams/{csid}/commands + * @param {JSON} jsonPayload - the JSON payload + * @param {CommandFilter} [commandFilter=new CommandFilter()] - default Command filter specifying the 'sysid' and 'csid' + */ + publishCommand(payload, commandFilter = new CommandFilter()) { + this.stream().publishRequest( + API.controlstreams.commands + .replace('{sysid}',this.properties['system@id']) + .replace('{csid}', this.properties.id), + payload + ); + } + + /** + * Get all status messages sent by this control interface + * route: /systems/{sysid}/controlstreams/{csid}/status + * @param {ControlStreamFilter} [controlStreamFilter=new ControlStreamFilter()] - default ControlStream filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<JSON>>} - A Collection of JSON + */ + async searchStatus(controlStreamFilter = new ControlStreamFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.controlstreams.status.replace('{sysid}',this.properties['system@id']).replace('{csid}', + this.properties.id), + controlStreamFilter, + pageSize, + this.conSysApiControlStreamStatusParser + ); + } + + /** + * Stream all status messages sent by this control interface + * route: /systems/{sysid}/controlstreams/{csid}/status + * @param {ControlStreamFilter} [controlStreamFilter= new ControlStreamFilter()] - default ControlStream filter + * @param {Function} callback - A callback to get observations + */ + streamStatus(controlStreamFilter = new ControlStreamFilter(), callback = function(){}) { + this.stream().onMessage = async (message) => { + const dataBlock = await this.conSysApiControlStreamStatusParser.parseData(message, 'arraybuffer'); + callback(dataBlock); + }; + + this.stream().doRequest( + API.controlstreams.status.replace('{sysid}',this.properties['system@id']).replace('{csid}',this.properties.id), + controlStreamFilter.toQueryString(), + 'arraybuffer' + ); + } + + /** + * Get the detailed schema of command messages in a command stream + * route: /systems/{sysid}/controlstreams/{csid}/schema + * @param {ControlStreamFilter} [controlStreamFilter= new ControlStreamFilter()] - default ControlStream filter, using 'commandFormat' to select response format + * @returns {Promise<JSON>} - The schema as JSON + */ + async getSchema(controlStreamFilter = new ControlStreamFilter()) { + const apiUrl = API.controlstreams.schema.replace('{sysid}',this.properties['system@id']).replace('{csid}',this.properties.id); + const queryString = controlStreamFilter.toQueryString(['select', 'commandFormat']); + return this.fetchAsJson(apiUrl, queryString); + } +} + +export default ControlStream; diff --git a/source/core/consysapi/controlstream/ControlStreamFilter.js b/source/core/consysapi/controlstream/ControlStreamFilter.js new file mode 100644 index 0000000000..d2e5f3c141 --- /dev/null +++ b/source/core/consysapi/controlstream/ControlStreamFilter.js @@ -0,0 +1,45 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApiFilter from "../Filter"; + +class ControlStreamFilter extends ConnectedSystemsApiFilter { + /** + * + * @param {Object} properties - object properties + * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search + * @param {string[]} [properties.actuableProperty=undefined] - Comma separated list of actuable property URIs to filter command streams + * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude) + * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for + * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response. + * @param {string} [properties.issueTime=undefined] - ISO 8601 time range to filter commands on their issue time. When this parameter is omitted, + * no filtering on "issueTime" is applied. + */ + constructor(properties) { + super({ + q: undefined, + actuableProperty: undefined, + observedProperty: undefined, + issueTime: undefined, + select: undefined, + foi: undefined, + format: 'application/json', + ...properties // merge defined properties + }); + //TODO: assertions + } +} +export default ControlStreamFilter; diff --git a/source/core/consysapi/controlstream/ControlStreams.js b/source/core/consysapi/controlstream/ControlStreams.js new file mode 100644 index 0000000000..8ff8a7249d --- /dev/null +++ b/source/core/consysapi/controlstream/ControlStreams.js @@ -0,0 +1,68 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConSysApiFetchControlStreamParser from "../../parsers/consysapi/collection/ConSysApiFetchControlStream.parser"; +import Collection from "../Collection"; +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import API from "../routes.conf"; +import ControlStreamFilter from "./ControlStreamFilter"; + +class ControlStreams extends ConnectedSystemsApi { + /** + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(networkProperties) { + super(networkProperties); // network properties + this.conSysApiControlStreamParser = new ConSysApiFetchControlStreamParser(networkProperties); + } + + /** + * List or search all controlstreams available through this API. + * @param {ControlStreamFilter} [controlStreamFilter=new ControlStreamFilter()] - default ControlStream filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<ControlStream>>} - A Collection of ControlStream + */ + async searchControlStreams(controlStreamFilter = new ControlStreamFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.controlstreams.search, + controlStreamFilter, + pageSize, + this.conSysApiControlStreamParser + ); + } + + /** + * Get a specific controlstream resource by ID + * @param {string} controlstreamId - ID of requested controlstream + * @param {ControlStreamFilter} [controlStreamFilter=new ControlStreamFilter()] - default controlstream filter + * @return {Promise<ControlStream>} - The corresponding ControlStream + */ + async getControlStreamById(controlstreamId, controlStreamFilter = new ControlStreamFilter()) { + const apiUrl = API.controlstreams.by_id.replace('{csid}',controlstreamId); + const queryString = controlStreamFilter.toQueryString(['select', 'format']); + const jsonData = await this.fetchAsJson(apiUrl, queryString); + return this.conSysApiControlStreamParser.parseData(jsonData); + } + +} + +export default ControlStreams; diff --git a/source/core/consysapi/datastream/DataStream.js b/source/core/consysapi/datastream/DataStream.js new file mode 100644 index 0000000000..36ff3af4d4 --- /dev/null +++ b/source/core/consysapi/datastream/DataStream.js @@ -0,0 +1,93 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import ObservationFilter from "../observation/ObservationFilter"; +import API from "../routes.conf"; +import DataStreamFilter from "./DataStreamFilter"; +import ObservationsCollection from "../ObservationsCollection"; +import ConSysApiResultParser from "../../parsers/consysapi/observations/ConSysApiResult.datastream.parser"; +import ConSysApiResultCollectionDatastreamParser + from "../../parsers/consysapi/observations/ConSysApiResult.collection.datastream.parser"; + +class DataStream extends ConnectedSystemsApi { + /** + * @param {Object} properties - the properties of the object + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(properties, networkProperties) { + super(networkProperties); // network properties + this.properties = properties; + this.conSysApiResultParser = new ConSysApiResultParser(this); + this.conSysApiResultCollectionDatastreamParser = new ConSysApiResultCollectionDatastreamParser(this); + } + + /** + * Retrieve historical observations from a datastream + * route: /datastreams/{id}/observations + * @param {ObservationFilter} [observationFilter=new ObservationFilter()] - default ObservationFilter + * @param {Function} callback - A callback to get observations + */ + streamObservations(observationFilter = new ObservationFilter(), callback = function(){}) { + this.stream().onMessage = async (message) => { + const dataBlock = await this.conSysApiResultParser.parseDataBlock(message,observationFilter.props.format); + callback(dataBlock); + } + + return this.stream().doRequest( + API.datastreams.observations.replace('{id}',this.properties.id), + observationFilter.toQueryString([], ['phenomenonTime']), + 'arraybuffer' + ); + } + + /** + * Retrieve historical observations from a datastream + * route: /datastreams/{id}/observations + * @param {ObservationFilter} [observationFilter=new ObservationFilter()] - default ObservationFilter + * @param {Number} [pageSize=10] - default page size + * @param {DataSourceParser} [parser=new ConSysApiResultParser()] - default observations parser + * @return {Collection<JSON>} - result observations as JSON + */ + async searchObservations(observationFilter = new ObservationFilter(), pageSize= 10, parser = this.conSysApiResultParser) { + return new ObservationsCollection( + this.baseUrl() + API.datastreams.observations.replace('{id}',this.properties.id), + observationFilter, + pageSize, + this.conSysApiResultCollectionDatastreamParser + ); + } + + /** + * Get the schema of a datastream + * route: /datastreams/{id}/schema + * @param {DataStreamFilter} [dataStreamFilter=new DataStreamFilter()] - default datastream filter + * @return {Promise<JSON>} - the JSON schema + */ + async getSchema(dataStreamFilter = new DataStreamFilter()) { + const apiUrl = API.datastreams.schema.replace('{id}',this.properties.id); + const queryString = dataStreamFilter.toQueryString(['select', 'obsFormat']); + return this.fetchAsJson(apiUrl, queryString); + } +} + +export default DataStream; diff --git a/source/core/consysapi/datastream/DataStreamFilter.js b/source/core/consysapi/datastream/DataStreamFilter.js new file mode 100644 index 0000000000..29bc7ec4c8 --- /dev/null +++ b/source/core/consysapi/datastream/DataStreamFilter.js @@ -0,0 +1,55 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApiFilter from "../Filter"; + +class DataStreamFilter extends ConnectedSystemsApiFilter { + /** + * + * @param {Object} properties - object properties + * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search + * @param {number[]} [properties.bbox=undefined] - BBOX to filter resources on their location + * @param {string} [properties.location=undefined] - WKT geometry and operator to filter resources on their location or geometry + * @param {string[]} [properties.observedProperty=undefined] - Comma separated list of observed property URIs to get observations for + * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for + * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude) + * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response. + * @param {string} [properties.validTime=undefined] - validTime - ISO 8601 time range to filter resources on their validity time. + * When this parameter is omitted, the implicit value is "now", except for "history" collections where the absence of this parameter means no filtering is applied. + * @param {string} [properties.resultTime=undefined] - validTime - ISO 8601 time range to filter observations on their result time. + * When this parameter is omitted, no filtering on "resultTime" is applied. + * @param {string} [properties.phenomenonTime=undefined] - validTime - ISO 8601 time range to filter observations on the phenomenon time. + * When this parameter is omitted, no filtering on "phenomenonTime" is applied. + */ + constructor(properties) { + super({ + q: undefined, + bbox: undefined, + location: undefined, + observedProperty: undefined, + foi: undefined, + select: undefined, + format: 'application/json', + obsFormat: 'application/om+json', + validTime: undefined, + phenomenonTime: undefined, + resultTime: undefined, + ...properties // merge defined properties + }); + //TODO: assertions + } +} +export default DataStreamFilter; diff --git a/source/core/consysapi/datastream/DataStreams.js b/source/core/consysapi/datastream/DataStreams.js new file mode 100644 index 0000000000..14108f25a6 --- /dev/null +++ b/source/core/consysapi/datastream/DataStreams.js @@ -0,0 +1,65 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import Collection from "../Collection"; +import DataStreamFilter from "./DataStreamFilter"; +import API from "../routes.conf"; +import ConSysApiDataStreamParser from "../../parsers/consysapi/collection/ConSysApiDataStream.parser"; + +class DataStreams extends ConnectedSystemsApi { + /** + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(networkProperties) { + super(networkProperties); + this.conSysApiDataStreamParser = new ConSysApiDataStreamParser(networkProperties); + } + + /** + * List or search all datastreams available through this API. + * @param {DataStreamFilter} [dataStreamFilter=new DataStreamFilter()] - default DataStream filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<DataStream>>} - A Collection of DataStream + */ + async searchDataStreams(dataStreamFilter = new DataStreamFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.datastreams.search, + dataStreamFilter, + pageSize, + this.conSysApiDataStreamParser + ); + } + + /** + * Get a specific datastream resource by ID + * @param {DataStreamFilter} [dataStreamFilter=new DataStreamFilter()] - default datastream filter + * @return {Promise<DataStream>} - The corresponding DataStream + */ + async getDataStreamById(datastreamId,dataStreamFilter = new DataStreamFilter()) { + const apiUrl = API.datastreams.by_id.replace('{id}',datastreamId); + const queryString = dataStreamFilter.toQueryString(['select','format']); + const jsonData = await this.fetchAsJson(apiUrl, queryString); + return this.conSysApiDataStreamParser.parseData(jsonData); + } +} +export default DataStreams; diff --git a/source/core/consysapi/event/Event.js b/source/core/consysapi/event/Event.js new file mode 100644 index 0000000000..4534184e09 --- /dev/null +++ b/source/core/consysapi/event/Event.js @@ -0,0 +1,36 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; + +class Event extends ConnectedSystemsApi { + /** + * @param {Object} properties - the properties of the object + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(properties, networkProperties) { + super(networkProperties); // network properties + this.properties = properties; + } +} + +export default Event; diff --git a/source/core/consysapi/event/EventFilter.js b/source/core/consysapi/event/EventFilter.js new file mode 100644 index 0000000000..dfcc123fee --- /dev/null +++ b/source/core/consysapi/event/EventFilter.js @@ -0,0 +1,42 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApiFilter from "../Filter"; + +class EventFilter extends ConnectedSystemsApiFilter { + /** + * + * @param {Object} properties - object properties + * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search + * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude) + * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response. + * @param {string} [properties.eventTime=undefined] - ISO 8601 time range to filter events on their timestamp. When this parameter + * is omitted, no filtering on "eventTime" is applied. + * @param {string} [properties.eventType=undefined] - Comma separated list of event type URIs to filter system events. + */ + constructor(properties) { + super({ + q: undefined, + eventTime: undefined, + eventType: undefined, + select: undefined, + format: 'application/json', + ...properties // merge defined properties + }); + //TODO: assertions + } +} +export default EventFilter; diff --git a/source/core/consysapi/event/Events.js b/source/core/consysapi/event/Events.js new file mode 100644 index 0000000000..7c6da6dea3 --- /dev/null +++ b/source/core/consysapi/event/Events.js @@ -0,0 +1,34 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; + +class Events extends ConnectedSystemsApi { + /** + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(networkProperties) { + super(networkProperties); + } +} + +export default Events; diff --git a/source/core/consysapi/history/SystemHistoryFilter.js b/source/core/consysapi/history/SystemHistoryFilter.js new file mode 100644 index 0000000000..847891217f --- /dev/null +++ b/source/core/consysapi/history/SystemHistoryFilter.js @@ -0,0 +1,38 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApiFilter from "../Filter"; + +class SystemHistoryFilter extends ConnectedSystemsApiFilter { + /** + * + * @param {Object} properties - object properties + * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude) + * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response. + * @param {string} [properties.validTime=undefined] - ISO 8601 time range to filter resources on their validity time. + * When this parameter is omitted, the implicit value is "now", except for "history" collections where the absence of this parameter means no filtering is applied. + */ + constructor(properties) { + super({ + select: undefined, + validTime: undefined, + format: 'application/json', + ...properties // merge defined properties + }); + //TODO: assertions + } +} +export default SystemHistoryFilter; diff --git a/source/core/consysapi/observation/Observation.js b/source/core/consysapi/observation/Observation.js new file mode 100644 index 0000000000..460a660b06 --- /dev/null +++ b/source/core/consysapi/observation/Observation.js @@ -0,0 +1,37 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; + +class Observation extends ConnectedSystemsApi { + /** + * @param {Object} properties - the properties of the object + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(properties, networkProperties) { + super(networkProperties); // network properties + this.properties = properties; + } + +} + +export default Observation; diff --git a/source/core/consysapi/observation/ObservationFilter.js b/source/core/consysapi/observation/ObservationFilter.js new file mode 100644 index 0000000000..106b7522e2 --- /dev/null +++ b/source/core/consysapi/observation/ObservationFilter.js @@ -0,0 +1,45 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ +import ConnectedSystemsApiFilter from "../Filter"; + +class ObservationFilter extends ConnectedSystemsApiFilter { + /** + * + * @param {Object} properties - object properties + * @param {any} [properties.phenomenonTime='now'] - time range <00:00:00T00:00:00Z/00:00:00T00:00:00Z> | 'now' | 'latest' + * @param {any} [properties.resultTime='now'] - time range <00:00:00T00:00:00Z/00:00:00T00:00:00Z> | 'latest' + * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for + * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude) + * @param {number[]} [properties.bbox=undefined] - BBOX to filter resources on their location + * @param {string} [properties.location=undefined] - WKT geometry and operator to filter resources on their location or geometry + * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response. + * @param {string} [properties.replaySpeed=undefined] - Mime type designating the format to use to encode the response. + */ + constructor(properties) { + super({ + phenomenonTime: undefined, + resultTime: undefined, + foi: undefined, + select: undefined, + bbox: undefined, + location: undefined, + format: 'application/om+json', + replaySpeed: undefined, + ...properties // merge defined properties + }); + } +} +export default ObservationFilter; diff --git a/source/core/consysapi/observation/Observations.js b/source/core/consysapi/observation/Observations.js new file mode 100644 index 0000000000..04ffe7a002 --- /dev/null +++ b/source/core/consysapi/observation/Observations.js @@ -0,0 +1,59 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import Collection from "../Collection"; +import ConSysApiFetchObservationParser from "../../parsers/consysapi/collection/ConSysApiFetchObservation.parser"; +import ObservationFilter from "./ObservationFilter"; +import API from "../routes.conf"; + +class Observations extends ConnectedSystemsApi { + /** + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(networkProperties) { + super(networkProperties); + this.conSysApiFetchObservationParser = new ConSysApiFetchObservationParser(networkProperties); + } + + /** + * List or search all observations available through this API. + * @param {ObservationFilter} [observationFilter=new ObservationFilter()] - default observation filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<Observation>>} - A Collection of Observation + */ + async searchObservations(observationFilter = new ObservationFilter(), pageSize= 10) { + return new Collection(this.baseUrl() + API.observations.search, observationFilter, pageSize,this.conSysApiFetchObservationParser); + } + + /** + * Get a specific observation resource by ID + * @param {string} observationId ID of requested observation + * @return {Promise<Observation>} - corresponding observation + */ + async getObservationById(observationId) { + const apiUrl = API.observations.by_id.replace('{id}', observationId); + const jsonData = await this.fetchAsJson(apiUrl, undefined); + return this.conSysApiFetchObservationParser.parseData(jsonData); + } +} +export default Observations; diff --git a/source/core/consysapi/routes.conf.js b/source/core/consysapi/routes.conf.js new file mode 100644 index 0000000000..46268219b0 --- /dev/null +++ b/source/core/consysapi/routes.conf.js @@ -0,0 +1,61 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +const API = { + datastreams: { + search: '/datastreams', + by_id: '/datastreams/{id}', + observations: '/datastreams/{id}/observations', + schema: '/datastreams/{id}/schema' + }, + systems: { + search: '/systems', + by_id: '/systems/{sysid}', + details: '/systems/{sysid}/details', + samplingFeatures: '/systems/{sysid}/samplingFeatures', + members: '/systems/{sysid}/members', + subsystems: '/systems/{sysid}/subsystems', + datastreams: '/systems/{sysid}/datastreams', + history_ver: '/systems/{sysid}/history/{ver}', + controlstream_by_id: '/systems/{sysid}/controlstreams/{csid}', + controlstreams: '/systems/{sysid}/controlstreams', + events: '/systems/{sysid}/events', + history: '/systems/{sysid}/history', + }, + controlstreams: { + search: '/controlstreams', + by_id: '/controlstreams/{csid}', + commands: '/systems/{sysid}/controlstreams/{csid}/commands', + command_by_id: '/systems/{sysid}/controlstreams/{csid}/commands/{cmdid}', + status: '/systems/{sysid}/controlstreams/{csid}/status', + schema: '/systems/{sysid}/controlstreams/{csid}/schema' + }, + commands: { + search: '/commands', + by_id: '/commands/{cmdid}', + status: '/systems/{sysid}/controlstreams/{csid}/commands/{cmdid}/status' + }, + observations: { + search: '/observations', + by_id: '/observations/{id}', + }, + samplingFeatures: { + search: '/samplingFeatures', + by_id: '/samplingFeatures/{id}', + }, +}; + +export default API; diff --git a/source/core/consysapi/samplingfeature/SamplingFeature.js b/source/core/consysapi/samplingfeature/SamplingFeature.js new file mode 100644 index 0000000000..4add902243 --- /dev/null +++ b/source/core/consysapi/samplingfeature/SamplingFeature.js @@ -0,0 +1,36 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; + +class SamplingFeature extends ConnectedSystemsApi { + /** + * @param {Object} properties - the properties of the object + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(properties, networkProperties) { + super(networkProperties); // network properties + this.properties = properties; + } +} + +export default SamplingFeature; diff --git a/source/core/consysapi/samplingfeature/SamplingFeatureFilter.js b/source/core/consysapi/samplingfeature/SamplingFeatureFilter.js new file mode 100644 index 0000000000..ab2f2148ac --- /dev/null +++ b/source/core/consysapi/samplingfeature/SamplingFeatureFilter.js @@ -0,0 +1,48 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApiFilter from "../Filter"; + +class SamplingFeatureFilter extends ConnectedSystemsApiFilter { + /** + * + * @param {Object} properties - object properties + * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search + * @param {number[]} [properties.bbox=undefined] - BBOX to filter resources on their location + * @param {string} [properties.location=undefined] - WKT geometry and operator to filter resources on their location or geometry + * @param {string} [properties.validTime=undefined] - validTime - ISO 8601 time range to filter resources on their validity time. + * When this parameter is omitted, the implicit value is "now", except for "history" collections where the absence of this parameter means no filtering is applied. + * @param {string[]} [properties.parent=undefined] - Comma separated list of parent resource IDs to restrict the search to or "*" to include nested resources at any level + * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude) + * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response. + * @param {String[]} [properties.foi=undefined] Comma separated list of feature of interest IDs to get observations for. + */ + constructor(properties) { + super({ + q: undefined, + bbox: undefined, + location: undefined, + validTime: undefined, + parent: undefined, + select: undefined, + foi: undefined, + format: 'application/json', + ...properties // merge defined properties + }); + //TODO: assertions + } +} +export default SamplingFeatureFilter; diff --git a/source/core/consysapi/samplingfeature/SamplingFeatures.js b/source/core/consysapi/samplingfeature/SamplingFeatures.js new file mode 100644 index 0000000000..3df34eae2e --- /dev/null +++ b/source/core/consysapi/samplingfeature/SamplingFeatures.js @@ -0,0 +1,65 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import SamplingFeatureFilter from "./SamplingFeatureFilter"; +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import Collection from "../Collection"; +import API from "../routes.conf"; +import ConSysApiFetchSamplingFeatureParser from "../../parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser"; + +class SamplingFeatures extends ConnectedSystemsApi { + /** + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(networkProperties) { + super(networkProperties); + this.conSysApiFetchSamplingFeatureParser = new ConSysApiFetchSamplingFeatureParser(networkProperties); + } + + /** + * List or search all sampled and sampling features available through this API. By default, only top level features + * and collections are listed (i.e. nested members of feature collections are ommitted) unless the "parent" query parameter is set. + * route: /samplingFeatures + * @param {SamplingFeatureFilter} [samplingFeatureFilter=new SamplingFeatureFilter()] - default SamplingFeature filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<SamplingFeatures>>} - A Collection of SamplingFeatures + */ + async searchSamplingFeatures(samplingFeatureFilter = new SamplingFeatureFilter(), pageSize= 10) { + return new Collection(this.baseUrl() + API.samplingFeatures.search, samplingFeatureFilter, pageSize,this.conSysApiFetchSamplingFeatureParser); + } + + /** + * Get a specific feature resource by ID. Note that this will return the description of the feature valid at the current time. + * To get the description valid for a past (or future) time, use the "history" sub-collection. + * route: /samplingFeatures/{id} + * @param {String} fId - The ID of the SamplingFeature resource + * @param {SamplingFeatureFilter} [samplingFeatureFilter=new SamplingFeatureFilter()] - default SamplingFeature filter + * @return {Promise<SamplingFeature>} - The corresponding SamplingFeatures as JSON + */ + async getSamplingFeatureById(fId,samplingFeatureFilter = new SamplingFeatureFilter()) { + const apiUrl = API.samplingFeatures.by_id.replace('{id}',fId); + const queryString = samplingFeatureFilter.toQueryString(['select', 'format']); + const jsonData = await this.fetchAsJson(apiUrl, queryString); + return this.conSysApiFetchSamplingFeatureParser.parseData(jsonData); + } +} +export default SamplingFeatures; diff --git a/source/core/consysapi/system/System.js b/source/core/consysapi/system/System.js new file mode 100644 index 0000000000..e50180ad5b --- /dev/null +++ b/source/core/consysapi/system/System.js @@ -0,0 +1,192 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import SystemFilter from "./SystemFilter"; +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import Collection from "../Collection"; +import DataStreamFilter from "../datastream/DataStreamFilter"; +import SamplingFeatureFilter from "../samplingfeature/SamplingFeatureFilter"; +import API from "../routes.conf"; +import ControlStreamFilter from "../controlstream/ControlStreamFilter"; +import EventFilter from "../event/EventFilter"; +import SystemHistoryFilter from "../history/SystemHistoryFilter"; +import ConSysApiFetchSystemParser from "../../parsers/consysapi/collection/ConSysApiFetchSystem.parser"; +import ConSysApiDataStreamParser from "../../parsers/consysapi/collection/ConSysApiDataStream.parser"; +import ConSysApiFetchSamplingFeatureParser from "../../parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser"; +import ConSysApiFetchEventParser from "../../parsers/consysapi/collection/ConSysApiFetchEvent.parser"; +import ConSysApiFetchControlStreamParser from "../../parsers/consysapi/collection/ConSysApiFetchControlStream.parser"; + +class System extends ConnectedSystemsApi { + /** + * @param {Object} properties - the properties of the object + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(properties, networkProperties) { + super(networkProperties); // network properties + this.properties = properties; + this.conSysApiFetchSystemParser = new ConSysApiFetchSystemParser(networkProperties); + this.conSysApiDataStreamParser = new ConSysApiDataStreamParser(networkProperties); + this.conSysApiFetchSamplingFeatureParser = new ConSysApiFetchSamplingFeatureParser(networkProperties); + this.conSysApiFetchEventParser = new ConSysApiFetchEventParser(networkProperties); + this.conSysApiFetchControlStreamParser = new ConSysApiFetchControlStreamParser(networkProperties); + } + + /** + * Get the latest specsheet of a system + * route: /systems/{sysid}/details + * @param {SystemFilter} [systemFilter=new SystemFilter()] - the system filter + * @return {Promise<JSON>} - SensorlML Description + */ + async getDetails(systemFilter = new SystemFilter()) { + const apiUrl = API.systems.details.replace('{sysid}',this.properties.id); + const queryString = systemFilter.toQueryString(['select', 'format']); + return this.fetchAsJson(apiUrl, queryString); + } + + /** + * Search for subsystems + * route: /systems/{sysid}/subsystems + * @param {SystemFilter} [systemFilter= new SystemFilter()] - the system filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<System>>} - A collection of System + */ + async searchSubSystems(systemFilter = new SystemFilter(), pageSize = 10) { + return new Collection( + this.baseUrl() + API.systems.subsystems.replace('{sysid}',this.properties.id), + systemFilter, + pageSize, + this.conSysApiFetchSystemParser + ); + } + + /** + * List or search output datastreams of the selected system. Individual datastreams can be retrieved by ID directly on the root "datastreams" collection. + * route: /systems/{sysid}/datastreams + * @param {DataStreamFilter} [dataStreamFilter=new DataStreamFilter()] - default DataStream filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<DataStream>>} - A collection of DataStream + */ + async searchDataStreams(dataStreamFilter = new DataStreamFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.systems.datastreams.replace('{sysid}',this.properties.id), + dataStreamFilter, + pageSize, + this.conSysApiDataStreamParser + ); + } + + /** + * List or search sampling features of a system. Individual features can be retrieved by ID directly on the root "samplingFeatures" collection + * route: /systems/{sysid}/samplingFeatures + * @param {SamplingFeatureFilter} [samplingFeatureFilter=new SamplingFeatureFilter()] - FOI filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<SamplingFeature>>} - A collection of SamplingFeature + */ + async searchSamplingFeatures(samplingFeatureFilter = new SamplingFeatureFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.systems.samplingFeatures.replace('{sysid}',this.properties.id), + samplingFeatureFilter, + pageSize, + this.conSysApiFetchSamplingFeatureParser + ); + } + + /** + * Get a list of control interfaces of a system + * route: /systems/{sysid}/controlstreams + * @param {ControlStreamFilter} [controlStreamFilter=new ControlStreamFilter()] - the controlstream filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<ControlStream>>} - A collection of ControlStream + */ + async searchControlStreams(controlStreamFilter = new ControlStreamFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.systems.controlstreams.replace('{sysid}',this.properties.id), + controlStreamFilter, + pageSize, + this.conSysApiFetchControlStreamParser + ); + } + + /** + * Get a specific control interface description by ID + * route: /systems/{sysid}/controlstreams/{dsid} + * @param {String} controlstreamId - The ID of the control stream + * @param {ControlStreamFilter} [controlStreamFilter= new ControlStreamFilter()] - the controlstream filter + * @return {ControlStream} - The corresponding ControlStream + */ + async getControlStreamById(controlstreamId,controlStreamFilter = new ControlStreamFilter()) { + const apiUrl = API.systems.controlstream_by_id.replace('{sysid}',this.properties.id).replace('{csid}', controlstreamId); + const queryString = controlStreamFilter.toQueryString(['select', 'format']); + const jsonData = await this.fetchAsJson(apiUrl, queryString); + return this.conSysApiFetchControlStreamParser.parseData(jsonData); + } + + /** + * List or search events related to a system (e.g. maintenance events, contact change, etc.) + * route: /systems/{sysid}/events + * @param {EventFilter} [eventFilter= new EventFilter()] - the event filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<Event>>} - A collection of Event + */ + async searchEvents(eventFilter = new EventFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.systems.events.replace('{sysid}',this.properties.id), + eventFilter, + pageSize, + this.conSysApiFetchEventParser + ); + } + + /** + * List or search for historical descriptions of a specific system (ordered by time of validity) + * route: /systems/{sysid}/history + * @param {SystemHistoryFilter} [systemHistoryFilter= new SystemHistoryFilter()] - the history filer + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<System>>} - A collection of System + */ + async searchHistory(systemHistoryFilter = new SystemHistoryFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.systems.history.replace('{sysid}',this.properties.id), + systemHistoryFilter, + pageSize, + this.conSysApiFetchSystemParser + ); + } + + /** + * List or search members of a system group. Individual members can be retrieved by ID directly on the root "systems" collection + * route: /systems/{sysid}/members + * @param {SystemFilter} [systemFilter=new SystemFilter()] - the system filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<System>>} - A collection of System + */ + async searchMembers(systemFilter = new SystemFilter(), pageSize= 10) { + return new Collection( + this.baseUrl() + API.systems.members.replace('{sysid}',this.properties.id), + systemFilter, + pageSize, + this.conSysApiFetchSystemParser + ); + } +} + +export default System; diff --git a/source/core/consysapi/system/SystemFilter.js b/source/core/consysapi/system/SystemFilter.js new file mode 100644 index 0000000000..7fbb25d724 --- /dev/null +++ b/source/core/consysapi/system/SystemFilter.js @@ -0,0 +1,48 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApiFilter from "../Filter"; + +class SystemFilter extends ConnectedSystemsApiFilter { + /** + * + * @param {Object} properties - object properties + * @param {string[]} [properties.q=undefined] - Comma separated keywords used for full-text search + * @param {number[]} [properties.bbox=undefined] - BBOX to filter resources on their location + * @param {string} [properties.location=undefined] - WKT geometry and operator to filter resources on their location or geometry + * @param {string[]} [properties.parent=undefined] - Comma separated list of parent resource IDs to restrict the search to or "*" to include nested resources at any level + * @param {string[]} [properties.foi=undefined] - Comma separated list of feature of interest IDs to get observations for + * @param {string[]} [properties.select=undefined] - Comma separated list of properties to include or exclude from results (use "!" prefix to exclude) + * @param {string} [properties.format='application/json'] - Mime type designating the format to use to encode the response. + * @param {string} [properties.validTime=undefined] - validTime - ISO 8601 time range to filter resources on their validity time. + When this parameter is omitted, the implicit value is "now", except for "history" collections where the absence of this parameter means no filtering is applied. + */ + constructor(properties) { + super({ + q: undefined, + bbox: undefined, + location: undefined, + parent: undefined, + foi: undefined, + select: undefined, + format: 'application/json', + validTime: undefined, + ...properties // merge defined properties + }); + //TODO: assertions + } +} +export default SystemFilter; diff --git a/source/core/consysapi/system/Systems.js b/source/core/consysapi/system/Systems.js new file mode 100644 index 0000000000..07a5b08935 --- /dev/null +++ b/source/core/consysapi/system/Systems.js @@ -0,0 +1,65 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConnectedSystemsApi from "../ConnectedSystemsApi"; +import Collection from "../Collection"; +import SystemFilter from "./SystemFilter"; +import API from "../routes.conf"; +import ConSysApiFetchSystemParser from "../../parsers/consysapi/collection/ConSysApiFetchSystem.parser"; + +class Systems extends ConnectedSystemsApi { + /** + * @param {Object} [networkProperties={}] + * @param {String} networkProperties.endpointUrl - defines the Http(s) endpoint URL + * @param {Boolean} networkProperties.tls - defines is use Http or Https secure protocol for fetching data + * @param {String} [networkProperties.streamProtocol='ws'] - the Stream protocol to use: 'ws' pr 'mqtt' + * @param {Object} [networkProperties.mqttOpts={}] - the Mqtt options if stream protocol is 'mqtt' + * @param {String} networkProperties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} networkProperties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + */ + constructor(networkProperties) { + super(networkProperties); + this.conSysApiFetchSystemParser = new ConSysApiFetchSystemParser(networkProperties); + } + + /** + * List or search all observing systems available through this API. By default, only top level systems are listed + * (i.e. subsystems are ommitted) unless the "parent" query parameter is set + * route: /systems + * @param {SystemFilter} [systemFilter= new SystemFilter()] - the system filter + * @param {Number} [pageSize=10] - default page size + * @return {Promise<Collection<System>>} - A collection of System + */ + async searchSystems(systemFilter = new SystemFilter(), pageSize = 10) { + return new Collection(this.baseUrl() + API.systems.search, systemFilter, pageSize, this.conSysApiFetchSystemParser); + } + + /** + * Get a specific system resource by ID. Note that this will return the description of the system valid at the + * current time. To get the description valid for a past (or future) time, use the "history" sub-collection. + * route: /systems/{sysid} + * @param {String} systemId - the ID of the System resource + * @param {SystemFilter} [systemFilter=new SystemFilter()] - the system filter + * @return {System} - The corresponding System + */ + async getSystemById(systemId,systemFilter = new SystemFilter()) { + const apiUrl = API.systems.by_id.replace('{sysid}',systemId); + const queryString = systemFilter.toQueryString(['select','format']); + const jsonData = await this.fetchAsJson(apiUrl, queryString); + return this.conSysApiFetchSystemParser.parseData(jsonData); + } +} +export default Systems; diff --git a/source/core/datasource/consysapi/ConSysApi.datasource.js b/source/core/datasource/consysapi/ConSysApi.datasource.js new file mode 100755 index 0000000000..afceb03cd0 --- /dev/null +++ b/source/core/datasource/consysapi/ConSysApi.datasource.js @@ -0,0 +1,91 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + + +import TimeSeriesDatasource from "../TimeSeries.datasource"; +import {Mode} from "../Mode"; +import ConSysApiDatasourceUpdater from "./ConSysApi.datasource.updater"; + +class ConSysApi extends TimeSeriesDatasource { + /** + * @param {String} name - the datasource name + * @param {Object} properties - the datasource properties + * @param {String} properties.protocol - defines the protocol of the datasource. @see {@link DataConnector}, 'http', 'ws', 'mqtt', 'file', 'topic' + * @param {String} properties.endpointUrl the endpoint url, this property is ignored in case of using 'mqtt' protocol, the properties.mqttOpts.endpointUrl will be used instead + * @param {String} properties.resource the resource, /procedures, /fois, /observations, /tasks, /datastreams/4778/obs + * @param {Boolean} properties.tls - defines if use secure TLS connection + * @param {Boolean} properties.connectorOpts - connector specific Opts + * @param {Object} [properties.mqttOpts={}] - the Mqtt options if protocol is 'mqtt' + * @param {String} properties.mqttOpts.prefix - the Mqtt prefix value + * @param {String} properties.mqttOpts.endpointUrl - the Mqtt specific endpointUrl + * @param {Number} [properties.responseFormat=application/om+json] the response format (e.g application/om+json) + * @param {String[]} [properties.parentId=undefined] the parent id + * @param {String[]} [properties.keywords=undefined] the keyword ids + * @param {String[]} [properties.includedProps=undefined] the included properties + * @param {String[]} [properties.excludedProps=undefined] the excluded properties + * @param {string} [properties.roi=undefined] - WKT geometry and operator to filter resources on their location or geometry + * @param {String[]} [properties.featureOfInterest=undefined] Comma separated list of feature of interest IDs to get observations for. + * @param {String[]} [properties.observedProperty=undefined] Comma separated list of observed property URIs to get observations for. + * @param {String[]} [properties.prefetchBatchSize=250] Number of elements to prefetch at a time + * @param {String[]} [properties.prefetchBatchDuration=5000] Duration before prefetching the next batch. N.b the next batch will be prefetched at 80% of this duration + */ + constructor(name, properties) { + super(name, { + reconnectTimeout: 1000 * 5, // default if not defined into properties + reconnectRetry: 10, + startTime: 'now', + endTime: '2055-01-01T00:00:00Z', + tls: false, + responseFormat: 'application/swe+json', + protocol: 'http', + type: 'ConSysApiStream', + mode: Mode.REAL_TIME, + prefetchBatchSize: 250, + prefetchBatchDuration: 5000, + connectorOpts: {}, + ...properties, + }); + } + + async createTimeUpdater() { + if(!this.timeUpdater) { + this.timeUpdater = new ConSysApiDatasourceUpdater(this.properties); + let first = true; + this.timeUpdater.onTimeChanged = (min, max) => { + if (first) { + this.setMinTime(min); + first = false; + } + this.setMaxTime(max); + if (this.getDataSynchronizer()) { + this.getDataSynchronizer().minMaxChanged(first); + } + } + this.timeUpdater.onError = (err) => reject(); + + return this.timeUpdater.start(); + } // TO CHECK: if timeUpdater has been created multiple times. Start() should not return anything + } + + destroyTimeUpdater() { + if(this.timeUpdater) { + this.timeUpdater.destroy(); + } + this.timeUpdater = undefined; + } +} + +export default ConSysApi; diff --git a/source/core/datasource/consysapi/ConSysApi.datasource.updater.js b/source/core/datasource/consysapi/ConSysApi.datasource.updater.js new file mode 100644 index 0000000000..83da7968da --- /dev/null +++ b/source/core/datasource/consysapi/ConSysApi.datasource.updater.js @@ -0,0 +1,55 @@ +class ConSysApiDatasourceUpdater { + constructor(properties) { + this.properties = properties; + this.datastreamInterval = undefined; + } + + async fetchTime(url) { + return fetch(url) + .then(response => { + if (!response.ok) { + // create error object and reject if not a 2xx response code + let err = new Error("HTTP status code: " + response.status) + err.response = response + err.status = response.status + this.onError(err); + throw err + } + return response + }) + .then(response => response.json()) + .then(response => { + // update datastream times + if(response && response.items.length > 0 && response.items[0].phenomenonTime + && response.items[0].phenomenonTime.length > 1) { + const minTime = response.items[0].phenomenonTime[0]; + const maxTime = response.items[0].phenomenonTime[1]; + this.onTimeChanged(minTime, maxTime); + } + }); + } + async start() { + const regex = new RegExp('\\/(.*\\/)(.*)\\/observations'); // /datastreams/abc13/observations + if(regex.test(this.properties.resource)) { + // is observation streaming + const match = regex.exec(this.properties.resource); + const datastreamId = match[2]; + const url = `http${this.properties.tls? 's' : ''}://${this.properties.endpointUrl}/datastreams?id=${datastreamId}&select=id,phenomenonTime&f=application%2Fjson`; + return this.fetchTime(url).then(() => { + this.datastreamInterval = setInterval(() => { + this.fetchTime(url); + }, 5000); + }) + } else { + throw Error(`Cannot parse dataStream id from resource ${this.properties.resource}`); + } + } + onTimeChanged(min, max){} + + onError(err){} + destroy() { + clearInterval(this.datastreamInterval); + } +} + +export default ConSysApiDatasourceUpdater; diff --git a/source/core/datasource/consysapi/context/ConSysApi.context.js b/source/core/datasource/consysapi/context/ConSysApi.context.js new file mode 100644 index 0000000000..d31d599c0a --- /dev/null +++ b/source/core/datasource/consysapi/context/ConSysApi.context.js @@ -0,0 +1,88 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import {isDefined} from "../../../utils/Utils"; +import ObservationFilter from "../../../consysapi/observation/ObservationFilter"; +import DataSourceContext from "../../common/context/DataSource.context"; +import ControlStreamFilter from "../../../consysapi/controlstream/ControlStreamFilter"; + +class ConSysApiContext extends DataSourceContext { + createControlStreamFilter(properties) { + const props = {}; + if(isDefined(properties.keywords)) { + props.q = properties.keywords; + } + if(isDefined(properties.actuableProperty)) { + props.actuableProperty = properties.actuableProperty; + } + if(isDefined(properties.statusCode)) { + props.statusCode = properties.statusCode; + } + if(isDefined(properties.responseFormat)) { + props.format = properties.responseFormat; + } + if(isDefined(properties.issueTime)) { + props.issueTime = properties.issueTime; + } + if(isDefined(properties.executionTime)) { + props.executionTime = properties.executionTime; + } + if(isDefined(properties.reportTime)) { + props.reportTime = properties.reportTime; + } + + return new ControlStreamFilter(props); + } + + createObservationFilter(properties) { + const props = {}; + if(isDefined(properties.roi)) { + props.location = props.roi; + } + if(isDefined(properties.responseFormat)) { + props.format = properties.responseFormat; + } + if(isDefined(properties.replaySpeed)) { + props.replaySpeed = properties.replaySpeed; + } + if(isDefined(properties.startTime)) { + props.phenomenonTime = properties.startTime + '/' + properties.endTime; + } + if(isDefined(properties.resultTime)) { + props.resultTime = properties.resultTime; + } + if(isDefined(properties.resultTime)) { + props.resultTime = properties.resultTime; + } + if(isDefined(properties.featureOfInterest)) { + props.featureOfInterest = properties.featureOfInterest; + } + if(isDefined(properties.excludedProps)) { + props.select = properties.excludedProps.map(e => '!' + e); + } + if(isDefined(properties.includedProps)) { + if(!isDefined(props.select)) { + props.select = []; + } + props.select.concat(properties.includedProps); + } + + return new ObservationFilter(props); + } +} + + +export default ConSysApiContext; diff --git a/source/core/datasource/consysapi/context/ConSysApi.realtime.context.js b/source/core/datasource/consysapi/context/ConSysApi.realtime.context.js new file mode 100644 index 0000000000..21593337f6 --- /dev/null +++ b/source/core/datasource/consysapi/context/ConSysApi.realtime.context.js @@ -0,0 +1,91 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConSysApiContext from "./ConSysApi.context"; +import DataStream from "../../../consysapi/datastream/DataStream"; +import {isDefined} from "../../../utils/Utils"; +import ControlStream from "../../../consysapi/controlstream/ControlStream"; + +class ConSysApiRealTimeContext extends ConSysApiContext { + init(properties) { + this.properties = properties; + + const networkProperties = { + ...properties, + streamProtocol: properties.protocol + }; + let filter; + let regex = new RegExp('\\/systems\\/(.*)\\/controlstreams\\/(.*)\\/status'); + + this.streamObject = undefined; + + // check control status + if(regex.test(properties.resource)) { + filter = this.createControlStreamFilter(properties); + // is observation streaming + const match = regex.exec(properties.resource); + + this.streamObject = new ControlStream({ + id: match[2], + 'system@id': match[1] + }, networkProperties); + this.streamFunction = function() { + this.streamObject.streamStatus(filter, (messages) => this.onStreamMessage(messages, filter.props.format)); + } + } else { + // check for datastream observations + regex = new RegExp('\\/(.*\\/)(.*)\\/observations'); // /datastreams/abc13/observations + if(regex.test(properties.resource)) { + filter = this.createObservationFilter(properties); + // is observation streaming + const match = regex.exec(properties.resource); + this.streamObject = new DataStream({ + id: match[2] + }, networkProperties); + this.streamFunction = function() { + this.streamObject.streamObservations(filter, (messages) => this.onStreamMessage(messages, filter.props.format)); + } + } + } + this.streamObject.stream().onChangeStatus = this.onChangeStatus.bind(this); + } + onStreamMessage(messages, format) { + // in case of om+json ,we have to add the timestamp which is not included for each record but at the root level + let results = messages; + let version = this.properties.version; + for(let message of messages) { + message.version = version; + } + this.handleData(results, format); + } + + connect() { + this.streamFunction(); + } + + async disconnect() { + if(isDefined(this.streamObject)) { + this.streamObject.stream().disconnect(); + } + } + + isConnected() { + return this.streamObject.stream().status; + } +} + + +export default ConSysApiRealTimeContext; diff --git a/source/core/datasource/consysapi/context/ConSysApi.replay.context.js b/source/core/datasource/consysapi/context/ConSysApi.replay.context.js new file mode 100644 index 0000000000..ad3c5e5122 --- /dev/null +++ b/source/core/datasource/consysapi/context/ConSysApi.replay.context.js @@ -0,0 +1,138 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import ConSysApiContext from "./ConSysApi.context"; +import DataStream from "../../../consysapi/datastream/DataStream"; +import {isDefined} from "../../../utils/Utils"; +import ControlStream from "../../../consysapi/controlstream/ControlStream"; + +class ConSysApiReplayContext extends ConSysApiContext { + init(properties) { + this.collection = undefined; + this.relativeStartTimestamp = undefined; + this.properties = properties; + this.replayFunction = undefined; + + const networkProperties = { + ...properties + }; + let filter; + let regex = new RegExp('\\/systems\\/(.*)\\/controlstreams\\/(.*)\\/status'); + + // check controlstream status + if(regex.test(properties.resource)) { + filter = this.createControlStreamFilter(properties); + // is observation streaming + const match = regex.exec(properties.resource); + + let control = new ControlStream({ + id: match[2], + 'system@id': match[1] + }, networkProperties); + this.replayFunction = function(props, startTimestamp, endTimestamp) { + const controlFilter = this.createControlStreamFilter({ + ...properties, + ...props, + startTime: new Date(startTimestamp).toISOString(), + endTime: new Date(endTimestamp).toISOString() + }); + return control.searchStatus(controlFilter, 1); + } + } else { + // check for datastream observations + regex = new RegExp('\\/(.*\\/)(.*)\\/observations'); // /datastreams/abc13/observations + if(regex.test(properties.resource)) { + // is observation streaming + const match = regex.exec(properties.resource); + let dataStream = new DataStream({ + id: match[2] + }, networkProperties); + this.dataStream = dataStream; + this.replayFunction = function(props, startTime, endTime) { + const obsFilter = this.createObservationFilter({ + ...properties, + ...props, + replaySpeed: undefined, + startTime: startTime, + endTime: endTime + }); + return dataStream.searchObservations(obsFilter, properties.prefetchBatchSize); + } + } + } + } + + async disconnect() { + this.collection = undefined; + this.relativeStartTimestamp = undefined; + this.replayFunction = undefined; + } + + async nextBatch(properties, masterTimestamp, status = {cancel:false}) { + let version = this.properties.version; + return new Promise(async (resolve, reject) => { + try { + let data; + let results = []; + + const moveTimeCursor = async () => { + let relativeStartTime; + if(isDefined(this.relativeStartTimestamp)) { + relativeStartTime = new Date(this.relativeStartTimestamp + 1).toISOString(); + } else { + //TOCHECK: ISO or timestamp + relativeStartTime = new Date(this.properties.startTime).toISOString(); + } + + console.warn(`fetching ${relativeStartTime} -> ` + + `${this.properties.endTime} for datasource ${this.properties.dataSourceId}`); + // if disconnected, replay function is reset + if(this.replayFunction) { + this.collection = await this.replayFunction(properties, relativeStartTime, this.properties.endTime); + } + } + + const fetchNext = async () => { + data = await this.collection.nextPage(); + if (status.cancel) { + reject('Status has been cancelled'); + } + if (data.length > 0) { + results = data; + for(let d of results) { + d.version = version; + } + if(status.cancel) { + reject('Status has been cancelled'); + } else { + // start startTime cursor + this.relativeStartTimestamp = results[results.length-1].timestamp; + resolve(data); + } + } + } + + await moveTimeCursor(); + await fetchNext(); + } catch (ex) { + reject(ex); + } + }); + } +} + + +export default ConSysApiReplayContext; diff --git a/source/core/datasource/consysapi/handler/ConSysApi.handler.js b/source/core/datasource/consysapi/handler/ConSysApi.handler.js new file mode 100644 index 0000000000..1b79d12ba4 --- /dev/null +++ b/source/core/datasource/consysapi/handler/ConSysApi.handler.js @@ -0,0 +1,32 @@ +/***************************** BEGIN LICENSE BLOCK *************************** + + The contents of this file are subject to the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one + at http://mozilla.org/MPL/2.0/. + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + Copyright (C) 2015-2022 Georobotix Inc. All Rights Reserved. + + Author: Mathieu Dhainaut <mathieu.dhainaut@gmail.com> + + ******************************* END LICENSE BLOCK ***************************/ + +import TimeSeriesHandler from "../../common/handler/TimeSeries.handler"; +import ConSysApiRealtimeContext from "../context/ConSysApi.realtime.context"; +import ConSysApiReplayContext from "../context/ConSysApi.replay.context"; +import {Mode} from "../../Mode"; + +class ConSysApiHandler extends TimeSeriesHandler { + createContext(properties) { + if(properties.mode === Mode.REPLAY || properties.mode === Mode.BATCH) { + return new ConSysApiReplayContext(); + } else { + return new ConSysApiRealtimeContext(); + } + } +} + +export default ConSysApiHandler; diff --git a/source/core/datasource/worker/DataSourceWorker.js b/source/core/datasource/worker/DataSourceWorker.js index b4a102305d..dfe95c3a48 100644 --- a/source/core/datasource/worker/DataSourceWorker.js +++ b/source/core/datasource/worker/DataSourceWorker.js @@ -1,6 +1,7 @@ import SosGetResultHandler from "../sos/handler/SosGetResult.handler"; import SosGetFoisHandler from "../sos/handler/SosGetFois.handler"; import SweApiHandler from "../sweapi/handler/SweApi.handler"; +import ConSysApiHandler from "../consysapi/handler/ConSysApi.handler"; class DataSourceWorker { constructor() { @@ -116,6 +117,8 @@ class DataSourceWorker { return new SosGetFoisHandler(); } else if (properties.type === 'SweApiStream') { return new SweApiHandler(); + } else if (properties.type === 'ConSysApiStream') { + return new ConSysApiHandler(); } else { throw Error('Unsupported SOS service Error'); } diff --git a/source/core/parsers/consysapi/collection/CollectionOmJsonParser.parser.js b/source/core/parsers/consysapi/collection/CollectionOmJsonParser.parser.js new file mode 100644 index 0000000000..57a65c7706 --- /dev/null +++ b/source/core/parsers/consysapi/collection/CollectionOmJsonParser.parser.js @@ -0,0 +1,24 @@ +import OmJsonParser from "../common/OmJsonParser.parser"; + +class OmJsonCollectionParser extends OmJsonParser { + constructor(rootElement) { + super(rootElement); + } + getTimeField() { + return 'phenomenonTime'; + } + + parseDataBlock(arrayBuffer) { + let dataBlock = this.textDecoder.decode(arrayBuffer); + const jsonData = JSON.parse(dataBlock); + const result = []; + + for(let d of jsonData.items) { + d['timestamp'] = new Date(d[this.getTimeField()]).getTime(); + result.push(d); + } + return result; + } +} + +export default OmJsonCollectionParser; diff --git a/source/core/parsers/consysapi/collection/ConSysApiCollectionObjectParser.js b/source/core/parsers/consysapi/collection/ConSysApiCollectionObjectParser.js new file mode 100644 index 0000000000..36cfba7edf --- /dev/null +++ b/source/core/parsers/consysapi/collection/ConSysApiCollectionObjectParser.js @@ -0,0 +1,9 @@ +class ConSysApiCollectionObjectParser { + constructor(networkProperties) { + this.networkProperties = networkProperties; + } + + parseData(data) {} +} + +export default ConSysApiCollectionObjectParser; diff --git a/source/core/parsers/consysapi/collection/ConSysApiControlStreamStatus.parser.js b/source/core/parsers/consysapi/collection/ConSysApiControlStreamStatus.parser.js new file mode 100644 index 0000000000..71c9701a4b --- /dev/null +++ b/source/core/parsers/consysapi/collection/ConSysApiControlStreamStatus.parser.js @@ -0,0 +1,20 @@ +import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser"; + +class ConSysApiControlStreamStatusParser extends ConSysApiCollectionObjectParser { + constructor(networkProperties) { + super(networkProperties); + this.textDecoder = new TextDecoder(); + } + + parseData(data, format) { + let res; + if(format === 'arraybuffer') { + res = this.textDecoder.decode(data); + } else { + res = JSON.parse(data); + } + return JSON.parse(res); + } +} + +export default ConSysApiControlStreamStatusParser; diff --git a/source/core/parsers/consysapi/collection/ConSysApiDataStream.parser.js b/source/core/parsers/consysapi/collection/ConSysApiDataStream.parser.js new file mode 100644 index 0000000000..8666a30c32 --- /dev/null +++ b/source/core/parsers/consysapi/collection/ConSysApiDataStream.parser.js @@ -0,0 +1,16 @@ +import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser"; +import DataStream from "../../../consysapi/datastream/DataStream"; + +class ConSysApiDataStreamParser extends ConSysApiCollectionObjectParser { + parseData(data) { + return new DataStream( + data, + { + streamProtocol: 'ws', // default streaming + ...this.networkProperties + } + ); + } +} + +export default ConSysApiDataStreamParser; diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchCommand.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchCommand.parser.js new file mode 100644 index 0000000000..e10575dd8f --- /dev/null +++ b/source/core/parsers/consysapi/collection/ConSysApiFetchCommand.parser.js @@ -0,0 +1,21 @@ +import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser"; +import Command from "../../../consysapi/command/Command"; + +class ConSysApiFetchCommandParser extends ConSysApiCollectionObjectParser { + constructor(networkProperties, systemId) { + super(networkProperties); + this.systemId = systemId; + } + + parseData(data) { + return new Command( + { + ...data, + systemId: this.systemId + }, + this.networkProperties + ); + } +} + +export default ConSysApiFetchCommandParser; diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchControlStream.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchControlStream.parser.js new file mode 100644 index 0000000000..f9efa12fe6 --- /dev/null +++ b/source/core/parsers/consysapi/collection/ConSysApiFetchControlStream.parser.js @@ -0,0 +1,16 @@ +import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser"; +import ControlStream from "../../../consysapi/controlstream/ControlStream"; + +class ConSysApiFetchControlStreamParser extends ConSysApiCollectionObjectParser { + parseData(data) { + return new ControlStream( + data, + { + streamProtocol: 'ws', // default streaming + ...this.networkProperties + } + ); + } +} + +export default ConSysApiFetchControlStreamParser; diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchEvent.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchEvent.parser.js new file mode 100644 index 0000000000..1d514b4150 --- /dev/null +++ b/source/core/parsers/consysapi/collection/ConSysApiFetchEvent.parser.js @@ -0,0 +1,12 @@ +import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser"; + +class ConSysApiFetchEventParser extends ConSysApiCollectionObjectParser { + parseData(data) { + return new Event( + data, + this.networkProperties + ); + } +} + +export default ConSysApiFetchEventParser; diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchObservation.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchObservation.parser.js new file mode 100644 index 0000000000..3be6531cec --- /dev/null +++ b/source/core/parsers/consysapi/collection/ConSysApiFetchObservation.parser.js @@ -0,0 +1,13 @@ +import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser"; +import Observation from "../../../consysapi/observation/Observation"; + +class ConSysApiFetchObservationParser extends ConSysApiCollectionObjectParser { + parseData(data) { + return new Observation( + data, + this.networkProperties + ); + } +} + +export default ConSysApiFetchObservationParser; diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser.js new file mode 100644 index 0000000000..17bcc5b586 --- /dev/null +++ b/source/core/parsers/consysapi/collection/ConSysApiFetchSamplingFeature.parser.js @@ -0,0 +1,18 @@ +import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser"; +import SamplingFeature from "../../../consysapi/samplingfeature/SamplingFeature"; + +class ConSysApiFetchSamplingFeatureParser extends ConSysApiCollectionObjectParser { + parseData(data) { + return new SamplingFeature( + { + ...data, + geometry: data.geometry || undefined, + bbox: data.bbox || undefined + }, + + this.networkProperties + ); + } +} + +export default ConSysApiFetchSamplingFeatureParser; diff --git a/source/core/parsers/consysapi/collection/ConSysApiFetchSystem.parser.js b/source/core/parsers/consysapi/collection/ConSysApiFetchSystem.parser.js new file mode 100644 index 0000000000..b627838ad9 --- /dev/null +++ b/source/core/parsers/consysapi/collection/ConSysApiFetchSystem.parser.js @@ -0,0 +1,13 @@ +import ConSysApiCollectionObjectParser from "./ConSysApiCollectionObjectParser"; +import System from "../../../consysapi/system/System"; + +class ConSysApiFetchSystemParser extends ConSysApiCollectionObjectParser { + parseData(data) { + return new System( + data, + this.networkProperties + ); + } +} + +export default ConSysApiFetchSystemParser; diff --git a/source/core/parsers/consysapi/collection/SweCollectionDataParser.js b/source/core/parsers/consysapi/collection/SweCollectionDataParser.js new file mode 100644 index 0000000000..cb1ebebb42 --- /dev/null +++ b/source/core/parsers/consysapi/collection/SweCollectionDataParser.js @@ -0,0 +1,37 @@ +class SweCollectionDataParser { + + constructor(format = 'application/json') { + this.format = format; + } + + parseData(data) { + if (this.format === 'application/om+json' || this.format === 'application/json') { + return this.parseOmJsonData(data); + } else if (this.format === 'application/swe+json') { + return this.parseSweJsonData(data); + } else if (this.format === 'application/swe+csv') { + return this.parseSweCsv(data); + } else if (this.format === 'application/swe+xml') { + return this.parseSweXml(data); + } else { + throw Error(`Unsupported collection format ${this.format}`); + } + } + + parseOmJsonData(data) { + return (data instanceof ArrayBuffer) ? JSON.parse(String.fromCharCode.apply(null, new Uint8Array(data))).items : data.items; + } + + parseSweJsonData(data) { + return (data instanceof ArrayBuffer) ? JSON.parse(String.fromCharCode.apply(null, new Uint8Array(data))) : data; + } + + parseSweCsv(data) { + let content = (data instanceof ArrayBuffer) ? String.fromCharCode.apply(null, new Uint8Array(data)) : data; + return content.split('\n'); + } + parseSweXml(data) { + return (data instanceof ArrayBuffer) ? String.fromCharCode.apply(null, new Uint8Array(data)) : data; + } +} +export default SweCollectionDataParser; diff --git a/source/core/parsers/consysapi/common/OmJsonParser.parser.js b/source/core/parsers/consysapi/common/OmJsonParser.parser.js new file mode 100644 index 0000000000..2f65224dbe --- /dev/null +++ b/source/core/parsers/consysapi/common/OmJsonParser.parser.js @@ -0,0 +1,12 @@ +import JsonDataParser from "../../JsonDataParser"; + +class OmJsonParser extends JsonDataParser { + constructor(rootElement) { + super(rootElement); + } + getTimeField() { + return 'phenomenonTime'; + } +} + +export default OmJsonParser; diff --git a/source/core/parsers/consysapi/common/SweBinaryParser.parser.js b/source/core/parsers/consysapi/common/SweBinaryParser.parser.js new file mode 100644 index 0000000000..d59f4b4d7c --- /dev/null +++ b/source/core/parsers/consysapi/common/SweBinaryParser.parser.js @@ -0,0 +1,9 @@ +import BinaryDataParser from "../../BinaryDataParser"; + +class SweBinaryParser extends BinaryDataParser { + constructor(rootElement, encoding) { + super(rootElement, encoding) + } +} + +export default SweBinaryParser; diff --git a/source/core/parsers/consysapi/common/SweCsvParser.parser.js b/source/core/parsers/consysapi/common/SweCsvParser.parser.js new file mode 100644 index 0000000000..c4364054c1 --- /dev/null +++ b/source/core/parsers/consysapi/common/SweCsvParser.parser.js @@ -0,0 +1,9 @@ +import TextDataParser from "../../TextDataParser"; + +class SweCsvParser extends TextDataParser { + constructor(rootElement, encoding) { + super(rootElement, encoding) + } +} + +export default SweCsvParser; diff --git a/source/core/parsers/consysapi/common/SweJsonParser.parser.js b/source/core/parsers/consysapi/common/SweJsonParser.parser.js new file mode 100644 index 0000000000..12f818a96b --- /dev/null +++ b/source/core/parsers/consysapi/common/SweJsonParser.parser.js @@ -0,0 +1,9 @@ +import JsonDataParser from "../../JsonDataParser"; + +class SweJsonParser extends JsonDataParser { + constructor(rootElement) { + super(rootElement) + } +} + +export default SweJsonParser; diff --git a/source/core/parsers/consysapi/common/SweXmlParser.parser.js b/source/core/parsers/consysapi/common/SweXmlParser.parser.js new file mode 100644 index 0000000000..705e5c3f37 --- /dev/null +++ b/source/core/parsers/consysapi/common/SweXmlParser.parser.js @@ -0,0 +1,9 @@ +import JsonDataParser from "../../../parsers/JsonDataParser"; + +class SweXmlParser extends JsonDataParser { + constructor(rootElement) { + super(rootElement) + } +} + +export default SweXmlParser; diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.collection.controlstream.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.collection.controlstream.parser.js new file mode 100644 index 0000000000..46f30df86b --- /dev/null +++ b/source/core/parsers/consysapi/observations/ConSysApiResult.collection.controlstream.parser.js @@ -0,0 +1,21 @@ +import ConSysApiResultControlStreamParser from "./ConSysApiResult.controlstream.parser"; + +class ConSysApiResultCollectionControlStreamParser extends ConSysApiResultControlStreamParser { + constructor(dataObject) { + super(dataObject); + } + + init(schema, format) { + if(format === 'application/swe+binary') { + //resultSchema + throw new Error(`Format not supported ${format}`); + } else if(format === 'application/swe+xml') { + //resultSchema + throw new Error(`Format not supported ${format}`); + } else { + super.init(schema, format); + } + } +} + +export default ConSysApiResultCollectionControlStreamParser; diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.collection.datastream.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.collection.datastream.parser.js new file mode 100644 index 0000000000..5016da7737 --- /dev/null +++ b/source/core/parsers/consysapi/observations/ConSysApiResult.collection.datastream.parser.js @@ -0,0 +1,22 @@ +import OmJsonCollectionParser from "../collection/CollectionOmJsonParser.parser"; +import ConSysApiResultDatastreamParser from "./ConSysApiResult.datastream.parser"; + +class ConSysApiResultCollectionDatastreamParser extends ConSysApiResultDatastreamParser { + constructor(dataObject) { + super(dataObject); + } + + init(schema, format) { + if(format === 'application/om+json') { + //resultSchema + this.parsers[format].parser = new OmJsonCollectionParser(schema.resultSchema); + } else if(format === 'application/swe+xml') { + //resultSchema + throw new Error(`Format not supported ${format}`); + } else { + super.init(schema, format); + } + } +} + +export default ConSysApiResultCollectionDatastreamParser; diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.controlstream.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.controlstream.parser.js new file mode 100644 index 0000000000..e47e7f3cc4 --- /dev/null +++ b/source/core/parsers/consysapi/observations/ConSysApiResult.controlstream.parser.js @@ -0,0 +1,34 @@ +import OmJsonParser from "../common/OmJsonParser.parser"; +import ConSysApiResultParser from "./ConSysApiResult.parser"; +import SweJsonParser from "../common/SweJsonParser.parser"; +import SweBinaryParser from "../common/SweBinaryParser.parser"; +import SweCsvParser from "../common/SweCsvParser.parser"; + +class ConSysApiResultControlStreamParser extends ConSysApiResultParser { + constructor(dataObject) { + super(dataObject); + } + + init(schema, format) { + if(format === 'application/om+json') { + //resultSchema + this.parsers[format].parser = new OmJsonParser(schema.commandSchema); + } else if(format === 'application/swe+json') { + //recordSchema + this.parsers[format].parser = new SweJsonParser(schema.commandSchema); + } /*else if(format === 'application/swe+xml') { + //recordSchema + this.parsers[format].parser = new SweXmlParser(schema.recordSchema); + }*/ else if(format === 'application/swe+binary') { + //recordSchema + this.parsers[format].parser = new SweBinaryParser(schema.commandSchema, schema.commandEncoding); + } else if(format === 'application/swe+csv') { + //recordSchema + this.parsers[format].parser = new SweCsvParser(schema.commandSchema, schema.commandEncoding); + } else { + throw Error(`Not supported parser format: ${format}`); + } + } +} + +export default ConSysApiResultControlStreamParser; diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.datastream.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.datastream.parser.js new file mode 100644 index 0000000000..a3c905bdec --- /dev/null +++ b/source/core/parsers/consysapi/observations/ConSysApiResult.datastream.parser.js @@ -0,0 +1,38 @@ +import OmJsonParser from "../common/OmJsonParser.parser"; +import ConSysApiResultParser from "./ConSysApiResult.parser"; +import SweJsonParser from "../common/SweJsonParser.parser"; +import SweBinaryParser from "../common/SweBinaryParser.parser"; +import SweCsvParser from "../common/SweCsvParser.parser"; +import {isDefined} from "../../../utils/Utils"; + +class ConSysApiResultDatastreamParser extends ConSysApiResultParser { + constructor(dataObject) { + super(dataObject); + } + + init(schema, format) { + if(format in this.parsers && isDefined(this.parsers[format].parser)) { + return this.parsers[format].parser; + } + if(format === 'application/om+json') { + //resultSchema + this.parsers[format].parser = new OmJsonParser(schema.resultSchema); + } else if(format === 'application/swe+json') { + //recordSchema + this.parsers[format].parser = new SweJsonParser(schema.recordSchema); + } /*else if(format === 'application/swe+xml') { + //recordSchema + this.parsers[format].parser = new SweXmlParser(schema.recordSchema); + }*/ else if(format === 'application/swe+binary') { + //recordSchema + this.parsers[format].parser = new SweBinaryParser(schema.recordSchema, schema.recordEncoding); + } else if(format === 'application/swe+csv') { + //recordSchema + this.parsers[format].parser = new SweCsvParser(schema.recordSchema, schema.recordEncoding); + } else { + throw Error(`Not supported parser format: ${format}`); + } + } +} + +export default ConSysApiResultDatastreamParser; diff --git a/source/core/parsers/consysapi/observations/ConSysApiResult.parser.js b/source/core/parsers/consysapi/observations/ConSysApiResult.parser.js new file mode 100644 index 0000000000..a12c8e3122 --- /dev/null +++ b/source/core/parsers/consysapi/observations/ConSysApiResult.parser.js @@ -0,0 +1,69 @@ +import ConnectedSystemsApiFilter from "../../../consysapi/Filter"; +import {isDefined} from "../../../utils/Utils"; + +class ConSysApiResultParser { + constructor(dataObject) { + this.dataObject = dataObject; + this.parsers = { + 'application/om+json' : { + schemaPromise: undefined, + parser: undefined + }, + 'application/swe+json' : { + schemaPromise: undefined, + parser: undefined + }, + 'application/swe+xml' : { + schemaPromise: undefined, + parser: undefined + }, + 'application/swe+csv' : { + schemaPromise: undefined, + parser: undefined + }, + 'application/swe+binary' : { + schemaPromise: undefined, + parser: undefined + } + } + } + + async checkParser(format) { + if(!(format in this.parsers)) { + throw new Error(`Not support format ${format}`); + } + + const parser = this.parsers[format]; + if(!isDefined(parser.parser)) { + if(!isDefined(parser.schemaPromise)) { + this.parsers[format].schemaPromise = new Promise(async (resolve, reject) => { + try { + const jsonSchema = await this.dataObject.getSchema(new ConnectedSystemsApiFilter({ + obsFormat: format + })); + this.init(jsonSchema, format); + resolve(); + } catch (ex) { + console.error(ex); + reject(ex); + } + }); + } + await parser.schemaPromise; + return this.parsers[format].parser; + } else { + return parser.parser; + } + } + + init(schema, format) { + throw new Error('Unsupported Operation') + } + + async parseDataBlock(arrayBuffer, format = 'application/om+json') { + const parser = await this.checkParser(format); + return parser.parseDataBlock(arrayBuffer); + } +} + +export default ConSysApiResultParser;