UNPKG

gme

Version:

modify google maps engine tables from node

262 lines (256 loc) 6.82 kB
'use strict'; var Promise = require('bluebird'); var auth = Promise.promisify(require('google-auth2-service-account').auth); var scope = 'https://www.googleapis.com/auth/mapsengine'; var rawRequest = Promise.promisify(require('request')); var Deque = require('double-ended-queue'); var fs = require('fs'); var Bulk = require('./bulk'); var limits = require('./limits.json'); var Stream = require('./stream'); var FeatureStream = require('./featureStream'); var readFile = Promise.promisify(fs.readFile, fs); var TRUE = Promise.resolve(true); module.exports = GME; function GME(key, email, table, opts) { if (Buffer.isBuffer(key)) { this.key = Promise.resolve(key); } else { this.key = readFile(key); } if (typeof opts === 'string') { opts = { primary: opts }; } this.iss = email; this.tableid = table; opts = opts || {}; this.primary = opts.primary || 'gx_id'; this.verbose = !!opts.verbose; this.nogeo = !!opts.nogeo; this.stopOnError = !!opts.stopOnError; if (opts.trace) { this.trace = opts.trace; } else { this.trace = false; } this.baseurl = 'https://www.googleapis.com/mapsengine/v1/'; this.queue = new Deque(); this.inProgress = false; if (opts.limits && typeof opts.limits === 'object') { this.limits = opts.limits; } else if (typeof opts.limits === 'string') { if (limits[opts.limits]) { this.limits = limits[opts.limits]; } } } GME.prototype._request = function (opts) { return rawRequest(opts).then(function (resp) { resp = resp[1]; if (resp && resp.error) { throw resp.error; } return resp; }); }; GME.prototype.request = function (opts) { if (this.inProgress) { var resolver = Promise.defer(); this.queue.push({ resolver: resolver, opts: opts }); return resolver.promise; } return this.createRequest(opts); }; GME.prototype.createRequest = function (opts) { var self = this; this.inProgress = true; var tries = 1; function attemptDownload(){ return self.auth().then(function (auth) { opts.headers = { Authorization: 'Bearer ' + auth }; return self._request(opts); }).catch(function (err) { if (tries++ > 10 || [401, 403, 429].indexOf(err.code) === -1 || self.stopOnError) { var error = new Error(err.message); error.code = err.code; error.errors = err.errors; if (self.verbose) { if (self.nogeo) { try { opts.body.features = opts.body.features.map(function (feature) { delete feature.geometry; return feature; }); } catch(e) {} } console.log(new Date()); console.log(err); console.log(JSON.stringify(opts, false, 4)); } throw error; } return Promise.delay(tries * 1000).then(function () { return attemptDownload(); }); }); } return attemptDownload().finally(function () { if (self.queue.length) { var next = self.queue.shift(); next.resolver.resolve(self.createRequest(next.opts)); return; } self.inProgress = false; }); }; GME.prototype.init = function () { var self = this; return this.key.then(function (key) { return auth(key, { iss: self.iss, scope: scope }).then(function (token) { if (self.timeout) { clearTimeout(self.timeout); self.timeout = null; } self.token = token; self.timeout = setTimeout(function () { self.token = null; self.timeout = null; }, 5 * 60 * 1000); return token; }); }); }; GME.prototype.auth = function () { if (this.token) { return Promise.resolve(this.token); } else { return this.init(); } }; GME.prototype.get = function (url, qs) { qs = qs || {}; url = this.baseurl + url; var self = this; if (this.trace) { qs.trace = this.trace; } return self.request({ url: url, qs: qs, json: true }); }; GME.prototype.post = function (url, body) { url = this.baseurl + url; var self = this; var opts = { url: url, body: body, json: true, method: 'POST' }; if (self.trace) { opts.qs = { trace: self.trace }; } return self.request(opts); }; GME.prototype.info = function () { return this.get('tables/' + this.tableid); }; GME.prototype.features = function (query) { var self = this; return new Promise(function (resolve, reject) { var out = { type: 'FeatureCollection', features: [] }; self.readStream(query).on('data', function (d) { out.features.push(d); }).on('finish', function () { resolve(out); }).on('error', reject); }); }; GME.prototype.featureStream = GME.prototype.readStream = function (query) { query = query || {}; return new FeatureStream(this, query); }; GME.prototype.feature = function (id) { return this.get('tables/' + this.tableid + '/features/' + id); }; GME.prototype.create = function(arr) { if (this.verbose && arr.length) { console.log(new Date()); console.log('create', arr.length); arr.forEach(function (item) { console.log(item.properties[this.primary]); }, this); } if (!arr.length) { return TRUE; } return this.post('tables/' + this.tableid + '/features/batchInsert', {features: arr}); }; GME.prototype.update = function(arr) { if (this.verbose && arr.length) { console.log(new Date()); console.log('update', arr.length); } if (!arr.length) { return TRUE; } return this.post('tables/' + this.tableid + '/features/batchPatch', {features: arr}); }; GME.prototype.remove = function(arr) { if (this.verbose && arr.length) { console.log(new Date()); console.log('remove', arr.length); arr.forEach(function (item) { console.log(item); }, this); console.log(this.tableid); } if (!arr.length) { return TRUE; } var self = this; if (this.primary !== 'gx_id') { return Promise.all(arr.map(this._fetchPrimaryKey, this)).then(function (arr) { return self.post('tables/' + self.tableid + '/features/batchDelete', {primaryKeys: arr}); }); } else { return self.post('tables/' + self.tableid + '/features/batchDelete', {primaryKeys: arr}); } }; GME.prototype._fetchPrimaryKey = function (item) { var query = {where: this.primary + '=\'' + item + '\''}; var self = this; return this.features(query).then(function (resp) { if (!resp.features.length) { return item; } var out = resp.features[0].properties.gx_id || item; if (self.verbose) { console.log(item, out); } return out; }); }; GME.prototype.bulk = function() { return new Bulk(this); }; GME.prototype.writeStream = function() { return new Stream(this); };