-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
520 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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'); | ||
|
@@ -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' | ||
|
@@ -120,7 +122,8 @@ class Connection { | |
} | ||
} | ||
|
||
this.capabilitiesObject = new Capabilities(data); | ||
GdcMigrate.connection = this; | ||
this.capabilitiesObject = new GdcCapabilities(data); | ||
return this.capabilitiesObject; | ||
} | ||
|
||
|
@@ -802,6 +805,45 @@ class Connection { | |
return await pg.describeUserProcess(); | ||
} | ||
|
||
isOgcProcess(process) { | ||
let nodes = Object.values(process.process_graph); | ||
return Boolean(nodes.find(node => { | ||
let process = this.processes.get(node.process_id); | ||
return Utils.isObject(process) && Boolean(process.ogcapi); | ||
})); | ||
} | ||
|
||
async executeOgcProcess(process, abortController = null) { | ||
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. | ||
* | ||
|
@@ -822,6 +864,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, | ||
|
@@ -1129,16 +1174,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 1177 in src/connection.js GitHub Actions / deploy
|
||
* @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); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | ||
|
||
constructor(data) { | ||
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() { | ||
if(!Array.isArray(this.data.conformsTo)) { | ||
return []; | ||
} | ||
return this.data.conformsTo; | ||
} | ||
|
||
hasConformance(uri) { | ||
if(!Array.isArray(this.data.conformsTo)) { | ||
return false; | ||
} | ||
return this.data.conformsTo.includes(uri); | ||
} | ||
|
||
_getLink(rel) { | ||
if (!Array.isArray(this.data.links)) { | ||
return null; | ||
} | ||
return this.data.links.find(link => link.rel === rel) || null; | ||
} | ||
|
||
checkConformance() { | ||
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) { | ||
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; |
Oops, something went wrong.