UNPKG

arcgis-api-client

Version:

ArcGIS Server REST API client module for Node.js

342 lines (314 loc) 10 kB
import servers from './servers'; import request from 'superagent'; import atRequest from 'request'; import fs from 'fs'; import requestProxy from 'superagent-proxy'; requestProxy(request); import urlworks from './urlworks'; import debug from 'debug'; const log = debug('arcgis'); const guid = () => { function s4() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); } return `${s4()} ${s4()} - ${s4()} - ${s4()} - ${s4()} - ${s4()} ${s4()} ${s4()}`; }; export default class FeatureServer { constructor(props, options = {}) { const { featureServerUrl, username, password } = props; this.featureServerUrl = featureServerUrl; this.username = username; this.password = password; this.serverUrl = urlworks.toArcgisServerBaseUrl(featureServerUrl); this.options = options; this.server = servers.getServer({ serverUrl: this.serverUrl, username, password }, options); } getRequest(url, params) { return new Promise((resolve, reject) => { let req = request.get(url); if (this.options.proxy) { req = req.proxy(this.options.proxy); } req .query(params) .accept('json') .end((err, res) => { if (err) { return reject(err); } if (!res.ok) { return reject(new Error('Query error (server response not ok).')); } let resBody; try { resBody = JSON.parse(res.text); } catch (e) { return reject(new Error('Query error (JSON parse error).')); } if (!!resBody.error) { return reject(new Error('Arcgis server: ' + resBody.error.message)); } return resolve(resBody); }); }); } postRequest(url, params) { return new Promise((resolve, reject) => { params = Object.assign({}, { f: 'json' }, params); let req = request.post(url); if (this.options.proxy) { req = req.proxy(this.options.proxy); } req .type('form') .send(params) .accept('json') .end((err, res) => { if (err) { return reject(err); } if (!res.ok) { return reject(new Error('Query error (server response not ok).')); } let resBody; try { resBody = JSON.parse(res.text); } catch (e) { return reject(new Error('Query error (JSON parse error).')); } if (!!resBody.error) { return reject(new Error('Arcgis server: ' + resBody.error.message)); } return resolve(resBody); }); }); } checkToken(params = {}, id = guid()) { if (this.server.needToken) { return this.server.getToken(id) .then(token => { log(id, 'token:', token); params.token = token; return params; }); } return Promise.resolve(params); } query(props = { where: '1=1' }) { let params = Object.assign({}, { outFields: '*', returnGeometry: false, where: '1=1' }, props); params.f = 'json'; params = this.prepObjectIds(params); log('query params:', params); return this.checkToken(params) .then((params) => { return this.getRequest(this.featureServerUrl + '/query', params) }); } queryCount(props = {}) { props.returnCountOnly = true; return this.query(props) .then(result => { if (!result.hasOwnProperty('count')) { return Promise.reject(new Error('Query result error: no count property returned.')); } return result.count; }); } add(features = []) { const params = { features: JSON.stringify(features) }; log('add params:', params); return this.checkToken(params) .then((params) => { return this.postRequest(this.featureServerUrl + '/addFeatures', params) }) .then(resBody => { if (!resBody.addResults) { // todo: error.message содержит больше данных return Promise.reject(new Error('Add error.')); } return resBody; }); } update(features = []) { const params = { features: JSON.stringify(features) }; log('update params:', params); return this.checkToken(params) .then((params) => { return this.postRequest(this.featureServerUrl + '/updateFeatures', params) }) .then(resBody => { if (!resBody.updateResults) { // todo: error.message содержит больше данных return Promise.reject(new Error('Update error.')); } return resBody; }); } prepObjectIds(params = {}) { if (params.objectIds) { if (Object.prototype.toString.call(params.objectIds) === '[object Array]') { params.objectIds = params.objectIds.join(', '); } else { if (typeof params.objectIds !== 'string') { log('objectIds type not supported.'); } } } return params; } delete(params = {}) { params = this.prepObjectIds(params); params.rollbackOnFailure = true; log('delete params:', params); return this.checkToken(params) .then((params) => { return this.postRequest(this.featureServerUrl + '/deleteFeatures', params) }) .then(resBody => { if (resBody.success || resBody.deleteResults) { return resBody; } else { return Promise.reject(new Error('Delete error.')); } }); } addAttachment(props = {}) { log('addAttachment props:', props); const params = { f: 'json' }; return this.checkToken(params) .then((params) => { params.objId = props.objId; params.rs = fs.createReadStream(props.filePath); return this.addAttach(params); }) .then(resBody => { if (!!resBody.addAttachmentResult) { log('!resBody.addAttachmentResult', resBody); // todo: error.message содержит больше данных return Promise.reject(new Error('addAttachmentResult error.')); } return Promise.resolve(resBody); }); } addAttach(params = {}) { log('in addAttach'); return new Promise((resolve) => { const { objId, rs, token } = params; const url = this.featureServerUrl + '/' + objId + '/addAttachment'; const r = atRequest.post(url, function (err, resp, body) { if (err) { return Promise.reject(err); } log(err, body); return resolve(body); }); const form = r.form(); form.append('f', 'json'); if (token) { form.append('token', token); } form.append('attachment', rs); }); } addAttachmentUrl(props = {}) { log('addAttachmentUrl props:', props); return this.checkToken() .then((params) => { params.objId = props.objId; const rs = atRequest.get(props.fileUrl); rs.on('error', function (err) { return Promise.reject(err); }); params.rs = rs; return this.addAttach(params); }) .then(resBody => { log(JSON.stringify(resBody)); if (!resBody.addAttachmentResult) { return Promise.reject(new Error('addAttachmentUrl error.')); } return resBody; }); } deleteAttachment(props = {}) { const params = { f: 'json', rollbackOnFailure: true, attachmentIds: props.attachmentIds }; if (params.attachmentIds) { if (Object.prototype.toString.call(params.attachmentIds) === '[object Array]') { params.attachmentIds = params.attachmentIds.join(', '); } else { if (typeof params.attachmentIds !== 'string') { return Promise.reject(new Error('attachmentIds type not supported.')); } } } else { return Promise.reject(new Error('attachmentIds is empty.')); } log('deleteAttachment params: ', params); return this.checkToken(params) .then((params) => { return this.postRequest(this.featureServerUrl + '/' + props.objId + '/deleteAttachments', params) }) .then(resBody => { if (!resBody.deleteAttachmentResults) { // todo: error.message содержит больше данных return Promise.reject(new Error('deleteAttachmentResults error.')); } return resBody; }); } attachmentInfos(objId) { log('attachmentInfos objId:', objId); const params = { f: 'json', }; return this.checkToken(params) .then((params) => { return this.getRequest(this.featureServerUrl + '/' + objId + '/attachments', params) }) .then(resBody => { if (!resBody.attachmentInfos) { // todo: error.message содержит больше данных return Promise.reject(new Error('attachmentInfos error.')); } return resBody; }); } connect(props = {}, id = guid()) { // Для теста id log(id, 1); const params = { f: 'json', }; return this.checkToken(params, id) .then((params) => { log(id, 2); return this.getRequest(this.featureServerUrl, params) }) .then(resBody => { log(id, 3); log(id, resBody.type); if (!(resBody.type && resBody.type === 'Feature Layer')) { return Promise.reject(new Error('Passed URL seems to be not an Arcgis FeatureServer' + ' REST endpoint')); } return resBody; }); } }