Skip to content

Commit

Permalink
GDC draft
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mohr committed Sep 8, 2024
1 parent f3f5c9a commit 30cd63c
Show file tree
Hide file tree
Showing 5 changed files with 520 additions and 6 deletions.
57 changes: 52 additions & 5 deletions src/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const AuthProvider = require('./authprovider');
const BasicProvider = require('./basicprovider');
const OidcProvider = require('./oidcprovider');

const Capabilities = require('./capabilities');
const GdcCapabilities = require('./gdc/capabilities');
const GdcMigrate = require('./gdc/migrate');
const FileTypes = require('./filetypes');
const UserFile = require('./userfile');
const Job = require('./job');
Expand All @@ -18,6 +19,7 @@ const Service = require('./service');
const Builder = require('./builder/builder');
const BuilderNode = require('./builder/node');


const CONFORMANCE_RELS = [
'conformance',
'http://www.opengis.net/def/rel/ogc/1.0/conformance'
Expand Down Expand Up @@ -120,7 +122,8 @@ class Connection {
}
}

this.capabilitiesObject = new Capabilities(data);
GdcMigrate.connection = this;
this.capabilitiesObject = new GdcCapabilities(data);
return this.capabilitiesObject;
}

Expand Down Expand Up @@ -802,6 +805,45 @@ class Connection {
return await pg.describeUserProcess();
}

isOgcProcess(process) {

Check failure on line 808 in src/connection.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

Check failure on line 808 in src/connection.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment
let nodes = Object.values(process.process_graph);
return Boolean(nodes.find(node => {
let process = this.processes.get(node.process_id);

Check failure on line 811 in src/connection.js

View workflow job for this annotation

GitHub Actions / checks

'process' is already declared in the upper scope on line 808 column 15

Check failure on line 811 in src/connection.js

View workflow job for this annotation

GitHub Actions / checks

'process' is already declared in the upper scope on line 808 column 15
return Utils.isObject(process) && Boolean(process.ogcapi);
}));
}

async executeOgcProcess(process, abortController = null) {

Check failure on line 816 in src/connection.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

Check failure on line 816 in src/connection.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment
let openEO = this._normalizeUserProcess(process);
let mode = null;
let p = Object.values(openEO.process.process_graph).find(v => {
let spec = this.processes.get(v.process_id);
if (Array.isArray(spec.jobControlOptions) && spec.jobControlOptions.includes("async-execute")) {
mode = 'async';
}
return Boolean(spec && spec.ogcapi);
});
let requestBody = GdcMigrate.execute(openEO);
let headers = {};
if (mode === 'async') {
headers.Prefer = 'respond-async';
}
console.log(p.process_id, requestBody, headers); // @todo remove
let response = await this._post(`/processes/${p.process_id}/execution`, requestBody, Environment.getResponseType(), abortController, headers);
let syncResult = {
data: response.data,
costs: null,
type: null,
logs: []
};

if (typeof response.headers['content-type'] === 'string') {
syncResult.type = response.headers['content-type'];
}

return syncResult;
}

/**
* Executes a process synchronously and returns the result as the response.
*
Expand All @@ -823,6 +865,9 @@ class Connection {
budget: budget
})
);
if (this.isOgcProcess(requestBody.process)) {
return this.executeOgcProcess(process, abortController);
}
let response = await this._post('/result', requestBody, Environment.getResponseType(), abortController);
let syncResult = {
data: response.data,
Expand Down Expand Up @@ -1131,16 +1176,18 @@ class Connection {
* @param {*} body
* @param {string} responseType - Response type according to axios, defaults to `json`.
* @param {?AbortController} [abortController=null] - An AbortController object that can be used to cancel the request.
* @param {Array.<Object.<string, string>>} [headers={}] - Headers

Check warning on line 1179 in src/connection.js

View workflow job for this annotation

GitHub Actions / checks

Invalid JSDoc @param "headers" type "Object"; prefer: "object"

Check warning on line 1179 in src/connection.js

View workflow job for this annotation

GitHub Actions / checks

Invalid JSDoc @param "headers" type "Object"; prefer: "object"
* @returns {Promise<AxiosResponse>}
* @throws {Error}
* @see https://github.com/axios/axios#request-config
*/
async _post(path, body, responseType, abortController = null) {
async _post(path, body, responseType, abortController = null, headers = {}) {
let options = {
method: 'post',
responseType: responseType,
responseType,
url: path,
data: body
data: body,
headers
};
return await this._send(options, abortController);
}
Expand Down
219 changes: 219 additions & 0 deletions src/gdc/capabilities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
const Capabilities = require("../capabilities");
const Utils = require('@openeo/js-commons/src/utils');
const Migrate = require('./migrate');

class GdcCapabilities extends Capabilities {

Check failure on line 5 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

Check failure on line 5 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

constructor(data) {

Check failure on line 7 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

Check failure on line 7 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment
super(data);
Object.assign(this.featureMap, {
describeCoverage: 'get /collections/{}/coverage',
describeCoverageDomainset: 'get /collections/{}/coverage/domainset',
describeCoverageRangetype: 'get /collections/{}/coverage/rangetype',
describeCoverageRangeset: 'get /collections/{}/coverage/rangeset',
describeCoverageMetadata: 'get /collections/{}/coverage/metadata',
executeOgcProcess: 'post /processes/{}/execution',
});
this.checkConformance();
}

getConformanceClasses() {

Check failure on line 20 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

Check failure on line 20 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment
if(!Array.isArray(this.data.conformsTo)) {
return [];
}
return this.data.conformsTo;
}

hasConformance(uri) {

Check failure on line 27 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

Check failure on line 27 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment
if(!Array.isArray(this.data.conformsTo)) {
return false;
}
return this.data.conformsTo.includes(uri);
}

_getLink(rel) {

Check failure on line 34 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

Check failure on line 34 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment
if (!Array.isArray(this.data.links)) {
return null;
}
return this.data.links.find(link => link.rel === rel) || null;
}

checkConformance() {

Check failure on line 41 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

Check failure on line 41 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment
if (!Array.isArray(this.data.endpoints)) {
this.data.endpoints = [];
}
const isCoverage = this.hasConformance('http://www.opengis.net/spec/ogcapi-coverages-1/0.0/conf/geodata-coverage');
const isFeatures = this.hasConformance('http://www.opengis.net/spec/ogcapi-features-1/1.0/conf/core');
if (isCoverage || isFeatures) {
this.data.endpoints.push({
"path": "/collections",
"methods": ["GET"]
});
this.data.endpoints.push({
"path": "/collections/{collection_id}",
"methods": ["GET"]
});
}
// if (isFeatures) {
// this.data.endpoints.push({
// "path": "/collections/{collection_id}/items",
// "methods": ["GET"]
// });
// this.data.endpoints.push({
// "path": "/collections/{collection_id}/items/{item_id}",
// "methods": ["GET"]
// });
// }
if (isCoverage) {
this.data.endpoints.push({
"path": "/collections/{collection_id}/coverage",
"methods": ["GET"]
});
this.data.endpoints.push({
"path": "/collections/{collection_id}/coverage",
"methods": ["GET"]
});
this.data.endpoints.push({
"path": "/collections/{collection_id}/coverage/domainset",
"methods": ["GET"]
});
this.data.endpoints.push({
"path": "/collections/{collection_id}/coverage/rangetype",
"methods": ["GET"]
});
this.data.endpoints.push({
"path": "/collections/{collection_id}/coverage/rangeset",
"methods": ["GET"]
});
this.data.endpoints.push({
"path": "/collections/{collection_id}/coverage/metadata",
"methods": ["GET"]
});
}
const isProcessApi = this.hasConformance('http://www.opengis.net/spec/ogcapi-processes-1/1.0/conf/core');
const processDismiss = this.hasConformance('http://www.opengis.net/spec/ogcapi-processes-1/1.0/conf/dismiss');
const processJobList = this.hasConformance('http://www.opengis.net/spec/ogcapi-processes-1/1.0/req/job-list');
const processLink = this._getLink('https://www.opengis.net/def/rel/ogc/1.0/processes');
if (isProcessApi || processLink) {
this.data.endpoints.push({
"path": "/processes",
"methods": ["GET"]
});
this.data.endpoints.push({
"path": "/processes/{processId}",
"methods": ["GET"]
});
this.data.endpoints.push({
"path": "/processes/{processId}/execution",
"methods": ["POST"]
});
let jobMethods = ["GET"];
if (processDismiss) { // @todo Is dismiss equivalent to openEO job cancellation or deletion?
jobMethods.push("DELETE");
}
this.data.endpoints.push({
"path": "/jobs/{job_id}",
"methods": jobMethods
});
this.data.endpoints.push({
"path": "/jobs/{job_id}/results",
"methods": ["GET"]
});
}
const jobLink = this._getLink('https://www.opengis.net/def/rel/ogc/1.0/job-list');
if (processJobList || jobLink) {
this.data.endpoints.push({
"path": "/jobs",
"methods": ["GET"]
});
}
this.init();
}

/**
* Initializes the class.
*
* @protected
*/
init() {
if (Array.isArray(this.data.endpoints)) {
super.init();
}
}

/**
* Validates the capabilities.
*
* Throws an error in case of an issue, otherwise just passes.
*
* @protected
* @throws {Error}
*/
validate() {
if(!Utils.isObject(this.data)) {
throw new Error("No capabilities retrieved.");
}
}

/**
* Returns the openEO API version implemented by the back-end.
*
* @returns {string} openEO API version number.F
*/
apiVersion() {
return this.data.api_version;
}

/**
* Returns the GDC API version implemented by the back-end.
*
* @returns {string} GDC API version number.
*/
gdcVersion() {
return this.data.gdc_version || "1.0.0-beta";
}

isEndpoint(response, method, endpoint) {

Check failure on line 176 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment

Check failure on line 176 in src/gdc/capabilities.js

View workflow job for this annotation

GitHub Actions / checks

Missing JSDoc comment
if (response.config.method !== method) {
return false;
}
if (endpoint.includes('{}')) {
let pattern = '^' + endpoint.replace('{}', '[^/]+') + '$';
let regex = new RegExp(pattern);
return regex.test(response.config.url);
}
return endpoint === response.config.url;
}

/**
* Migrates a response, if required.
*
* @param {AxiosResponse} response
* @protected
* @returns {AxiosResponse}
*/
migrate(response) {
if (this.isEndpoint(response, 'get', '/collections')) {
response.data.collections = response.data.collections.map(collection => Migrate.collection(collection, response));
}
else if (this.isEndpoint(response, 'get', '/collections/{}')) {
response.data = Migrate.collection(response.data, response);
}
else if (this.isEndpoint(response, 'get', '/processes')) {
response.data.processes = response.data.processes.map(process => Migrate.process(process, response));
}
else if (this.isEndpoint(response, 'get', '/jobs')) {
response.data.jobs = response.data.jobs.map(job => Migrate.job(job, response));
}
else if (this.isEndpoint(response, 'get', '/jobs/{}')) {
response.data = Migrate.job(response.data, response);
}

response = Migrate.all(response);

return response;
}
}


module.exports = GdcCapabilities;
Loading

0 comments on commit 30cd63c

Please sign in to comment.