From ccaf73d5fcfcab2fd6036403437fe0069c59056e Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 22 Sep 2015 13:58:29 -0400 Subject: [PATCH 01/40] updated README --- README.md | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index bcec6e2..53d2f71 100644 --- a/README.md +++ b/README.md @@ -3,21 +3,24 @@ Basic library to help with calling IDOL OnDemand APIs [http://idolondemand.com](http://idolondemand.com) ### Installation - ``` -npm install git+ +npm install iod-node +``` +If you want to install the latest module directly from Github, use the following command: +``` +npm install git+https://github.com/HP-IDOL-OnDemand/iod-node ``` -### Start +### Include it ```js var iod = require('iod-node') -client= new iod.IODClient('http://api.idolondemand.com','apikey') +client = new iod.IODClient('http://api.idolondemand.com','apikey') ``` ### Callbacks -``` +```js var callback = function(err,resp,body){ console.log(body) } @@ -25,41 +28,41 @@ var callback = function(err,resp,body){ We can define our callbacks as functions and pass them as arguments +```js +var data = {'text' : 'I like cats'} +client.call('analyzesentiment', callback, data) ``` -var data= {'text':'I like cats'} -client.call('analyzesentiment',callback,data) -``` - -Or we can use the .on('data') hook to do the same thing. +Or, we can use the .on('data') hook to do the same thing. -``` +```js client.call('analyzesentiment',data).on('data',callback) ``` -THe order of the arguments after the api name don't matter when passed. - -``` -client.call('analyzesentiment',data,callback) +The order of the arguments after the API name don't matter when passed, so all of these are the equivalent. +```js +//1 +client.call('analyzesentiment', data, callback) +//2 +client.call(data, 'analyzesentiment', callback) +//3 +client.call(data, callback, 'analyzesentiment') ``` ### Async calls -While node will mostly deal with things asynchronously, IDOL OnDemand offers a servetr side asynchronous calls method which should be used with large files and slow queries. +While node will mostly deal with things asynchronously, IDOL OnDemand offers server side asynchronous call method which should be used with large files and slow queries. Pass a boolean for the async parameter. -``` -client.call('analyzesentiment',callback,data,true) +```js +client.call('analyzesentiment', data, callback, true) ``` -Pass a boolean for the async parameter. - - ### Posting files File posting is handled using the "file" parameter name which is used for all current file postings in IDOL OnDemand -``` -var data={'file':'test.txt'} -client.call('analyzesentiment',data,callback) +```js +var data={'file' : 'test.txt'} +client.call('analyzesentiment', data, callback) ``` From e99589d4a96b2b5c8e1db210b170b02e743fcb05 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 22 Sep 2015 13:59:06 -0400 Subject: [PATCH 02/40] updated version --- npm-debug.log | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 npm-debug.log diff --git a/npm-debug.log b/npm-debug.log new file mode 100644 index 0000000..ff174e1 --- /dev/null +++ b/npm-debug.log @@ -0,0 +1,87 @@ +0 info it worked if it ends with ok +1 verbose cli [ 'node', '/usr/local/bin/npm', 'publish' ] +2 info using npm@2.7.4 +3 info using node@v0.12.2 +4 verbose publish [ '.' ] +5 silly cache add args [ '.', null ] +6 verbose cache add spec . +7 silly cache add parsed spec { raw: '.', +7 silly cache add scope: null, +7 silly cache add name: null, +7 silly cache add rawSpec: '.', +7 silly cache add spec: '/Users/tylernappy/node_projects/iod-node', +7 silly cache add type: 'directory' } +8 verbose addLocalDirectory /Users/tylernappy/.npm/iod-node/0.1.1/package.tgz not in flight; packing +9 verbose tar pack [ '/Users/tylernappy/.npm/iod-node/0.1.1/package.tgz', +9 verbose tar pack '/Users/tylernappy/node_projects/iod-node' ] +10 verbose tarball /Users/tylernappy/.npm/iod-node/0.1.1/package.tgz +11 verbose folder /Users/tylernappy/node_projects/iod-node +12 info prepublish iod-node@0.1.1 +13 verbose addLocalTarball adding from inside cache /Users/tylernappy/.npm/iod-node/0.1.1/package.tgz +14 silly cache afterAdd iod-node@0.1.1 +15 verbose afterAdd /Users/tylernappy/.npm/iod-node/0.1.1/package/package.json not in flight; writing +16 verbose afterAdd /Users/tylernappy/.npm/iod-node/0.1.1/package/package.json written +17 silly publish { name: 'iod-node', +17 silly publish version: '0.1.1', +17 silly publish description: 'Idol OnDemand node client', +17 silly publish main: 'index.js', +17 silly publish dependencies: { needle: '^0.7.10' }, +17 silly publish devDependencies: {}, +17 silly publish scripts: { test: 'node test.js' }, +17 silly publish author: { name: 'Martin Zerbib' }, +17 silly publish license: 'MIT', +17 silly publish readme: '# Node JS client library for IDOL OnDemand\n\nBasic library to help with calling IDOL OnDemand APIs [http://idolondemand.com](http://idolondemand.com)\n\n### Installation\n```\nnpm install iod-node\n```\nIf you want to install the latest module directly from Github, use the following command:\n```\nnpm install git+https://github.com/HP-IDOL-OnDemand/iod-node\n```\n\n### Include it\n\n```js\nvar iod = require(\'iod-node\')\nclient = new iod.IODClient(\'http://api.idolondemand.com\',\'apikey\')\n```\n\n### Callbacks\n\n```js\nvar callback = function(err,resp,body){\n console.log(body)\n}\n```\n\nWe can define our callbacks as functions and pass them as arguments\n\n```js\nvar data = {\'text\' : \'I like cats\'}\nclient.call(\'analyzesentiment\', callback, data)\n```\nOr, we can use the .on(\'data\') hook to do the same thing.\n\n```js\nclient.call(\'analyzesentiment\',data).on(\'data\',callback)\n```\n\nThe order of the arguments after the API name don\'t matter when passed, so all of these are the equivalent.\n\n```js\n//1\nclient.call(\'analyzesentiment\', data, callback)\n//2\nclient.call(data, \'analyzesentiment\', callback)\n//3\nclient.call(data, callback, \'analyzesentiment\')\n```\n\n\n### Async calls\n\nWhile node will mostly deal with things asynchronously, IDOL OnDemand offers server side asynchronous call method which should be used with large files and slow queries. Pass a boolean for the async parameter.\n\n```js\nclient.call(\'analyzesentiment\', data, callback, true)\n```\n\n### Posting files\n\nFile posting is handled using the "file" parameter name which is used for all current file postings in IDOL OnDemand\n\n```js\nvar data={\'file\' : \'test.txt\'}\nclient.call(\'analyzesentiment\', data, callback)\n```\n', +17 silly publish readmeFilename: 'README.md', +17 silly publish gitHead: 'ccaf73d5fcfcab2fd6036403437fe0069c59056e', +17 silly publish _id: 'iod-node@0.1.1', +17 silly publish _shasum: '3e4e6a3b836b9e11fbe93dd09785171d4b0e8e50', +17 silly publish _from: '.' } +18 silly mapToRegistry name iod-node +19 silly mapToRegistry using default registry +20 silly mapToRegistry registry https://registry.npmjs.org/ +21 silly mapToRegistry uri https://registry.npmjs.org/iod-node +22 verbose publish registryBase https://registry.npmjs.org/ +23 silly publish uploading /Users/tylernappy/.npm/iod-node/0.1.1/package.tgz +24 verbose request uri https://registry.npmjs.org/iod-node +25 verbose request sending authorization for write operation +26 info attempt registry request try #1 at 1:58:40 PM +27 verbose request using bearer token for auth +28 verbose request id 6d67e8b7db7c85ed +29 http request PUT https://registry.npmjs.org/iod-node +30 http 403 https://registry.npmjs.org/iod-node +31 verbose headers { 'content-type': 'application/json', +31 verbose headers 'cache-control': 'max-age=60', +31 verbose headers 'content-length': '95', +31 verbose headers 'accept-ranges': 'bytes', +31 verbose headers date: 'Tue, 22 Sep 2015 17:58:42 GMT', +31 verbose headers via: '1.1 varnish', +31 verbose headers connection: 'keep-alive', +31 verbose headers 'x-served-by': 'cache-iad2136-IAD', +31 verbose headers 'x-cache': 'MISS', +31 verbose headers 'x-cache-hits': '0', +31 verbose headers 'x-timer': 'S1442944721.773050,VS0,VE720' } +32 verbose request invalidating /Users/tylernappy/.npm/registry.npmjs.org/iod-node on PUT +33 error publish Failed PUT 403 +34 verbose stack Error: "You cannot publish over the previously published version 0.1.1." : iod-node +34 verbose stack at CachingRegistryClient. (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:247:14) +34 verbose stack at Request._callback (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:170:14) +34 verbose stack at Request.self.callback (/usr/local/lib/node_modules/npm/node_modules/request/request.js:344:22) +34 verbose stack at Request.emit (events.js:110:17) +34 verbose stack at Request. (/usr/local/lib/node_modules/npm/node_modules/request/request.js:1239:14) +34 verbose stack at Request.emit (events.js:129:20) +34 verbose stack at IncomingMessage. (/usr/local/lib/node_modules/npm/node_modules/request/request.js:1187:12) +34 verbose stack at IncomingMessage.emit (events.js:129:20) +34 verbose stack at _stream_readable.js:908:16 +34 verbose stack at process._tickCallback (node.js:355:11) +35 verbose statusCode 403 +36 verbose pkgid iod-node +37 verbose cwd /Users/tylernappy/node_projects/iod-node +38 error Darwin 14.3.0 +39 error argv "node" "/usr/local/bin/npm" "publish" +40 error node v0.12.2 +41 error npm v2.7.4 +42 error code E403 +43 error "You cannot publish over the previously published version 0.1.1." : iod-node +44 error If you need help, you may report this error at: +44 error +45 verbose exit [ 1, true ] diff --git a/package.json b/package.json index 82875a3..5882113 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iod-node", - "version": "0.1.1", + "version": "0.1.2", "description": "Idol OnDemand node client", "main": "index.js", "dependencies": { From 215bed673d4727bbb6aec76fe7f144471d069a56 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 22 Sep 2015 18:21:29 -0400 Subject: [PATCH 03/40] updated README --- README.md | 21 +++++++++++-- npm-debug.log | 87 --------------------------------------------------- 2 files changed, 18 insertions(+), 90 deletions(-) delete mode 100644 npm-debug.log diff --git a/README.md b/README.md index 53d2f71..087d8d1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,23 @@ # Node JS client library for IDOL OnDemand - -Basic library to help with calling IDOL OnDemand APIs [http://idolondemand.com](http://idolondemand.com) +Basic library to help with calling IDOL OnDemand APIs [http://idolondemand.com](http://idolondemand.com). + +## What is IDOL OnDemand? +IDOL OnDemand is a set of over 70 APIs for handling all sorts of unstructured data. Here are just some of our APIs' capabilities: +* Speech to text +* OCR +* Text extraction +* Indexing documents +* Smart search +* Language identification +* Concept extraction +* Sentiment analysis +* Web crawlers +* Machine learning + +For a full list of all the APIs and to try them out, check out https://www.idolondemand.com/developer/apis ### Installation +To install, run the following command: ``` npm install iod-node ``` @@ -63,6 +78,6 @@ client.call('analyzesentiment', data, callback, true) File posting is handled using the "file" parameter name which is used for all current file postings in IDOL OnDemand ```js -var data={'file' : 'test.txt'} +var data = {'file' : 'test.txt'} client.call('analyzesentiment', data, callback) ``` diff --git a/npm-debug.log b/npm-debug.log deleted file mode 100644 index ff174e1..0000000 --- a/npm-debug.log +++ /dev/null @@ -1,87 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ 'node', '/usr/local/bin/npm', 'publish' ] -2 info using npm@2.7.4 -3 info using node@v0.12.2 -4 verbose publish [ '.' ] -5 silly cache add args [ '.', null ] -6 verbose cache add spec . -7 silly cache add parsed spec { raw: '.', -7 silly cache add scope: null, -7 silly cache add name: null, -7 silly cache add rawSpec: '.', -7 silly cache add spec: '/Users/tylernappy/node_projects/iod-node', -7 silly cache add type: 'directory' } -8 verbose addLocalDirectory /Users/tylernappy/.npm/iod-node/0.1.1/package.tgz not in flight; packing -9 verbose tar pack [ '/Users/tylernappy/.npm/iod-node/0.1.1/package.tgz', -9 verbose tar pack '/Users/tylernappy/node_projects/iod-node' ] -10 verbose tarball /Users/tylernappy/.npm/iod-node/0.1.1/package.tgz -11 verbose folder /Users/tylernappy/node_projects/iod-node -12 info prepublish iod-node@0.1.1 -13 verbose addLocalTarball adding from inside cache /Users/tylernappy/.npm/iod-node/0.1.1/package.tgz -14 silly cache afterAdd iod-node@0.1.1 -15 verbose afterAdd /Users/tylernappy/.npm/iod-node/0.1.1/package/package.json not in flight; writing -16 verbose afterAdd /Users/tylernappy/.npm/iod-node/0.1.1/package/package.json written -17 silly publish { name: 'iod-node', -17 silly publish version: '0.1.1', -17 silly publish description: 'Idol OnDemand node client', -17 silly publish main: 'index.js', -17 silly publish dependencies: { needle: '^0.7.10' }, -17 silly publish devDependencies: {}, -17 silly publish scripts: { test: 'node test.js' }, -17 silly publish author: { name: 'Martin Zerbib' }, -17 silly publish license: 'MIT', -17 silly publish readme: '# Node JS client library for IDOL OnDemand\n\nBasic library to help with calling IDOL OnDemand APIs [http://idolondemand.com](http://idolondemand.com)\n\n### Installation\n```\nnpm install iod-node\n```\nIf you want to install the latest module directly from Github, use the following command:\n```\nnpm install git+https://github.com/HP-IDOL-OnDemand/iod-node\n```\n\n### Include it\n\n```js\nvar iod = require(\'iod-node\')\nclient = new iod.IODClient(\'http://api.idolondemand.com\',\'apikey\')\n```\n\n### Callbacks\n\n```js\nvar callback = function(err,resp,body){\n console.log(body)\n}\n```\n\nWe can define our callbacks as functions and pass them as arguments\n\n```js\nvar data = {\'text\' : \'I like cats\'}\nclient.call(\'analyzesentiment\', callback, data)\n```\nOr, we can use the .on(\'data\') hook to do the same thing.\n\n```js\nclient.call(\'analyzesentiment\',data).on(\'data\',callback)\n```\n\nThe order of the arguments after the API name don\'t matter when passed, so all of these are the equivalent.\n\n```js\n//1\nclient.call(\'analyzesentiment\', data, callback)\n//2\nclient.call(data, \'analyzesentiment\', callback)\n//3\nclient.call(data, callback, \'analyzesentiment\')\n```\n\n\n### Async calls\n\nWhile node will mostly deal with things asynchronously, IDOL OnDemand offers server side asynchronous call method which should be used with large files and slow queries. Pass a boolean for the async parameter.\n\n```js\nclient.call(\'analyzesentiment\', data, callback, true)\n```\n\n### Posting files\n\nFile posting is handled using the "file" parameter name which is used for all current file postings in IDOL OnDemand\n\n```js\nvar data={\'file\' : \'test.txt\'}\nclient.call(\'analyzesentiment\', data, callback)\n```\n', -17 silly publish readmeFilename: 'README.md', -17 silly publish gitHead: 'ccaf73d5fcfcab2fd6036403437fe0069c59056e', -17 silly publish _id: 'iod-node@0.1.1', -17 silly publish _shasum: '3e4e6a3b836b9e11fbe93dd09785171d4b0e8e50', -17 silly publish _from: '.' } -18 silly mapToRegistry name iod-node -19 silly mapToRegistry using default registry -20 silly mapToRegistry registry https://registry.npmjs.org/ -21 silly mapToRegistry uri https://registry.npmjs.org/iod-node -22 verbose publish registryBase https://registry.npmjs.org/ -23 silly publish uploading /Users/tylernappy/.npm/iod-node/0.1.1/package.tgz -24 verbose request uri https://registry.npmjs.org/iod-node -25 verbose request sending authorization for write operation -26 info attempt registry request try #1 at 1:58:40 PM -27 verbose request using bearer token for auth -28 verbose request id 6d67e8b7db7c85ed -29 http request PUT https://registry.npmjs.org/iod-node -30 http 403 https://registry.npmjs.org/iod-node -31 verbose headers { 'content-type': 'application/json', -31 verbose headers 'cache-control': 'max-age=60', -31 verbose headers 'content-length': '95', -31 verbose headers 'accept-ranges': 'bytes', -31 verbose headers date: 'Tue, 22 Sep 2015 17:58:42 GMT', -31 verbose headers via: '1.1 varnish', -31 verbose headers connection: 'keep-alive', -31 verbose headers 'x-served-by': 'cache-iad2136-IAD', -31 verbose headers 'x-cache': 'MISS', -31 verbose headers 'x-cache-hits': '0', -31 verbose headers 'x-timer': 'S1442944721.773050,VS0,VE720' } -32 verbose request invalidating /Users/tylernappy/.npm/registry.npmjs.org/iod-node on PUT -33 error publish Failed PUT 403 -34 verbose stack Error: "You cannot publish over the previously published version 0.1.1." : iod-node -34 verbose stack at CachingRegistryClient. (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:247:14) -34 verbose stack at Request._callback (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/request.js:170:14) -34 verbose stack at Request.self.callback (/usr/local/lib/node_modules/npm/node_modules/request/request.js:344:22) -34 verbose stack at Request.emit (events.js:110:17) -34 verbose stack at Request. (/usr/local/lib/node_modules/npm/node_modules/request/request.js:1239:14) -34 verbose stack at Request.emit (events.js:129:20) -34 verbose stack at IncomingMessage. (/usr/local/lib/node_modules/npm/node_modules/request/request.js:1187:12) -34 verbose stack at IncomingMessage.emit (events.js:129:20) -34 verbose stack at _stream_readable.js:908:16 -34 verbose stack at process._tickCallback (node.js:355:11) -35 verbose statusCode 403 -36 verbose pkgid iod-node -37 verbose cwd /Users/tylernappy/node_projects/iod-node -38 error Darwin 14.3.0 -39 error argv "node" "/usr/local/bin/npm" "publish" -40 error node v0.12.2 -41 error npm v2.7.4 -42 error code E403 -43 error "You cannot publish over the previously published version 0.1.1." : iod-node -44 error If you need help, you may report this error at: -44 error -45 verbose exit [ 1, true ] From 0edca059f5412b6294e33473a364fec916b9dd4b Mon Sep 17 00:00:00 2001 From: tylernappy Date: Sun, 27 Sep 2015 13:11:38 -0700 Subject: [PATCH 04/40] updated REDAME --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 087d8d1..ddaa6e6 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Or, we can use the .on('data') hook to do the same thing. client.call('analyzesentiment',data).on('data',callback) ``` -The order of the arguments after the API name don't matter when passed, so all of these are the equivalent. +The order of the arguments after the API name doesn't matter when passed, so all of these are the equivalent. ```js //1 From 8a837b80319520538218d2c689fbb71091af6a62 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 7 Oct 2015 17:46:44 -0400 Subject: [PATCH 05/40] added gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ From 9e388e2cf2fd63bef89ebfb4376ad0eba0abd222 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 7 Oct 2015 17:55:18 -0400 Subject: [PATCH 06/40] updated to Haven from IDOL --- README.md | 22 +++++++-------- index.js | 4 +-- lib/{iodneedle.js => hodneedle.js} | 44 +++++++++++++++--------------- package.json | 4 +-- 4 files changed, 37 insertions(+), 37 deletions(-) rename lib/{iodneedle.js => hodneedle.js} (77%) diff --git a/README.md b/README.md index ddaa6e6..b15dffe 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Node JS client library for IDOL OnDemand -Basic library to help with calling IDOL OnDemand APIs [http://idolondemand.com](http://idolondemand.com). +# Node JS client library for Haven OnDemand +Basic library to help with calling Haven OnDemand APIs [http://havenondemand.com](http://havenondemand.com). -## What is IDOL OnDemand? -IDOL OnDemand is a set of over 70 APIs for handling all sorts of unstructured data. Here are just some of our APIs' capabilities: +## What is Haven OnDemand? +Haven OnDemand is a set of over 70 APIs for handling all sorts of unstructured data. Here are just some of our APIs' capabilities: * Speech to text * OCR * Text extraction @@ -14,23 +14,23 @@ IDOL OnDemand is a set of over 70 APIs for handling all sorts of unstructured da * Web crawlers * Machine learning -For a full list of all the APIs and to try them out, check out https://www.idolondemand.com/developer/apis +For a full list of all the APIs and to try them out, check out https://www.havenondemand.com/developer/apis ### Installation To install, run the following command: ``` -npm install iod-node +npm install hod-node ``` If you want to install the latest module directly from Github, use the following command: ``` -npm install git+https://github.com/HP-IDOL-OnDemand/iod-node +npm install git+https://github.com/HP-Haven-OnDemand/hod-node ``` ### Include it ```js -var iod = require('iod-node') -client = new iod.IODClient('http://api.idolondemand.com','apikey') +var hod = require('hod-node') +client = new hod.HODClient('http://api.havenondemand.com','apikey') ``` ### Callbacks @@ -67,7 +67,7 @@ client.call(data, callback, 'analyzesentiment') ### Async calls -While node will mostly deal with things asynchronously, IDOL OnDemand offers server side asynchronous call method which should be used with large files and slow queries. Pass a boolean for the async parameter. +While node will mostly deal with things asynchronously, Haven OnDemand offers server side asynchronous call method which should be used with large files and slow queries. Pass a boolean for the async parameter. ```js client.call('analyzesentiment', data, callback, true) @@ -75,7 +75,7 @@ client.call('analyzesentiment', data, callback, true) ### Posting files -File posting is handled using the "file" parameter name which is used for all current file postings in IDOL OnDemand +File posting is handled using the "file" parameter name which is used for all current file postings in Haven OnDemand ```js var data = {'file' : 'test.txt'} diff --git a/index.js b/index.js index a407198..c392e19 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,3 @@ -var iod = require('./lib/iodneedle') +var hod = require('./lib/hodneedle') -module.exports=iod +module.exports=hod diff --git a/lib/iodneedle.js b/lib/hodneedle.js similarity index 77% rename from lib/iodneedle.js rename to lib/hodneedle.js index d8c8c7e..b8ec86e 100644 --- a/lib/iodneedle.js +++ b/lib/hodneedle.js @@ -2,7 +2,7 @@ var needle = require('needle') var util = require('util') var fs = require('fs') // Constructor -function IODClient(endpoint,apikey) { +function HODClient(endpoint,apikey) { // always initialize all instance properties this.apikey = apikey; this.endpoint = endpoint+"/1/api/%s/%s/v1"; @@ -30,7 +30,7 @@ parseArgs=function(arg1,arg2,arg3){ } -IODClient.prototype.call = function(handler,arg1,arg2,arg3) { +HODClient.prototype.call = function(handler,arg1,arg2,arg3) { var args= parseArgs(arg1,arg2,arg3) var data= args.data; var callback= args.callback; @@ -78,7 +78,7 @@ IODClient.prototype.call = function(handler,arg1,arg2,arg3) { }; -IODClient.prototype.createIndex=function(name,arg1,arg2,arg3){ +HODClient.prototype.createIndex=function(name,arg1,arg2,arg3){ var args= parseArgs(arg1,arg2,arg3) var data= args.data; var callback= args.callback; @@ -90,11 +90,11 @@ IODClient.prototype.createIndex=function(name,arg1,arg2,arg3){ return this.call('createtextindex',callback,data) } -IODClient.prototype.getIndex=function(name){ - return new IODIndex(this,name) +HODClient.prototype.getIndex=function(name){ + return new HODIndex(this,name) } -IODClient.prototype.deleteIndex=function(name,arg1,arg2,arg3){ +HODClient.prototype.deleteIndex=function(name,arg1,arg2,arg3){ var args= parseArgs(arg1,arg2,arg3) var data= args.data; var callback= args.callback; @@ -114,38 +114,38 @@ IODClient.prototype.deleteIndex=function(name,arg1,arg2,arg3){ } -function IODIndex(client,name){ +function HODIndex(client,name){ this.client=client; this.name=name; } -IODIndex.prototype.retrieveindexfields=function(callback){ +HODIndex.prototype.retrieveindexfields=function(callback){ data={'indexes':this.name} return this.client.call('retrieveindexfields',callback,data) } -IODIndex.prototype.status=function(callback){ +HODIndex.prototype.status=function(callback){ data={'indexes':this.name} return this.client.call('indexstatus',callback,data) } -IODIndex.prototype.delete=function(callback){ +HODIndex.prototype.delete=function(callback){ data={'indexes':this.name} return this.client.call('deletetextindex',callback,data) } -IODIndex.prototype.deletedocs=function(callback,data){ +HODIndex.prototype.deletedocs=function(callback,data){ data.indexes=this.name return this.client.call('deletetextindex',callback,data) } -IODIndex.prototype.create=function(callback,data){ +HODIndex.prototype.create=function(callback,data){ if (typeof data == "undefined") data={'flavor':'standard'} data.index=this.name return this.client.call('createtextindex',callback,data) } -IODIndex.prototype.adddocs=function(callback,docs,data){ +HODIndex.prototype.adddocs=function(callback,docs,data){ data.indexes=this.name docs={'document':docs} data.json=JSON.stringify(docs) @@ -153,37 +153,37 @@ IODIndex.prototype.adddocs=function(callback,docs,data){ } -function IODConnector(client,name){ +function HODConnector(client,name){ this.client=client; this.name=name; } -IODConnector.prototype.start=function(callback){ +HODConnector.prototype.start=function(callback){ data={'connector':this.name} return this.client.call('startconnector',callback,data) } -IODConnector.prototype.status=function(callback){ +HODConnector.prototype.status=function(callback){ data={'connector':this.name} return this.client.call('connectorstatus',callback,data) } -IODConnector.prototype.retrieveconfig=function(callback){ +HODConnector.prototype.retrieveconfig=function(callback){ data={'connector':this.name} return this.client.call('retrieveconfig',callback,data) } -IODConnector.prototype.updateconnector=function(callback,data){ +HODConnector.prototype.updateconnector=function(callback,data){ data.connector=this.name return this.client.call('updateconnector',callback,data) } -IODConnector.prototype.delete=function(callback){ +HODConnector.prototype.delete=function(callback){ data={'connector':this.name} return this.client.call('deleteconnector',callback,data) } // export the class -exports.IODClient=IODClient -exports.IODConnector=IODConnector -exports.IODIndex=IODIndex +exports.HODClient=HODClient +exports.HODConnector=HODConnector +exports.HODIndex=HODIndex diff --git a/package.json b/package.json index 5882113..1d2274f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "iod-node", + "name": "hod-node", "version": "0.1.2", - "description": "Idol OnDemand node client", + "description": "Haven OnDemand node client", "main": "index.js", "dependencies": { "needle": "^0.7.10" From c32d531361b141a30890a44a92a75ebbadfd6930 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 7 Oct 2015 20:33:15 -0400 Subject: [PATCH 07/40] changed package name and added contributors --- package.json | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 1d2274f..1d79414 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "hod-node", - "version": "0.1.2", - "description": "Haven OnDemand node client", + "name": "havenondemand", + "version": "1.0.0", + "description": "Official Haven OnDemand NodeJS client", "main": "index.js", "dependencies": { "needle": "^0.7.10" @@ -10,6 +10,10 @@ "scripts": { "test": "node test.js" }, - "author": "Martin Zerbib", + "author": "Haven OnDemand", + "contributors": [ + "Tyler Nappy ", + "Martin Zerbib" + ], "license": "MIT" } From 6bdcf623cb768a48874a40366edc94ceb2138a6d Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 7 Oct 2015 20:36:27 -0400 Subject: [PATCH 08/40] updated README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b15dffe..655f797 100644 --- a/README.md +++ b/README.md @@ -19,18 +19,18 @@ For a full list of all the APIs and to try them out, check out https://www.haven ### Installation To install, run the following command: ``` -npm install hod-node +npm install havenondemand ``` If you want to install the latest module directly from Github, use the following command: ``` -npm install git+https://github.com/HP-Haven-OnDemand/hod-node +npm install git+https://github.com/HP-Haven-OnDemand/havenondemand-node ``` ### Include it ```js -var hod = require('hod-node') -client = new hod.HODClient('http://api.havenondemand.com','apikey') +var hod = require('havenondemand') +client = new hod.HODClient('http://api.havenondemand.com', 'apikey') ``` ### Callbacks From 54ad22e93b5a198e290837c440576fad74954230 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Thu, 8 Oct 2015 09:09:52 -0400 Subject: [PATCH 09/40] changed url --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 655f797..dd3249f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Node JS client library for Haven OnDemand -Basic library to help with calling Haven OnDemand APIs [http://havenondemand.com](http://havenondemand.com). +Official client library to help with calling Haven OnDemand APIs [http://havenondemand.com](http://havenondemand.com). ## What is Haven OnDemand? Haven OnDemand is a set of over 70 APIs for handling all sorts of unstructured data. Here are just some of our APIs' capabilities: @@ -27,11 +27,12 @@ npm install git+https://github.com/HP-Haven-OnDemand/havenondemand-node ``` ### Include it - +*Note*: URL endpoint will change in the near future to `http://api.havenondemand.com` ```js var hod = require('havenondemand') -client = new hod.HODClient('http://api.havenondemand.com', 'apikey') +client = new hod.HODClient('http://api.idolondemand.com', 'API_KEY') ``` +You can find your API key [here](https://www.idolondemand.com/account/api-keys.html) after signing up. ### Callbacks From 332c3f6020726e3615a51d9a7edbcd253da94783 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Thu, 8 Oct 2015 09:11:59 -0400 Subject: [PATCH 10/40] updated verision number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1d79414..90f4a92 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "havenondemand", - "version": "1.0.0", + "version": "1.0.1", "description": "Official Haven OnDemand NodeJS client", "main": "index.js", "dependencies": { From b21a2d812cb59776279df5847123b068faae7f55 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Thu, 8 Oct 2015 09:17:03 -0400 Subject: [PATCH 11/40] updated note at top of README for versioning --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index dd3249f..9c06f6f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +**Note:** formerly known as `iod-node`. For the older version, see the `iod` branch. + # Node JS client library for Haven OnDemand Official client library to help with calling Haven OnDemand APIs [http://havenondemand.com](http://havenondemand.com). From 24738bbec15c87ae02fa3166ad75ed296fb434b3 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 9 Dec 2015 11:34:43 -0500 Subject: [PATCH 12/40] updated constructor - removed typing URL and added optional parameter for version --- lib/hodneedle.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index b8ec86e..ab661e1 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -2,10 +2,15 @@ var needle = require('needle') var util = require('util') var fs = require('fs') // Constructor -function HODClient(endpoint,apikey) { +function HODClient(apikey,version) { // always initialize all instance properties + if (apikey=='http://api.havenondemand.com' || apikey=='http://api.havenondemand.com/' || apikey=='https://api.havenondemand.com' || apikey=='https://api.havenondemand.com/') { + throw new Error("Using an outdated wrapper constructor method. No need to include API URL.\nInclude as such:\n client = new havenondemand.HODClient(API_KEY, VERSION)") + } + if (version==undefined) {this.version="v1";} + else {this.version=version;} this.apikey = apikey; - this.endpoint = endpoint+"/1/api/%s/%s/v1"; + this.endpoint = "http://api.havenondemand.com/1/api/%s/%s/"+this.version; } // class methods From 4bffa3c617912774df67d6bfc977d140eb263995 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 9 Dec 2015 11:36:26 -0500 Subject: [PATCH 13/40] changed to https --- lib/hodneedle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index ab661e1..986272d 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -10,7 +10,7 @@ function HODClient(apikey,version) { if (version==undefined) {this.version="v1";} else {this.version=version;} this.apikey = apikey; - this.endpoint = "http://api.havenondemand.com/1/api/%s/%s/"+this.version; + this.endpoint = "https://api.havenondemand.com/1/api/%s/%s/"+this.version; } // class methods From bcfe5bcc68785a1506cce30f31ede2031d373a2e Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 9 Dec 2015 11:42:14 -0500 Subject: [PATCH 14/40] updated README and version --- README.md | 6 +++--- package.json | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9c06f6f..cb5c9e4 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,13 @@ npm install git+https://github.com/HP-Haven-OnDemand/havenondemand-node ``` ### Include it -*Note*: URL endpoint will change in the near future to `http://api.havenondemand.com` ```js var hod = require('havenondemand') -client = new hod.HODClient('http://api.idolondemand.com', 'API_KEY') +client = new hod.HODClient(apikey, version) ``` -You can find your API key [here](https://www.idolondemand.com/account/api-keys.html) after signing up. +You can find your API key [here](https://www.haveondemand.com/account/api-keys.html) after signing up. +`version` is an optional parameter (defaults to `'v1'`) and can be either `'v1'` or `'v2'`. ### Callbacks ```js diff --git a/package.json b/package.json index 90f4a92..0645b94 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "havenondemand", - "version": "1.0.1", - "description": "Official Haven OnDemand NodeJS client", + "version": "1.1.0", + "description": "Official Haven OnDemand Node.js client", "main": "index.js", "dependencies": { "needle": "^0.7.10" From 6454071e78dd557a64d3e0b5350fcc965ff94497 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 8 Mar 2016 17:38:02 -0500 Subject: [PATCH 15/40] updated README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index cb5c9e4..0f17f3e 100644 --- a/README.md +++ b/README.md @@ -84,3 +84,12 @@ File posting is handled using the "file" parameter name which is used for all cu var data = {'file' : 'test.txt'} client.call('analyzesentiment', data, callback) ``` + +## Contributing +We encourage you to contribute to this repo! Please send pull requests with modified and updated code. + +1. Fork it ( https://github.com/HPE-Haven-OnDemand/havenondemand-node/fork ) +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create a new Pull Request From 814b5fc4a13279c439fa21c3b511b25b4f7338a9 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 22 Mar 2016 09:50:17 -0400 Subject: [PATCH 16/40] added LICENSE.txt --- LICENSE.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..636e03e --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2014 TODO: Write your name + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 06ba681be1f2a777dba51c3ce4ea35de8a8e0cde Mon Sep 17 00:00:00 2001 From: tylernappy Date: Thu, 7 Apr 2016 14:08:55 -0400 Subject: [PATCH 17/40] updated for staging --- lib/hodneedle.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index 986272d..2aac8b5 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -2,7 +2,7 @@ var needle = require('needle') var util = require('util') var fs = require('fs') // Constructor -function HODClient(apikey,version) { +function HODClient(apikey,version,staging) { // always initialize all instance properties if (apikey=='http://api.havenondemand.com' || apikey=='http://api.havenondemand.com/' || apikey=='https://api.havenondemand.com' || apikey=='https://api.havenondemand.com/') { throw new Error("Using an outdated wrapper constructor method. No need to include API URL.\nInclude as such:\n client = new havenondemand.HODClient(API_KEY, VERSION)") @@ -10,7 +10,11 @@ function HODClient(apikey,version) { if (version==undefined) {this.version="v1";} else {this.version=version;} this.apikey = apikey; - this.endpoint = "https://api.havenondemand.com/1/api/%s/%s/"+this.version; + if (staging==undefined || staging==false) { + this.endpoint = "https://api.havenondemand.com/1/api/%s/%s/"+this.version; + } else if (staging==true) { + this.endpoint = "https://api.staging.havenondemand.com/1/api/%s/%s/"+this.version; + } } // class methods From a89b7f56bbbdc86b075f9d996181470ffecc1143 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Thu, 7 Apr 2016 14:10:44 -0400 Subject: [PATCH 18/40] updated version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0645b94..304e9b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "havenondemand", - "version": "1.1.0", + "version": "1.1.1", "description": "Official Haven OnDemand Node.js client", "main": "index.js", "dependencies": { From 92c4c030d10aa999ec5996cca589e8db1daefadb Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 12 Apr 2016 16:51:54 -0400 Subject: [PATCH 19/40] added status and result API --- lib/hodneedle.js | 42 ++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index 2aac8b5..d14837a 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -15,6 +15,8 @@ function HODClient(apikey,version,staging) { } else if (staging==true) { this.endpoint = "https://api.staging.havenondemand.com/1/api/%s/%s/"+this.version; } + this.getJobResultEndpoint = "https://api.havenondemand.com/1/job/result/%s?apikey=%s" + this.getJobStatusEndpoint = "https://api.havenondemand.com/1/job/status/%s?apikey=%s" } // class methods @@ -38,6 +40,16 @@ parseArgs=function(arg1,arg2,arg3){ return {'data':data,'callback':callback,'async':async} } +parseArgsCheckStatusResult=function(arg1,arg2){ + var jobID,callback; + if (typeof arg1 == "function") {callback = arg1;} + else if (typeof arg1 == "string") {jobID = arg1;} + + if (typeof arg2 == "function") {callback = arg2;} + else if (typeof arg2 == "string") {jobID = arg2;} + + return {'jobID':jobID,'callback':callback}; +} HODClient.prototype.call = function(handler,arg1,arg2,arg3) { var args= parseArgs(arg1,arg2,arg3) @@ -86,6 +98,36 @@ HODClient.prototype.call = function(handler,arg1,arg2,arg3) { }; +HODClient.prototype.getJobResult = function(arg1,arg2) { + var args= parseArgsCheckStatusResult(arg1,arg2) + var jobID= args.jobID; + var callback= args.callback; + + var url = util.format(this.getJobResultEndpoint, jobID, this.apikey); + + if (typeof callback == "undefined") { + return needle.get(url); + } + else { + return needle.get(url, callback); + } +} + +HODClient.prototype.getJobStatus = function(arg1,arg2) { + var args= parseArgsCheckStatusResult(arg1,arg2) + var jobID= args.jobID; + var callback= args.callback; + + var url = util.format(this.getJobStatusEndpoint, jobID, this.apikey); + + if (typeof callback == "undefined") { + return needle.get(url); + } + else { + return needle.get(url, callback); + } +} + HODClient.prototype.createIndex=function(name,arg1,arg2,arg3){ var args= parseArgs(arg1,arg2,arg3) diff --git a/package.json b/package.json index 304e9b6..8d86272 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "havenondemand", - "version": "1.1.1", + "version": "1.1.2", "description": "Official Haven OnDemand Node.js client", "main": "index.js", "dependencies": { From 6ceae806291f24e59233e3158378c1d28fdb1931 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Thu, 28 Apr 2016 12:27:07 -0400 Subject: [PATCH 20/40] updated README --- README.md | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0f17f3e..f393b77 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Official client library to help with calling Haven OnDemand APIs [http://havenondemand.com](http://havenondemand.com). ## What is Haven OnDemand? -Haven OnDemand is a set of over 70 APIs for handling all sorts of unstructured data. Here are just some of our APIs' capabilities: +Haven OnDemand is a set of over 60 APIs for handling all sorts of unstructured data. Here are just some of our APIs' capabilities: * Speech to text * OCR * Text extraction @@ -70,10 +70,25 @@ client.call(data, callback, 'analyzesentiment') ### Async calls -While node will mostly deal with things asynchronously, Haven OnDemand offers server side asynchronous call method which should be used with large files and slow queries. Pass a boolean for the async parameter. - +While node will mostly deals with processes asynchronously, Haven OnDemand offers server side asynchronous call methods which should be used with large files and slow queries. Pass a boolean for the async parameter. The API response will return back a job ID which is used to check the status or result of your API request. +```js +var jobID +client.call('analyzesentiment', data, true, function(err, resp, body) { + jobID = resp.body.jobID + console.log(jobID) +}) +``` +**(Recommended method)** To check the status of your API call, use the following code with the jobID from obtained from the async call above. This will tell you if it's still processing or if it's complete, and if so, it will return the result. ```js -client.call('analyzesentiment', data, callback, true) +client.getJobStatus(jobID, function(err, resp, body) { + console.log(resp.body) +}) +``` +Or, to check the result of your API call, use the following code with the jobID obtained from the async call. *Note: This method may timeout if your async API call is still processing.* +```js +client.getJobResult(jobID, function(err, resp, body) { + console.log(resp.body) +}) ``` ### Posting files @@ -82,7 +97,9 @@ File posting is handled using the "file" parameter name which is used for all cu ```js var data = {'file' : 'test.txt'} -client.call('analyzesentiment', data, callback) +client.call('analyzesentiment', data, function(err, resp, body) { + console.log(resp.body) +}) ``` ## Contributing From 3d25653973c4dd4358cddf072ed6cb5083e3663f Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 3 May 2016 14:30:47 -0400 Subject: [PATCH 21/40] updated for proxies --- lib/hodneedle.js | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index d14837a..85ca334 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -2,7 +2,7 @@ var needle = require('needle') var util = require('util') var fs = require('fs') // Constructor -function HODClient(apikey,version,staging) { +function HODClient(apikey, version, proxy, staging) { // always initialize all instance properties if (apikey=='http://api.havenondemand.com' || apikey=='http://api.havenondemand.com/' || apikey=='https://api.havenondemand.com' || apikey=='https://api.havenondemand.com/') { throw new Error("Using an outdated wrapper constructor method. No need to include API URL.\nInclude as such:\n client = new havenondemand.HODClient(API_KEY, VERSION)") @@ -15,6 +15,7 @@ function HODClient(apikey,version,staging) { } else if (staging==true) { this.endpoint = "https://api.staging.havenondemand.com/1/api/%s/%s/"+this.version; } + this.proxy = proxy this.getJobResultEndpoint = "https://api.havenondemand.com/1/job/result/%s?apikey=%s" this.getJobStatusEndpoint = "https://api.havenondemand.com/1/job/status/%s?apikey=%s" } @@ -75,8 +76,11 @@ HODClient.prototype.call = function(handler,arg1,arg2,arg3) { //console.log(url) if (typeof callback == "undefined") { - - return needle.post(url, data, { multipart: true }); + if (this.proxy != undefined) { + return needle.post(url, data, { multipart: true, proxy: this.proxy }); + } else { + return needle.post(url, data, { multipart: true }); + } } else{ @@ -92,7 +96,11 @@ HODClient.prototype.call = function(handler,arg1,arg2,arg3) { else{ var callbackmanager= callback; } - needle.post(url, data, { multipart: true }, callbackmanager); + if (this.proxy != undefined) { + needle.post(url, data, { multipart: true, proxy: this.proxy }, callbackmanager); + } else { + needle.post(url, data, { multipart: true }, callbackmanager); + } } @@ -106,10 +114,18 @@ HODClient.prototype.getJobResult = function(arg1,arg2) { var url = util.format(this.getJobResultEndpoint, jobID, this.apikey); if (typeof callback == "undefined") { - return needle.get(url); + if (this.proxy != undefined) { + return needle.get(url, {proxy: this.proxy}); + } else { + return needle.get(url); + } } else { - return needle.get(url, callback); + if (this.proxy != undefined) { + return needle.get(url, {proxy: this.proxy}, callback); + } else { + return needle.get(url, callback); + } } } @@ -121,10 +137,18 @@ HODClient.prototype.getJobStatus = function(arg1,arg2) { var url = util.format(this.getJobStatusEndpoint, jobID, this.apikey); if (typeof callback == "undefined") { - return needle.get(url); + if (this.proxy != undefined) { + return needle.get(url, {proxy: this.proxy}); + } else { + return needle.get(url); + } } else { - return needle.get(url, callback); + if (this.proxy != undefined) { + return needle.get(url, {proxy: this.proxy}, callback); + } else { + return needle.get(url, callback); + } } } From 6d107dd87217217e6176acaaadcd811113d38357 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 3 May 2016 14:35:16 -0400 Subject: [PATCH 22/40] updated README and version --- README.md | 4 +++- package.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f393b77..faa7047 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,13 @@ npm install git+https://github.com/HP-Haven-OnDemand/havenondemand-node ### Include it ```js var hod = require('havenondemand') -client = new hod.HODClient(apikey, version) +client = new hod.HODClient(apikey, version, proxy) ``` You can find your API key [here](https://www.haveondemand.com/account/api-keys.html) after signing up. `version` is an optional parameter (defaults to `'v1'`) and can be either `'v1'` or `'v2'`. + +`proxy` is an optional parameter. Please set this if you're behind a firewall. ### Callbacks ```js diff --git a/package.json b/package.json index 8d86272..e1b6e37 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "havenondemand", - "version": "1.1.2", + "version": "1.1.3", "description": "Official Haven OnDemand Node.js client", "main": "index.js", "dependencies": { From 786230ced8a162082feb2c12de218074be11fe97 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 3 May 2016 14:46:36 -0400 Subject: [PATCH 23/40] updated README for proxy example --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index faa7047..f373727 100644 --- a/README.md +++ b/README.md @@ -30,14 +30,18 @@ npm install git+https://github.com/HP-Haven-OnDemand/havenondemand-node ### Include it ```js -var hod = require('havenondemand') -client = new hod.HODClient(apikey, version, proxy) +var havenondemand = require('havenondemand') +var client = new havenondemand.HODClient(apikey, version, proxy) ``` You can find your API key [here](https://www.haveondemand.com/account/api-keys.html) after signing up. `version` is an optional parameter (defaults to `'v1'`) and can be either `'v1'` or `'v2'`. -`proxy` is an optional parameter. Please set this if you're behind a firewall. +`proxy` is an optional parameter. Please set this if you're behind a firewall. Here is an example of iniating the client if you're using a proxy: +```js +var havenondemand = require('havenondemand') +var client = new havenondemand.HODClient('123456-asdf', 'v1', 'http://user:pass@proxy.server.com:3128') +``` ### Callbacks ```js From ea83be898570ba0fdfc4a624bf0814b3e95a61bd Mon Sep 17 00:00:00 2001 From: tylernappy Date: Fri, 20 May 2016 14:34:57 -0400 Subject: [PATCH 24/40] updated error handling --- lib/hodneedle.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index 85ca334..def0d70 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -89,12 +89,26 @@ HODClient.prototype.call = function(handler,arg1,arg2,arg3) { var callbackmanager=function(err,resp,body){ body={'async':true,'data':body}; body.status - - callback(err,resp,body); + var error; + if (resp.body.error) { + error = resp.body; + } else { + error = null; + } + callback(error, resp, body); } } else{ - var callbackmanager= callback; + // var callbackmanager= callback; + var callbackmanager = function(err, resp, body) { + var error; + if (resp.body.error) { + error = resp.body; + } else { + error = null; + } + callback(error, resp, body); + } } if (this.proxy != undefined) { needle.post(url, data, { multipart: true, proxy: this.proxy }, callbackmanager); From 1fdf79651dc1878531caaa6d87c15a66243ac1cf Mon Sep 17 00:00:00 2001 From: tylernappy Date: Fri, 20 May 2016 14:37:14 -0400 Subject: [PATCH 25/40] updated version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e1b6e37..e7d0486 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "havenondemand", - "version": "1.1.3", + "version": "1.2.0", "description": "Official Haven OnDemand Node.js client", "main": "index.js", "dependencies": { From 77362de8af93f02e9f352eecf1e1ad51a0d307e4 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Thu, 16 Jun 2016 14:45:53 -0400 Subject: [PATCH 26/40] added preliminary support for Job API --- lib/hodneedle.js | 74 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index def0d70..f24d3d8 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -15,9 +15,10 @@ function HODClient(apikey, version, proxy, staging) { } else if (staging==true) { this.endpoint = "https://api.staging.havenondemand.com/1/api/%s/%s/"+this.version; } - this.proxy = proxy - this.getJobResultEndpoint = "https://api.havenondemand.com/1/job/result/%s?apikey=%s" - this.getJobStatusEndpoint = "https://api.havenondemand.com/1/job/status/%s?apikey=%s" + this.proxy = proxy; + this.getJobResultEndpoint = "https://api.havenondemand.com/1/job/result/%s?apikey=%s"; + this.getJobStatusEndpoint = "https://api.havenondemand.com/1/job/status/%s?apikey=%s"; + this.jobAPIEndpoint = "https://api.havenondemand.com/1/job"; } // class methods @@ -52,6 +53,17 @@ parseArgsCheckStatusResult=function(arg1,arg2){ return {'jobID':jobID,'callback':callback}; } +parseArgsJobAPI=function(arg1, arg2) { + var data, callback; + if (typeof arg1 == "function") {callback = arg1;} + else if (typeof arg1 == "object") {data = arg1;} + + if (typeof arg2 == "function") {callback = arg2;} + else if (typeof arg2 == "object") {data = arg2;} + + return {'data': data, 'callback': callback} +} + HODClient.prototype.call = function(handler,arg1,arg2,arg3) { var args= parseArgs(arg1,arg2,arg3) var data= args.data; @@ -89,13 +101,7 @@ HODClient.prototype.call = function(handler,arg1,arg2,arg3) { var callbackmanager=function(err,resp,body){ body={'async':true,'data':body}; body.status - var error; - if (resp.body.error) { - error = resp.body; - } else { - error = null; - } - callback(error, resp, body); + } } else{ @@ -166,6 +172,54 @@ HODClient.prototype.getJobStatus = function(arg1,arg2) { } } +HODClient.prototype.batch=function(arg1, arg2) { // data is array + var data = {}; + var args = parseArgsJobAPI(arg1, arg2); + var parsedData = args.data; + var callback = args.callback; + var url = this.jobAPIEndpoint; + var apikey = this.apikey + + if (typeof parsedData =="undefined") { + data={}; + } else { + processData(parsedData, function(processedData) { //processedData is array + data.apikey= apikey; + data["job"] = processedData; + + //make call + var callback = callback; + var callbackmanager=function(err,resp,body){ + debugger + body={'async':true,'data':body}; + body.status + } + + if (this.proxy != undefined) { + needle.post(url, data, { multipart: true, proxy: this.proxy }, callbackmanager); + } else { + debugger + needle.post(url, data, { multipart: true }, callbackmanager); + } + //end make call + + + }) + } +} + +processData = function(params, callback) { + debugger + for (var i=0; i Date: Thu, 16 Jun 2016 17:13:55 -0400 Subject: [PATCH 27/40] added error handling for async batch job --- LICENSE.txt | 2 +- lib/hodneedle.js | 27 +++++++++++++++------------ package.json | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 636e03e..5c6593a 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2014 TODO: Write your name +Copyright (c) 2014 TODO: Tyler Nappy MIT License diff --git a/lib/hodneedle.js b/lib/hodneedle.js index f24d3d8..de7c6f7 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -99,9 +99,15 @@ HODClient.prototype.call = function(handler,arg1,arg2,arg3) { if (async){ var callback = callback; var callbackmanager=function(err,resp,body){ + var error; + if (resp.body.error) { + error = resp.body; + } else { + error = null; + } body={'async':true,'data':body}; body.status - + callback(error, resp, body); } } else{ @@ -172,7 +178,7 @@ HODClient.prototype.getJobStatus = function(arg1,arg2) { } } -HODClient.prototype.batch=function(arg1, arg2) { // data is array +HODClient.prototype.batchJob=function(arg1, arg2) { // data is array var data = {}; var args = parseArgsJobAPI(arg1, arg2); var parsedData = args.data; @@ -186,36 +192,33 @@ HODClient.prototype.batch=function(arg1, arg2) { // data is array processData(parsedData, function(processedData) { //processedData is array data.apikey= apikey; data["job"] = processedData; - - //make call - var callback = callback; var callbackmanager=function(err,resp,body){ - debugger + var error; + if (resp.body.error) { + error = resp.body; + } else { + error = null; + } body={'async':true,'data':body}; body.status + callback(error, resp, body); } if (this.proxy != undefined) { needle.post(url, data, { multipart: true, proxy: this.proxy }, callbackmanager); } else { - debugger needle.post(url, data, { multipart: true }, callbackmanager); } - //end make call - - }) } } processData = function(params, callback) { - debugger for (var i=0; i Date: Wed, 22 Jun 2016 17:08:51 -0400 Subject: [PATCH 28/40] added post and get requests --- lib/hodneedle.js | 147 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 148 insertions(+), 1 deletion(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index de7c6f7..ad09289 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -64,6 +64,153 @@ parseArgsJobAPI=function(arg1, arg2) { return {'data': data, 'callback': callback} } +HODClient.prototype.post = function(handler,arg1,arg2,arg3) { + var args= parseArgs(arg1,arg2,arg3) + var data= args.data; + var callback= args.callback; + var async=args.async; + if (typeof async =="undefined") async = false; + if (typeof data =="undefined") data={}; + + if (data["file"]){ + data["file"]={'file':data["file"],'content_type':'multipart/form-data'} + } +// console.log('incall',data) + async_string="sync"; + data.apikey=this.apikey; + + + if (async) { + async_string="async"; + } + + var url = util.format(this.endpoint,async_string,handler); + //console.log(url) + + if (typeof callback == "undefined") { + if (this.proxy != undefined) { + return needle.post(url, data, { multipart: true, proxy: this.proxy }); + } else { + return needle.post(url, data, { multipart: true }); + } + } + else{ + + if (async){ + var callback = callback; + var callbackmanager=function(err,resp,body){ + var error; + if (resp.body.error) { + error = resp.body; + } else { + error = null; + } + body={'async':true,'data':body}; + body.status + callback(error, resp, body); + } + } + else{ + // var callbackmanager= callback; + var callbackmanager = function(err, resp, body) { + var error; + if (resp.body.error) { + error = resp.body; + } else { + error = null; + } + callback(error, resp, body); + } + } + if (this.proxy != undefined) { + needle.post(url, data, { multipart: true, proxy: this.proxy }, callbackmanager); + } else { + needle.post(url, data, { multipart: true }, callbackmanager); + } + + } + +}; + +HODClient.prototype.get = function(handler,arg1,arg2,arg3) { + var args= parseArgs(arg1,arg2,arg3) + var data= args.data; + var callback= args.callback; + var async=args.async; + if (typeof async =="undefined") async = false; + if (typeof data =="undefined") data={}; + + if (data["file"]){ + throw new Error("Cannot perform GET with file. Use POST request.") + } + + async_string="sync"; + data.apikey=this.apikey; + + + if (async) { + async_string="async"; + } + + var url = constructGetUrl(this.endpoint, async_string, handler, data) + if (typeof callback == "undefined") { + if (this.proxy != undefined) { + return needle.get(url, { proxy: this.proxy }); + } else { + return needle.get(url); + } + } + else{ + if (async){ + var callback = callback; + var callbackmanager=function(err,resp,body){ + var error; + if (resp.body.error) { + error = resp.body; + } else { + error = null; + } + body={'async':true,'data':body}; + body.status + callback(error, resp, body); + } + } + else{ + // var callbackmanager= callback; + var callbackmanager = function(err, resp, body) { + var error; + if (resp.body.error) { + error = resp.body; + } else { + error = null; + } + callback(error, resp, body); + } + } + if (this.proxy != undefined) { + needle.get(url, { proxy: this.proxy }, callbackmanager); + } else { + debugger + needle.get(url, callbackmanager); + } + + } +}; + +constructGetUrl = function(endpoint, asyncString, apiHandler, apiData) { + var formatedUrl = util.format(endpoint, asyncString, apiHandler); + var counter = 0; + for (var key in apiData) { + counter += 1; + if (counter == 1) { + formatedUrl += "?" + key + "=" + apiData[key]; + } else { + formatedUrl += "&" + key + "=" + apiData[key]; + } + } + return encodeURI(formatedUrl); +} + HODClient.prototype.call = function(handler,arg1,arg2,arg3) { var args= parseArgs(arg1,arg2,arg3) var data= args.data; diff --git a/package.json b/package.json index 607314c..90446de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "havenondemand", - "version": "1.2.1", + "version": "1.2.2", "description": "Official Haven OnDemand Node.js client", "main": "index.js", "dependencies": { From b03bc0e1e983e5ca9ad528f157b0930b1f30d43b Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 22 Jun 2016 17:19:36 -0400 Subject: [PATCH 29/40] updated README for batch and get request --- README.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f373727..a0f8bfc 100644 --- a/README.md +++ b/README.md @@ -54,32 +54,41 @@ We can define our callbacks as functions and pass them as arguments ```js var data = {'text' : 'I like cats'} -client.call('analyzesentiment', callback, data) +client.post('analyzesentiment', callback, data) ``` Or, we can use the .on('data') hook to do the same thing. ```js -client.call('analyzesentiment',data).on('data',callback) +client.post('analyzesentiment',data).on('data',callback) ``` The order of the arguments after the API name doesn't matter when passed, so all of these are the equivalent. ```js //1 -client.call('analyzesentiment', data, callback) +client.post('analyzesentiment', data, callback) //2 -client.call(data, 'analyzesentiment', callback) +client.post(data, 'analyzesentiment', callback) //3 -client.call(data, callback, 'analyzesentiment') +client.post(data, callback, 'analyzesentiment') ``` +### GET request +APIs can also be accessed via a GET request. +```js +client.get('analyzesentiment', {'text': 'I love dogs'}, function(err, resp, body) { + if (!err) { + console.log(resp.body) + } +}) +``` ### Async calls While node will mostly deals with processes asynchronously, Haven OnDemand offers server side asynchronous call methods which should be used with large files and slow queries. Pass a boolean for the async parameter. The API response will return back a job ID which is used to check the status or result of your API request. ```js var jobID -client.call('analyzesentiment', data, true, function(err, resp, body) { +client.post('analyzesentiment', data, true, function(err, resp, body) { jobID = resp.body.jobID console.log(jobID) }) @@ -103,11 +112,46 @@ File posting is handled using the "file" parameter name which is used for all cu ```js var data = {'file' : 'test.txt'} -client.call('analyzesentiment', data, function(err, resp, body) { +client.post('analyzesentiment', data, function(err, resp, body) { + console.log(resp.body) +}) +``` + +### Batch jobs + +Haven OnDemand allows you to batch multiple API jobs in a single request using the Job API, for example, to analyze a batch of web pages, documents or social media messages where you need to analyze each text individually but want to be more efficient with your code, or where you want to execute multiple API calls on a single web page, document, or text. **Note: files are currently not supported in this wrapper for batch jobs.** + +```js +var jobID +var data = [ + { "name": "analyzesentiment", + "version": "v1", + "params": { + 'text': 'I love dogs' + } + }, + { "name": "extractconcepts", + "version": "v1", + "params": { + "url": "http://en.wikipedia.org/wiki/United_Kingdom" + } + } + ] +client.batchJob(data, function(err, resp, body) { + jobID = resp.body.jobID + console.log(jobID) +}) + +// +// check result of async request with Status API after some time +// + +client.getJobStatus(jobID, function(err, resp, body) { console.log(resp.body) }) ``` + ## Contributing We encourage you to contribute to this repo! Please send pull requests with modified and updated code. From 0e7a08fd2402d2baf1f334c8fedf4ff80a58b623 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Fri, 15 Jul 2016 12:08:42 -0400 Subject: [PATCH 30/40] updated error handling --- lib/hodneedle.js | 29 ++++++++++++++++++++++------- package.json | 2 +- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index ad09289..d5f57ee 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -100,7 +100,9 @@ HODClient.prototype.post = function(handler,arg1,arg2,arg3) { var callback = callback; var callbackmanager=function(err,resp,body){ var error; - if (resp.body.error) { + if (typeof(resp) == 'undefined') { + error = 'Problem getting result from Haven OnDemand. Please try aagain.'; + } else if (resp.body.error) { error = resp.body; } else { error = null; @@ -114,7 +116,10 @@ HODClient.prototype.post = function(handler,arg1,arg2,arg3) { // var callbackmanager= callback; var callbackmanager = function(err, resp, body) { var error; - if (resp.body.error) { + // + if (typeof(resp) == 'undefined') { + error = 'Problem getting result from Haven OnDemand. Please try aagain.' + } else if (resp.body.error) { error = resp.body; } else { error = null; @@ -165,7 +170,9 @@ HODClient.prototype.get = function(handler,arg1,arg2,arg3) { var callback = callback; var callbackmanager=function(err,resp,body){ var error; - if (resp.body.error) { + if (typeof(resp) == 'undefined') { + error = 'Problem getting result from Haven OnDemand. Please try aagain.'; + } else if (resp.body.error) { error = resp.body; } else { error = null; @@ -179,7 +186,9 @@ HODClient.prototype.get = function(handler,arg1,arg2,arg3) { // var callbackmanager= callback; var callbackmanager = function(err, resp, body) { var error; - if (resp.body.error) { + if (typeof(resp) == 'undefined') { + error = 'Problem getting result from Haven OnDemand. Please try aagain.'; + } else if (resp.body.error) { error = resp.body; } else { error = null; @@ -247,7 +256,9 @@ HODClient.prototype.call = function(handler,arg1,arg2,arg3) { var callback = callback; var callbackmanager=function(err,resp,body){ var error; - if (resp.body.error) { + if (typeof(resp) == 'undefined') { + error = 'Problem getting result from Haven OnDemand. Please try aagain.' + } else if (resp.body.error) { error = resp.body; } else { error = null; @@ -261,7 +272,9 @@ HODClient.prototype.call = function(handler,arg1,arg2,arg3) { // var callbackmanager= callback; var callbackmanager = function(err, resp, body) { var error; - if (resp.body.error) { + if (typeof(resp) == 'undefined') { + error = 'Problem getting result from Haven OnDemand. Please try aagain.' + } else if (resp.body.error) { error = resp.body; } else { error = null; @@ -341,7 +354,9 @@ HODClient.prototype.batchJob=function(arg1, arg2) { // data is array data["job"] = processedData; var callbackmanager=function(err,resp,body){ var error; - if (resp.body.error) { + if (typeof(resp) == 'undefined') { + error = 'Problem getting result from Haven OnDemand. Please try aagain.' + } else if (resp.body.error) { error = resp.body; } else { error = null; diff --git a/package.json b/package.json index 90446de..c89609e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "havenondemand", - "version": "1.2.2", + "version": "1.2.3", "description": "Official Haven OnDemand Node.js client", "main": "index.js", "dependencies": { From c519a410f8fb9420c8e5868a2ffa75eaee006500 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Tue, 25 Oct 2016 14:50:51 -0400 Subject: [PATCH 31/40] added POST request for combinations --- .gitignore | 1 + lib/hodneedle.js | 79 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index c2658d7..ef5ccfd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +**/.DS_Store diff --git a/lib/hodneedle.js b/lib/hodneedle.js index d5f57ee..bb039a3 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -13,7 +13,7 @@ function HODClient(apikey, version, proxy, staging) { if (staging==undefined || staging==false) { this.endpoint = "https://api.havenondemand.com/1/api/%s/%s/"+this.version; } else if (staging==true) { - this.endpoint = "https://api.staging.havenondemand.com/1/api/%s/%s/"+this.version; + this.endpoint = "https://api.staging.havenondemand.com/1/api/%s/%s/"+this.version; } this.proxy = proxy; this.getJobResultEndpoint = "https://api.havenondemand.com/1/job/result/%s?apikey=%s"; @@ -64,13 +64,79 @@ parseArgsJobAPI=function(arg1, arg2) { return {'data': data, 'callback': callback} } +HODClient.prototype.post_combination = function(combination,arg1,arg2,arg3) { + var args = parseArgs(arg1,arg2,arg3); + var data = args.data; + var callback = args.callback; + var async = args.async; + var handler = "executecombination" + if (typeof async == "undefined") async = false; + if (typeof data == "undefined") data = {}; + async_string = "sync"; + data.apikey = this.apikey; + data.combination = combination; + data.parameters = JSON.stringify(data.parameters) + + if (async) async_string="async"; + + var url = util.format(this.endpoint, async_string, handler); + + if (typeof callback == "undefined") { + if (this.proxy != undefined) { + return needle.post(url, data, { multipart: true, proxy: this.proxy }); + } else { + return needle.post(url, data, { multipart: true }); + } + } + else{ + + if (async){ + var callback = callback; + var callbackmanager=function(err,resp,body){ + var error; + if (typeof(resp) == 'undefined') { + error = 'Problem getting result from Haven OnDemand. Please try aagain.'; + } else if (resp.body.error) { + error = resp.body; + } else { + error = null; + } + body={'async':true,'data':body}; + body.status + callback(error, resp, body); + } + } + else{ + // var callbackmanager= callback; + var callbackmanager = function(err, resp, body) { + var error; + if (typeof(resp) == 'undefined') { + error = 'Problem getting result from Haven OnDemand. Please try aagain.' + } else if (resp.body.error) { + error = resp.body; + } else { + error = null; + } + callback(error, resp, body); + } + } + if (this.proxy != undefined) { + needle.post(url, data, { multipart: true, proxy: this.proxy }, callbackmanager); + } else { + needle.post(url, data, { multipart: true }, callbackmanager); + } + + } + +} + HODClient.prototype.post = function(handler,arg1,arg2,arg3) { - var args= parseArgs(arg1,arg2,arg3) - var data= args.data; - var callback= args.callback; + var args = parseArgs(arg1,arg2,arg3); + var data = args.data; + var callback = args.callback; var async=args.async; - if (typeof async =="undefined") async = false; - if (typeof data =="undefined") data={}; + if (typeof async == "undefined") async = false; + if (typeof data == "undefined") data = {}; if (data["file"]){ data["file"]={'file':data["file"],'content_type':'multipart/form-data'} @@ -199,7 +265,6 @@ HODClient.prototype.get = function(handler,arg1,arg2,arg3) { if (this.proxy != undefined) { needle.get(url, { proxy: this.proxy }, callbackmanager); } else { - debugger needle.get(url, callbackmanager); } From b5c1fc3c27f296eebeb23033c11a665351d40973 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 26 Oct 2016 12:55:35 -0400 Subject: [PATCH 32/40] updated README --- README.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a0f8bfc..f08e218 100644 --- a/README.md +++ b/README.md @@ -113,10 +113,33 @@ File posting is handled using the "file" parameter name which is used for all cu ```js var data = {'file' : 'test.txt'} client.post('analyzesentiment', data, function(err, resp, body) { - console.log(resp.body) + if (err) { + console.log(err) + } else { + console.log(resp.body) + } }) ``` +### Combinations + +Haven OnDemand allows to chain two ore more APIs together to create customizable, reusable services. These combinations enable one data input to have unlimited transformations and processing all from a single API call. + +```js +var data = { parameters: { name:"name_of_input", value: "value_of_input"} } +client.post_combination('name_of_combination', data, function(err, resp, body) { + if (err) { + console.log(err) + } else { + console.log(resp.body) + } +}) +``` + +**Note: using local files and publicly accessible URLs is not supported by this wrapper** + +To find out more about combinations and how to create one, see [here](https://dev.havenondemand.com/combination/home). + ### Batch jobs Haven OnDemand allows you to batch multiple API jobs in a single request using the Job API, for example, to analyze a batch of web pages, documents or social media messages where you need to analyze each text individually but want to be more efficient with your code, or where you want to execute multiple API calls on a single web page, document, or text. **Note: files are currently not supported in this wrapper for batch jobs.** From 89d544c2a42e62192285613d284037e851245831 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Wed, 26 Oct 2016 12:56:11 -0400 Subject: [PATCH 33/40] updated version to 1.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c89609e..e08d325 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "havenondemand", - "version": "1.2.3", + "version": "1.3.0", "description": "Official Haven OnDemand Node.js client", "main": "index.js", "dependencies": { From 4aa77002ad042abbbab2cbd6ee9bb2c5f653a8c5 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Thu, 3 Nov 2016 00:01:08 -0400 Subject: [PATCH 34/40] fixed get requests --- lib/hodneedle.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index bb039a3..c60e530 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -1,6 +1,7 @@ var needle = require('needle') var util = require('util') var fs = require('fs') +var querystring = require('querystring') // Constructor function HODClient(apikey, version, proxy, staging) { // always initialize all instance properties @@ -223,7 +224,7 @@ HODClient.prototype.get = function(handler,arg1,arg2,arg3) { async_string="async"; } - var url = constructGetUrl(this.endpoint, async_string, handler, data) + var url = util.format(this.endpoint, async_string,handler) + "?" + querystring.stringify(data) if (typeof callback == "undefined") { if (this.proxy != undefined) { return needle.get(url, { proxy: this.proxy }); From 4218b17eefff8c04ea63c41d7db4322065987d51 Mon Sep 17 00:00:00 2001 From: tylernappy Date: Thu, 3 Nov 2016 00:02:35 -0400 Subject: [PATCH 35/40] fixed get requests --- lib/hodneedle.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index c60e530..5d891ae 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -272,20 +272,6 @@ HODClient.prototype.get = function(handler,arg1,arg2,arg3) { } }; -constructGetUrl = function(endpoint, asyncString, apiHandler, apiData) { - var formatedUrl = util.format(endpoint, asyncString, apiHandler); - var counter = 0; - for (var key in apiData) { - counter += 1; - if (counter == 1) { - formatedUrl += "?" + key + "=" + apiData[key]; - } else { - formatedUrl += "&" + key + "=" + apiData[key]; - } - } - return encodeURI(formatedUrl); -} - HODClient.prototype.call = function(handler,arg1,arg2,arg3) { var args= parseArgs(arg1,arg2,arg3) var data= args.data; From 63a2c798bcbfcd0c2e1b5190615f1166e65de2c0 Mon Sep 17 00:00:00 2001 From: Paco Vu Date: Thu, 1 Dec 2016 16:55:00 -0800 Subject: [PATCH 36/40] Major changes - Modified needle lib to satisfy Haven OnDemand post request for combinations - Modified needle lib is included. No separate install needle required --- .gitignore | 1 - README.md | 70 +-- lib/hodneedle.js | 588 ++++++++++++------------- node_modules/.bin/needle | 1 + node_modules/needle/CHANGELOG.md | 12 + node_modules/needle/README.md | 439 ++++++++++++++++++ node_modules/needle/lib/auth.js | 87 ++++ node_modules/needle/lib/decoder.js | 52 +++ node_modules/needle/lib/multipart.js | 163 +++++++ node_modules/needle/lib/needle.js | 445 +++++++++++++++++++ node_modules/needle/lib/parsers.js | 73 +++ node_modules/needle/lib/querystring.js | 40 ++ node_modules/needle/package.json | 91 ++++ package.json | 6 +- 14 files changed, 1733 insertions(+), 335 deletions(-) create mode 120000 node_modules/.bin/needle create mode 100644 node_modules/needle/CHANGELOG.md create mode 100644 node_modules/needle/README.md create mode 100644 node_modules/needle/lib/auth.js create mode 100644 node_modules/needle/lib/decoder.js create mode 100644 node_modules/needle/lib/multipart.js create mode 100644 node_modules/needle/lib/needle.js create mode 100644 node_modules/needle/lib/parsers.js create mode 100644 node_modules/needle/lib/querystring.js create mode 100644 node_modules/needle/package.json diff --git a/.gitignore b/.gitignore index ef5ccfd..79b5594 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -node_modules/ **/.DS_Store diff --git a/README.md b/README.md index f08e218..9dd9cfe 100644 --- a/README.md +++ b/README.md @@ -42,41 +42,28 @@ You can find your API key [here](https://www.haveondemand.com/account/api-keys.h var havenondemand = require('havenondemand') var client = new havenondemand.HODClient('123456-asdf', 'v1', 'http://user:pass@proxy.server.com:3128') ``` -### Callbacks - +### Callback +We must define a callback function and pass it as an argument ```js var callback = function(err,resp,body){ console.log(body) } -``` - -We can define our callbacks as functions and pass them as arguments - -```js var data = {'text' : 'I like cats'} -client.post('analyzesentiment', callback, data) -``` -Or, we can use the .on('data') hook to do the same thing. - -```js -client.post('analyzesentiment',data).on('data',callback) +client.post('analyzesentiment', data, false, callback) ``` -The order of the arguments after the API name doesn't matter when passed, so all of these are the equivalent. - +The order of the arguments is strict. It must be in the following order: +method("api_name", {params}, async=[true|false], callback_method) ```js -//1 -client.post('analyzesentiment', data, callback) -//2 -client.post(data, 'analyzesentiment', callback) -//3 -client.post(data, callback, 'analyzesentiment') +var data = {'text' : 'I like cats'} +client.post('analyzesentiment', data, false, callback) ``` ### GET request -APIs can also be accessed via a GET request. +APIs can be accessed via a GET request. ```js -client.get('analyzesentiment', {'text': 'I love dogs'}, function(err, resp, body) { +var data = {'text' : 'I like cats'} +client.get('analyzesentiment', data, false, function(err, resp, body) { if (!err) { console.log(resp.body) } @@ -88,6 +75,7 @@ client.get('analyzesentiment', {'text': 'I love dogs'}, function(err, resp, body While node will mostly deals with processes asynchronously, Haven OnDemand offers server side asynchronous call methods which should be used with large files and slow queries. Pass a boolean for the async parameter. The API response will return back a job ID which is used to check the status or result of your API request. ```js var jobID +var data = {'text': 'I love dogs'} client.post('analyzesentiment', data, true, function(err, resp, body) { jobID = resp.body.jobID console.log(jobID) @@ -112,7 +100,7 @@ File posting is handled using the "file" parameter name which is used for all cu ```js var data = {'file' : 'test.txt'} -client.post('analyzesentiment', data, function(err, resp, body) { +client.post('analyzesentiment', data, false, function(err, resp, body) { if (err) { console.log(err) } else { @@ -125,9 +113,37 @@ client.post('analyzesentiment', data, function(err, resp, body) { Haven OnDemand allows to chain two ore more APIs together to create customizable, reusable services. These combinations enable one data input to have unlimited transformations and processing all from a single API call. +If you created a combination API name "sentimentanalysistoindex" which takes input as plain text. You can call the combination API from the code shown below: ```js -var data = { parameters: { name:"name_of_input", value: "value_of_input"} } -client.post_combination('name_of_combination', data, function(err, resp, body) { +var params = {text : "Haven OnDemand is awesome."}; +client.post_combination('sentimentanalysistoindex', params, false, function(err, resp, body) { + if (err) { + console.log(err) + } else { + console.log(resp.body) + } +}) +``` +If you created a combination API name "sentimentanalysistoindex" which takes JSON input and presumed that the name of your input is "jsoninput". And your combination API was defined to parse the jsonContent similar to the format below. You can call the combination API from the code as follows: +```js +var jsonContent = '{"arrayinput":[{"content":"Haven OnDemand is awesome."},{"content":"Sentiment Analysis API is very usefule."}]}' +var params = {} +params.jsoninput = jsonContent +client.get_combination('sentimentanalysistoindex', params, false, function(err, resp, body) { + if (err) { + console.log(err) + } else { + console.log(resp.body) + } +}) +``` +If you created a combination API name "sentimentanalysistoindex" which takes a file input and presumed that the name of your input is "textfile". And your combination API was defined to take also the language configuration. You can call the combination API from the code as follows: +```js +var files = [{"textfile":"path/document.txt"}] +var params = {} +params.file = files +params.language = "eng" +client.post_combination('sentimentanalysistoindex', params, false, function(err, resp, body) { if (err) { console.log(err) } else { @@ -135,8 +151,6 @@ client.post_combination('name_of_combination', data, function(err, resp, body) { } }) ``` - -**Note: using local files and publicly accessible URLs is not supported by this wrapper** To find out more about combinations and how to create one, see [here](https://dev.havenondemand.com/combination/home). diff --git a/lib/hodneedle.js b/lib/hodneedle.js index 5d891ae..c723462 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -2,6 +2,7 @@ var needle = require('needle') var util = require('util') var fs = require('fs') var querystring = require('querystring') + // Constructor function HODClient(apikey, version, proxy, staging) { // always initialize all instance properties @@ -25,71 +26,49 @@ function HODClient(apikey, version, proxy, staging) { needle.defaults({ timeout: 120000}); - -parseArgs=function(arg1,arg2,arg3){ - var data,callback,async; - if (typeof arg1 == "function") {callback = arg1;} - else if (typeof arg1 == "object") {data=arg1;} - else {async=arg1;} - - if (typeof arg2 == "function") {callback = arg2;} - else if (typeof arg2 =="object") {data=arg2;} - else {async=arg2;} - - if (typeof arg3 == "function") {callback = arg3;} - else if (typeof arg3 =="object") {data=arg3;} - else {async=arg3;} - - return {'data':data,'callback':callback,'async':async} -} - -parseArgsCheckStatusResult=function(arg1,arg2){ - var jobID,callback; - if (typeof arg1 == "function") {callback = arg1;} - else if (typeof arg1 == "string") {jobID = arg1;} - - if (typeof arg2 == "function") {callback = arg2;} - else if (typeof arg2 == "string") {jobID = arg2;} - - return {'jobID':jobID,'callback':callback}; +validadeParameters=function(hodApp,params,async,callback) { + if (typeof hodApp == "undefined") { + throw new Error("Missing hodApp parameter. Required valid API name") + } + if (typeof params == "undefined") { + throw new Error("Missing params parameter. Required API's input and configuration parameters") + } + if (typeof async == "undefined") { + throw new Error("Missing async parameter. Required true or false") + }else if (typeof async == "function"){ + if (typeof callback == "undefined") { + throw new Error("Missing async parameter. Required true or false") + }else{ + throw new Error("Wrong parameters order. Required (hodApp,params,async,callback)") + } + } + if (typeof callback == "undefined") { + throw new Error("Missing callback parameter. Required callback function") + }else if (typeof callback != "function"){ + throw new Error("Wrong callback parameter. Required callback function") + } } - -parseArgsJobAPI=function(arg1, arg2) { - var data, callback; - if (typeof arg1 == "function") {callback = arg1;} - else if (typeof arg1 == "object") {data = arg1;} - - if (typeof arg2 == "function") {callback = arg2;} - else if (typeof arg2 == "object") {data = arg2;} - - return {'data': data, 'callback': callback} +isJSON=function(value) { + var ret = true + try { + JSON.parse(value); + } catch (e) { + ret = false + } + return ret } - -HODClient.prototype.post_combination = function(combination,arg1,arg2,arg3) { - var args = parseArgs(arg1,arg2,arg3); - var data = args.data; - var callback = args.callback; - var async = args.async; - var handler = "executecombination" - if (typeof async == "undefined") async = false; - if (typeof data == "undefined") data = {}; +HODClient.prototype.post_combination = function(hodApp,params,async,callback) { + var data = {} + validadeParameters(hodApp,params,async,callback) async_string = "sync"; data.apikey = this.apikey; - data.combination = combination; - data.parameters = JSON.stringify(data.parameters) + data.combination = hodApp; + for(var item in params){ + data[item] = params[item] + } if (async) async_string="async"; - - var url = util.format(this.endpoint, async_string, handler); - - if (typeof callback == "undefined") { - if (this.proxy != undefined) { - return needle.post(url, data, { multipart: true, proxy: this.proxy }); - } else { - return needle.post(url, data, { multipart: true }); - } - } - else{ + var url = util.format(this.endpoint, async_string, "executecombination"); if (async){ var callback = callback; @@ -108,7 +87,6 @@ HODClient.prototype.post_combination = function(combination,arg1,arg2,arg3) { } } else{ - // var callbackmanager= callback; var callbackmanager = function(err, resp, body) { var error; if (typeof(resp) == 'undefined') { @@ -122,46 +100,58 @@ HODClient.prototype.post_combination = function(combination,arg1,arg2,arg3) { } } if (this.proxy != undefined) { - needle.post(url, data, { multipart: true, proxy: this.proxy }, callbackmanager); + needle.post(url, data, { combination:true, multipart: true, proxy: this.proxy }, callbackmanager); } else { - needle.post(url, data, { multipart: true }, callbackmanager); + needle.post(url, data, { combination:true, multipart: true }, callbackmanager); } - - } - } +HODClient.prototype.post_combination_S = function(hodApp,params,async,callback) { + var data = {} + validadeParameters(hodApp,params,async,callback) + async_string = "sync"; + data.apikey = this.apikey; + data.combination = hodApp; + + for(var item in params){ + if (item == 'file'){ + var files = params[item] + var count = files.length + for(var i=0; i Api changes between v0.6 and v0.7 +--------------------------------------------------- + +In version 0.7 a lot of work was done on the Needle internals to make streams a first class citizen. Needle can now be used as a streams2-compatible stream and you gain a lot of performance improvements come with it. + +While great care was taken not to introduce any breaking changes, there are probably a few edge cases in which Needle's behaviour has changed, specifically: + + * Needle now emits a strict streams2-compatible stream. This means that if your code relied on the Needle stream to always be in flowing mode, your code will likely need an update. For more information about this new Stream behavior, please refer to [the Node.JS blog](http://blog.nodejs.org/2012/12/20/streams2/). + + * In the v0.6 release, Needle's stream didn't parse, uncompress or did anything to the body content: everything chunk of data that was emitted on the stream was the raw body. In the 0.7 release every chunk of data will be a fully processed chunk, including uncompression, character recoding and parsing (in case of XML/JSON). + +If you use the regular callback interface of Needle, this will be a backwards-compatible upgrade. diff --git a/node_modules/needle/README.md b/node_modules/needle/README.md new file mode 100644 index 0000000..84e1151 --- /dev/null +++ b/node_modules/needle/README.md @@ -0,0 +1,439 @@ +Needle +====== +This is a modified version for HPE Haven OnDemand. + +[![NPM](https://nodei.co/npm/needle.png)](https://nodei.co/npm/needle/) + +The leanest and most handsome HTTP client in the Nodelands. + +```js +var needle = require('needle'); + +needle.get('http://www.google.com', function(error, response) { + if (!error && response.statusCode == 200) + console.log(response.body); +}); +``` + +Callbacks not floating your boat? Needle got your back. + +```js +var data = { + file: '/home/johnlennon/walrus.png', + content_type: 'image/png' +}; + +needle + .post('https://my.server.com/foo', data, { multipart: true }) + .on('readable', function() { /* eat your chunks */ }) + .on('end', function() { + console.log('Ready-o, friend-o.'); + }) +``` + +With only one single dependency, Needle supports: + + - HTTP/HTTPS requests, with the usual verbs you would expect. + - All of Node's native TLS options, such as 'rejectUnauthorized' (see below). + - Basic & Digest authentication + - Multipart form-data (e.g. file uploads) + - HTTP Proxy forwarding, optionally with authentication. + - Streaming gzip or deflate decompression + - Automatic XML & JSON parsing + - 301/302 redirect following, if enabled, and + - Streaming non-UTF-8 charset decoding, via `iconv-lite`. + +And yes, Mr. Wayne, it does come with the latest streams2 support. + +This makes Needle an ideal alternative for performing quick HTTP requests in Node, either for API interaction, downloading or uploading streams of data, and so on. If you need OAuth, AWS support or anything fancier, you should check out mikeal's request module. + +Important +--------- + +The version bump from 0.6 to 0.7 includes a few notable changes to the streaming interface. If you were using Needle in 'steams mode', please take a look at the [changelog](https://github.com/tomas/needle/blob/master/CHANGELOG.md) to see what's going on. If you were using regular callbacks, no problemo amigo -- you can update to 0.7+ and everything will be smooth as silk. + +Install +------- + +``` +$ npm install needle +``` + +Usage +----- + +```js +// using callback +needle.get('ifconfig.me/all.json', function(error, response) { + if (!error) + console.log(response.body.ip_addr); // JSON decoding magic. :) +}); + +// using streams +var out = fs.createWriteStream('logo.png'); +needle.get('https://google.com/images/logo.png').pipe(out); +``` + +As you can see, you can call Needle with a callback or without it. When passed, the response body will be buffered and written to `response.body`, and the callback will be fired when all of the data has been collected and processed (e.g. decompressed, decoded and/or parsed). + +When no callback is passed, the buffering logic will be skipped but the response stream will still go through Needle's processing pipeline, so you get all the benefits of post-processing while keeping the streamishness we all love from Node. + +Response pipeline +----------------- + +Depending on the response's Content-Type, Needle will either attempt to parse JSON or XML streams, or, if a text response was received, will ensure that the final encoding you get is UTF-8. For XML decoding to work, though, you'll need to install the `xml2js` package as we don't enforce unneeded dependencies unless strictly needed. + +You can also request a gzip/deflated response, which, if sent by the server, will be processed before parsing or decoding is performed. + +```js +needle.get('http://stackoverflow.com/feeds', { compressed: true }, function(err, resp) { + console.log(resp.body); // this little guy won't be a Gzipped binary blob + // but a nice object containing all the latest entries +}); +``` + +Or in anti-callback mode, using a few other options: + +```js +var options = { + compressed : true, + follow : true, + rejectUnauthorized : true +} + +// in this case, we'll ask Needle to follow redirects (disabled by default), +// but also to verify their SSL certificates when connecting. +var stream = needle.get('https://backend.server.com/everything.html', options); + +stream.on('readable', function() { + while (data = this.read()) { + console.log(data.toString()); + } +}) +``` + +API +--- + +All of Needle's request methods return a Readable stream, and both `options` and `callback` are optional. If passed, the callback will return three arguments: `error`, `response` and `body`, which is basically an alias for `response.body`. + +### needle.head(url, options, callback) + +```js +var options = { + timeout: 5000 // if we don't get a response in 5 seconds, boom. +} + +needle.head('https://my.backend.server.com', function(err, resp) { + if (err) + console.log('Shoot! Something is wrong: ' + err.message) + else + console.log('Yup, still alive.') +}) +``` + +### needle.get(url, options, callback) + +```js +needle.get('google.com/search?q=syd+barrett', function(err, resp) { + // if no http:// is found, Needle will automagically prepend it. +}); +``` + +### needle.post(url, data, options, callback) + +```js +var options = { + headers: { 'X-Custom-Header': 'Bumbaway atuna' } +} + +needle.post('https://my.app.com/endpoint', 'foo=bar', options, function(err, resp) { + // you can pass params as a string or as an object. +}); +``` + +### needle.put(url, data, options, callback) + +```js +var nested = { + params: { + are: { + also: 'supported' + } + } +} + +needle.put('https://api.app.com/v2', nested, function(err, resp) { + console.log('Got ' + resp.bytes + ' bytes.') // another nice treat from this handsome fella. +}); +``` + +### needle.delete(url, data, options, callback) + +```js +var options = { + username: 'fidelio', + password: 'x' +} + +needle.delete('https://api.app.com/messages/123', null, options, function(err, resp) { + // in this case, data may be null, but you need to explicity pass it. +}); +``` + +### needle.request(method, url, data, options, callback) + +Generic request. This not only allows for flexibility, but also lets you perform a GET request with data, in which case will be appended to the request as a query string. + +```js +var data = { + q : 'a very smart query', + page : 2, + format : 'json' +} + +needle.request('get', 'forum.com/search', data, function(err, resp) { + if (!err && resp.statusCode == 200) + console.log(resp.body); // here you go, mister. +}); +``` + +More examples after this short break. + +Request options +--------------- + + - `timeout` : Returns error if no response received in X milisecs. Defaults to `10000` (10 secs). `0` means no timeout. + - `follow` : Number of redirects to follow. `false` means don't follow any (default), `true` means 10. + - `multipart` : Enables multipart/form-data encoding. Defaults to `false`. Use it when uploading files. + - `proxy` : Forwards request through HTTP(s) proxy. Eg. `proxy: 'http://proxy.server.com:3128'` + - `agent` : Uses an http.Agent of your choice, instead of the global, default one. + - `headers` : Object containing custom HTTP headers for request. Overrides defaults described below. + - `auth` : Determines what to do with provided username/password. Options are `auto`, `digest` or `basic` (default). `auto` will detect the type of authentication depending on the response headers. + - `json` : When `true`, sets content type to `application/json` and sends request body as JSON string, instead of a query string. + +Response options +---------------- + + - `decode` : Whether to decode the text responses to UTF-8, if Content-Type header shows a different charset. Defaults to `true`. + - `parse` : Whether to parse XML or JSON response bodies automagically. Defaults to `true`. + - `output` : Dump response output to file. This occurs after parsing and charset decoding is done. + +Note: To stay light on dependencies, Needle doesn't include the `xml2js` module used for XML parsing. To enable it, simply do `npm install xml2js`. + +HTTP Header options +------------------- + +These are basically shortcuts to the `headers` option described above. + + - `compressed`: If `true`, sets 'Accept-Encoding' header to 'gzip,deflate', and inflates content if zipped. Defaults to `false`. + - `username` : For HTTP basic auth. + - `password` : For HTTP basic auth. Requires username to be passed, but is optional. + - `accept` : Sets 'Accept' HTTP header. Defaults to `*/*`. + - `connection`: Sets 'Connection' HTTP header. Defaults to `close`. + - `user_agent`: Sets the 'User-Agent' HTTP header. Defaults to `Needle/{version} (Node.js {node_version})`. + +Node.js TLS Options +------------------- + +These options are passed directly to `https.request` if present. Taken from the [original documentation](http://nodejs.org/docs/latest/api/https.html): + + - `pfx`: Certificate, Private key and CA certificates to use for SSL. + - `key`: Private key to use for SSL. + - `passphrase`: A string of passphrase for the private key or pfx. + - `cert`: Public x509 certificate to use. + - `ca`: An authority certificate or array of authority certificates to check the remote host against. + - `ciphers`: A string describing the ciphers to use or exclude. + - `rejectUnauthorized`: If true, the server certificate is verified against the list of supplied CAs. An 'error' event is emitted if verification fails. Verification happens at the connection level, before the HTTP request is sent. + - `secureProtocol`: The SSL method to use, e.g. SSLv3_method to force SSL version 3. + +Overriding Defaults +------------------- + +Yes sir, we have it. Needle includes a `defaults()` method, that lets you override some of the defaults for all future requests. Like this: + +```js +needle.defaults({ timeout: 60000, user_agent: 'MyApp/1.2.3' }); +``` + +This will override Needle's default user agent and 10-second timeout, so you don't need to pass those options in every other request. + +Examples Galore +--------------- + +### HTTPS GET with Basic Auth + +```js +needle.get('https://api.server.com', { username: 'you', password: 'secret' }, + function(err, resp) { + // used HTTP auth +}); +``` + +Or use [RFC-1738](http://tools.ietf.org/html/rfc1738#section-3.1) basic auth URL syntax: + +```js +needle.get('https://username:password@api.server.com', function(err, resp) { + // used HTTP auth from URL +}); +``` + +### Digest Auth + +```js +needle.get('other.server.com', { username: 'you', password: 'secret', auth: 'digest' }, + function(err, resp, body) { + // needle prepends 'http://' to your URL, if missing +}); +``` + +### Custom Accept header, deflate + +```js +var options = { + compressed : true, + follow : true, + accept : 'application/vnd.github.full+json' +} + +needle.get('api.github.com/users/tomas', options, function(err, resp, body) { + // body will contain a JSON.parse(d) object + // if parsing fails, you'll simply get the original body +}); +``` + +### GET XML object + +```js +needle.get('https://news.ycombinator.com/rss', function(err, resp, body) { + // if xml2js is installed, you'll get a nice object containing the nodes in the RSS +}); +``` + +### GET binary, output to file + +```js +needle.get('http://upload.server.com/tux.png', { output: '/tmp/tux.png' }, function(err, resp, body) { + // you can dump any response to a file, not only binaries. +}); +``` + +### GET through proxy + +```js +needle.get('http://search.npmjs.org', { proxy: 'http://localhost:1234' }, function(err, resp, body) { + // request passed through proxy +}); +``` + +### GET a very large document in a stream (from 0.7+) + +```js +var stream = needle.get('http://www.as35662.net/100.log'); + +stream.on('readable', function() { + var chunk; + while (chunk = this.read()) { + console.log('got data: ', chunk); + } +}); +``` + +### GET JSON object in a stream (from 0.7+) + +```js +var stream = needle.get('http://jsonplaceholder.typicode.com/db', { parse: true }); + +stream.on('readable', function() { + var node; + + // our stream will only emit a single JSON root node. + while (node = this.read()) { + console.log('got data: ', node); + } +}); +``` + +### GET JSONStream flexible parser with search query (from 0.7+) + +```js + + // The 'data' element of this stream will be the string representation + // of the titles of all posts. + +needle.get('http://jsonplaceholder.typicode.com/db', { parse: true }) + .pipe(new JSONStream.parse('posts.*.title')); + .on('data', function (obj) { + console.log('got post title: %s', obj); + }); +``` + +### File upload using multipart, passing file path + +```js +var data = { + foo: 'bar', + image: { file: '/home/tomas/linux.png', content_type: 'image/png' } +} + +needle.post('http://my.other.app.com', data, { multipart: true }, function(err, resp, body) { + // needle will read the file and include it in the form-data as binary +}); +``` + +### Stream upload, PUT or POST + +``` js +needle.put('https://api.app.com/v2', fs.createReadStream('myfile.txt'), function(err, resp, body) { + // stream content is uploaded verbatim +}); +``` + +### Multipart POST, passing data buffer + +```js +var buffer = fs.readFileSync('/path/to/package.zip'); + +var data = { + zip_file: { + buffer : buffer, + filename : 'mypackage.zip', + content_type : 'application/octet-stream' + } +} + +needle.post('http://somewhere.com/over/the/rainbow', data, { multipart: true }, function(err, resp, body) { + // if you see, when using buffers we need to pass the filename for the multipart body. + // you can also pass a filename when using the file path method, in case you want to override + // the default filename to be received on the other end. +}); +``` + +### Multipart with custom Content-Type + +```js +var data = { + token: 'verysecret', + payload: { + value: JSON.stringify({ title: 'test', version: 1 }), + content_type: 'application/json' + } +} + +needle.post('http://test.com/', data, { timeout: 5000, multipart: true }, function(err, resp, body) { + // in this case, if the request takes more than 5 seconds + // the callback will return a [Socket closed] error +}); +``` + +For even more examples, check out the examples directory in the repo. + +Credits +------- + +Written by Tomás Pollak, with the help of contributors. + +Copyright +--------- + +(c) 2014 Fork Ltd. Licensed under the MIT license. diff --git a/node_modules/needle/lib/auth.js b/node_modules/needle/lib/auth.js new file mode 100644 index 0000000..0f4b7bb --- /dev/null +++ b/node_modules/needle/lib/auth.js @@ -0,0 +1,87 @@ +var createHash = require('crypto').createHash; + +var md5 = function(string) { + return createHash('md5').update(string).digest('hex'); +} + +var basic = function(user, pass) { + var str = typeof pass == 'undefined' ? user : [user, pass].join(':'); + return 'Basic ' + new Buffer(str).toString('base64'); +} + +// digest logic inspired from https://github.com/simme/node-http-digest-client +var digest = {}; + +digest.parse_header = function(header) { + var challenge = {}, + matches = header.match(/([a-z0-9_-]+)="([^"]+)"/gi); + + for (var i = 0, l = matches.length; i < l; i++) { + var pos = matches[i].indexOf('='), + key = matches[i].substring(0, pos), + val = matches[i].substring(pos + 1); + challenge[key] = val.substring(1, val.length - 1); + } + + return challenge; +} + +digest.update_nc = function(nc) { + var max = 99999999; + nc++; + + if (nc > max) + nc = 1; + + var padding = new Array(8).join('0') + ''; + nc = nc + ''; + return padding.substr(0, 8 - nc.length) + nc; +} + +digest.generate = function(header, user, pass, method, path) { + + var nc = 1, + cnonce = null, + challenge = digest.parse_header(header); + + var ha1 = md5(user + ':' + challenge.realm + ':' + pass), + ha2 = md5(method + ':' + path), + resp = [ha1, challenge.nonce]; + + if (typeof challenge.qop === 'string') { + cnonce = md5(Math.random().toString(36)).substr(0, 8); + nc = digest.update_nc(nc); + resp = resp.concat(nc, cnonce); + } + + resp = resp.concat(challenge.qop, ha2); + + var params = { + username: user, + realm: challenge.realm, + nonce: challenge.nonce, + uri: path, + qop: challenge.qop, + response: md5(resp.join(':')) + } + +// if (challenge.opaque) { +// params.opaque = challenge.opaque; +// } + + if (cnonce) { + params.nc = nc; + params.cnonce = cnonce; + } + + header = [] + for (var k in params) + header.push(k + '="' + params[k] + '"') + + return 'Digest ' + header.join(', '); +} + +module.exports = { + basic: basic, + digest: digest.generate +} diff --git a/node_modules/needle/lib/decoder.js b/node_modules/needle/lib/decoder.js new file mode 100644 index 0000000..c63a56d --- /dev/null +++ b/node_modules/needle/lib/decoder.js @@ -0,0 +1,52 @@ +var iconv, + inherits = require('util').inherits, + stream = require('stream'); + +var charsetReg = /(?:charset|encoding)\s*=\s*['"]? *([\w\-]+)/i; + +inherits(StreamDecoder, stream.Transform); + +function StreamDecoder(charset) { + if (!(this instanceof StreamDecoder)) + return new StreamDecoder(charset); + + stream.Transform.call(this, charset); + this.charset = charset; + this.parsedFromChunk = false; +} + +StreamDecoder.prototype._transform = function(chunk, encoding, done) { + var res; + + // try get charset from chunk, just once + if (this.charset == 'iso-8859-1' && !this.parsedFromChunk) { + this.parsedFromChunk = true; + var matchs = charsetReg.exec(chunk.toString()); + if (matchs) { + var cs = matchs[1].toLowerCase(); + this.charset = cs == 'utf-8' ? 'utf8' : cs; + } + } + + try { + res = iconv.decode(chunk, this.charset); + } catch(e) { // something went wrong, just return original chunk + res = chunk; + } + + this.push(res); + done(); +} + +module.exports = function(charset) { + try { + if (!iconv) iconv = require('iconv-lite'); + } catch(e) { + /* iconv not found */ + } + + if (iconv) + return new StreamDecoder(charset); + else + return new stream.PassThrough; +} diff --git a/node_modules/needle/lib/multipart.js b/node_modules/needle/lib/multipart.js new file mode 100644 index 0000000..32fa1b6 --- /dev/null +++ b/node_modules/needle/lib/multipart.js @@ -0,0 +1,163 @@ +var readFile = require('fs').readFile, + basename = require('path').basename; +var util = require('util') + +isJSON=function(value) { + var ret = true + try { + JSON.parse(value); + } catch (e) { + ret = false + } + return ret +} +exports.build_combination = function(data, boundary, callback) { + if (typeof data != 'object') + return callback(new Error('Multipart builder expects data as key/val object.')); + + var body = '', + count = Object.keys(data).length; + if (count === 0) + return callback(new Error('Empty multipart body. Invalid data.')) + + var done = function(err, section) { + if (err) return callback(err); + if (section) body += section; + --count || callback(null, body + '--' + boundary + '--'); + }; + + var extra = function(err, section) { + if (err) return callback(err); + if (section) + body += section; + }; + + for (var key in data) { + var value = data[key]; + if (value === null || typeof value == 'undefined') { + done(); + }else { + if (key == 'apikey' || key == 'combination'){ + var part = (value.buffer || value.file || value.content_type) ? value : {value: value}; + generate_part(key, part, boundary, done); + }else if (key == 'file'){ + var len = value.length + for(var i=0; i +// (c) 2012-2013 - Fork Ltd. +// MIT Licensed +////////////////////////////////////////// + +var fs = require('fs'), + http = require('http'), + https = require('https'), + url = require('url'), + stream = require('stream'), + stringify = require('./querystring').build, + multipart = require('./multipart'), + auth = require('./auth'), + parsers = require('./parsers'), + decoder = require('./decoder'); + +////////////////////////////////////////// +// variabilia +////////////////////////////////////////// + +var version = JSON.parse(fs.readFileSync(__dirname + '/../package.json').toString()).version, + debugging = !!process.env.DEBUG, + debug = debugging ? console.log : function() { /* noop */ }; + +var user_agent = 'Needle/' + version; +user_agent += ' (Node.js ' + process.version + '; ' + process.platform + ' ' + process.arch + ')'; + +var node_tls_opts = 'agent pfx key passphrase cert ca ciphers rejectUnauthorized secureProtocol'; + +////////////////////////////////////////// +// decompressors for gzip/deflate bodies +////////////////////////////////////////// + +var decompressors = {}; + +try { + + var zlib = require('zlib') + + decompressors['x-deflate'] = zlib.Inflate; + decompressors['deflate'] = zlib.Inflate; + decompressors['x-gzip'] = zlib.Gunzip; + decompressors['gzip'] = zlib.Gunzip; + +} catch(e) { /* zlib not available */ } + +////////////////////////////////////////// +// defaults +////////////////////////////////////////// + +var defaults = { + accept : '*/*', + connection : 'close', + user_agent : user_agent, + follow : 0, + decode_response : true, + parse_response : true, + compressed : false, + timeout : 10000, + encoding : 'utf8', + boundary : '--------------------NODENEEDLEHTTPCLIENT' +} + +////////////////////////////////////////// +// the main act +////////////////////////////////////////// + +var Needle = { + request: function(method, uri, data, options, callback) { + var self = this, + out = new stream.PassThrough({ objectMode: false }), + callback = (typeof options == 'function') ? options : callback, + options = options || {}; + + // uri checks and parsing + if (typeof uri !== 'string') + throw new TypeError('URL must be a string, not ' + uri); + + // if no 'http' is found on URL, prepend it. + if (uri.indexOf('http') === -1) + uri = 'http://' + uri; + + // if url contains user:pass@host, parse it. + if (uri.indexOf('@') !== -1) { + var parts = (url.parse(uri).auth || '').split(':'); + options.username = parts[0]; + options.password = parts[1]; + } + + var config = { + base_opts : {}, + proxy : options.proxy, + output : options.output, + encoding : options.encoding || (options.multipart ? 'binary' : defaults.encoding), + decode_response : options.decode === false ? false : defaults.decode_response, + parse_response : options.parse === false ? false : defaults.parse_response, + follow : options.follow === true ? 10 : typeof options.follow == 'number' ? options.follow : defaults.follow, + timeout : (typeof options.timeout == 'number') ? options.timeout : defaults.timeout + } + + // if any of node's TLS options are passed, let them be passed to https.request() + node_tls_opts.split(' ').forEach(function(key) { + if (typeof options[key] != 'undefined') { + config.base_opts[key] = options[key]; + if (typeof options.agent == 'undefined') + config.base_opts.agent = false; // otherwise tls options are skipped + } + }); + + config.headers = { + 'Accept' : options.accept || defaults.accept, + 'Connection' : options.connection || defaults.connection, + 'User-Agent' : options.user_agent || defaults.user_agent + } + + if ((options.compressed || defaults.compressed) && typeof zlib != 'undefined') + config.headers['Accept-Encoding'] = 'gzip,deflate'; + + for (var h in options.headers) + config.headers[h] = options.headers[h]; + + if (options.username) { + if (options.auth && (options.auth == 'auto' || options.auth == 'digest')) { + config.credentials = [options.username, options.password]; + } else { + var auth_header = options.proxy ? 'Proxy-Authorization' : 'Authorization'; + config.headers[auth_header] = auth.basic(options.username, options.password); + } + } + + if (data) { + if (method.toUpperCase() == 'GET') { // build query string and append to URI + uri = uri.replace(/\?.*|$/, '?' + stringify(data)); + post_data = null; + + } else if (options.multipart) { // build multipart body for request + var boundary = options.boundary || defaults.boundary; + + if (options.combination){ + console.log("post combination"); + multipart.build_combination(data, boundary, function(err, body) { + if (err) throw(err); + + config.headers['Content-Type'] = 'multipart/form-data; boundary=' + boundary; + config.headers['Content-Length'] = body.length; + self.send_request(1, method, uri, config, body, out, callback); + }); + }else { + console.log("post standalone"); + multipart.build(data, boundary, function(err, body) { + if (err) throw(err); + + config.headers['Content-Type'] = 'multipart/form-data; boundary=' + boundary; + config.headers['Content-Length'] = body.length; + self.send_request(1, method, uri, config, body, out, callback); + }); + } + return out; // stream + + } else if (this.is_stream(data) || Buffer.isBuffer(data)) { + + post_data = data; + + } else { // string or object data, no multipart. + + // format data according to content type + var post_data = (typeof(data) === 'string') ? data : + options.json ? JSON.stringify(data) : stringify(data); + + // if no content-type was passed, determine if json or not. + if (!config.headers['Content-Type']) { + config.headers['Content-Type'] = options.json + ? 'application/json' + : 'application/x-www-form-urlencoded'; + } + + post_data = new Buffer(post_data, config.encoding); + config.headers['Content-Length'] = post_data.length; + + // unless a specific accept header was passed, assume json wants json back. + if (options.json && config.headers['Accept'] === defaults.accept) + config.headers['Accept'] = 'application/json'; + } + } + return this.send_request(1, method, uri, config, post_data, out, callback); + }, + + get_request_opts: function(method, uri, config) { + var opts = config.base_opts, + proxy = config.proxy, + remote = proxy ? url.parse(proxy) : url.parse(uri); + + opts.protocol = remote.protocol; + opts.host = remote.hostname; + opts.port = remote.port || (remote.protocol == 'https:' ? 443 : 80); + opts.path = proxy ? uri : remote.pathname + (remote.search || ''); + opts.method = method; + opts.headers = config.headers; + + if (!opts.headers['Host']) { + // if using proxy, make sure the host header shows the final destination + var target = proxy ? url.parse(uri) : remote; + opts.headers['Host'] = target.hostname; + + // and if a non standard port was passed, append it to the port header + if (target.port && [80, 443].indexOf(target.port) === -1) { + opts.headers['Host'] += ':' + target.port; + } + } + + return opts; + }, + + get_auth_header: function(header, credentials, request_opts) { + var type = header.split(' ')[0], + user = credentials[0], + pass = credentials[1]; + + if (type == 'Digest') { + return auth.digest(header, user, pass, request_opts.method, request_opts.path); + } else if (type == 'Basic') { + return auth.basic(user, pass); + } + }, + + send_request: function(count, method, uri, config, post_data, out, callback) { + var timer, + returned = 0, + self = this, + request_opts = this.get_request_opts(method, uri, config), + protocol = request_opts.protocol == 'https:' ? https : http; + + var done = function(err, resp, body) { + if (returned++ > 0) return; + if (callback) + callback(err, resp, body); + else + out.emit('end', err, resp, body); + } + + debug('Making request #' + count, request_opts); + var request = protocol.request(request_opts, function(resp) { + + var headers = resp.headers; + debug('Got response', headers); + if (timer) clearTimeout(timer); + + // if redirect code is found, send a GET request to that location if enabled via 'follow' option + if ([301, 302, 303].indexOf(resp.statusCode) != -1 && headers.location) { + if (count <= config.follow) { + out.emit('redirect', headers.location); + delete config.headers['Content-Length']; // in case the original was a multipart POST request. + return self.send_request(++count, 'GET', url.resolve(uri, headers.location), config, null, out, callback); + } else if (config.follow > 0) { + return done(new Error('Max redirects reached. Possible loop in: ' + headers.location)); + } + } + + // if authentication is requested and credentials were not passed, resend request if we have user/pass + if (resp.statusCode == 401 && headers['www-authenticate'] && config.credentials) { + if (!config.headers['Authorization']) { // only if authentication hasn't been sent + var auth_header = self.get_auth_header(headers['www-authenticate'], config.credentials, request_opts); + + if (auth_header) { + config.headers['Authorization'] = auth_header; + return self.send_request(count, method, uri, config, post_data, out, callback); + } + } + } + + // ok so we got a valid (non-redirect & authorized) response. notify the stream guys. + out.emit('headers', headers); + + var pipeline = [], + parsed = false, + mime = self.parse_content_type(headers['content-type']), + text_response = mime.type && mime.type.indexOf('text/') != -1; + + // To start, if our body is compressed and we're able to inflate it, do it. + if (headers['content-encoding'] && decompressors[headers['content-encoding']]) { + pipeline.push(decompressors[headers['content-encoding']]()); + } + + // If parse is enabled and we have a parser for it, then go for it. + if (config.parse_response && parsers[mime.type]) { + parsed = true; + pipeline.push(parsers[mime.type]()); + + // set objectMode on out stream to improve performance + out._writableState.objectMode = true; + out._readableState.objectMode = true; + + // If we're not parsing, and unless decoding was disabled, we'll try + // decoding non UTF-8 bodies to UTF-8, using the iconv-lite library. + } else if (text_response && config.decode_response + && mime.charset && !mime.charset.match(/utf-?8$/i)) { + pipeline.push(decoder(mime.charset)); + } + + // And `out` is the stream we finally push the decoded/parsed output to. + pipeline.push(out); + + // Now release the kraken! + var tmp = resp; + while (pipeline.length) { + tmp = tmp.pipe(pipeline.shift()); + } + + // If the user has requested and output file, pipe the output stream to it. + // In stream mode, we will still get the response stream to play with. + if (config.output && resp.statusCode == 200) { + resp.pipe(fs.createWriteStream(config.output)) + } + + // Only aggregate the full body if a callback was requested. +// if (callback) { + resp.raw = []; + resp.body = []; + resp.bytes = 0; + // Count the amount of (raw) bytes passed using a PassThrough stream. + var clean_pipe = new stream.PassThrough(); + resp.pipe(clean_pipe); + + clean_pipe.on('readable', function() { + var chunk; + while (chunk = this.read()) { + resp.bytes += chunk.length; + resp.raw.push(chunk); + } + }) + + // Listen on the 'readable' event to aggregate the chunks. + out.on('readable', function() { + var chunk; + while ((chunk = this.read()) !== null) { + // We're either pushing buffers or objects, never strings. + if (typeof chunk == 'string') chunk = new Buffer(chunk); + + // Push all chunks to resp.body. We'll bind them in resp.end(). + resp.body.push(chunk); + } + }) + + // And set the .body property once all data is in. + out.on('end', function() { + + // we may want access to the raw data, so keep a reference. + resp.raw = Buffer.concat(resp.raw); + + // if parse was successful, we should have an array with one object + if (resp.body[0] !== undefined && !Buffer.isBuffer(resp.body[0])) { + resp.body = resp.body[0]; + } else { // we got one or several buffers. string or binary. + resp.body = Buffer.concat(resp.body); + + // if we're here and parsed is true, it means we tried to but it didn't work. + // so given that we got a text response, let's stringify it. + if (text_response || parsed) { + resp.body = resp.body.toString(); + } + } + // time to call back, junior. + //done(null, resp, resp.body); + + if (callback) { + done(null, resp, resp.body); + }else { + return resp.body; + } + }); + +// } + + }); // end request call + + // unless timeout was disabled, set a timeout to abort the request + if (config.timeout > 0) { + timer = setTimeout(function() { + request.abort(); + }, config.timeout) + } + + request.on('error', function(err) { + debug('Request error', err); + if (timer) clearTimeout(timer); + + done(err || new Error('Unknown error when making request.')); + }); + + if (post_data) { + if (this.is_stream(post_data)) { + post_data.pipe(request); + } else { + request.write(post_data, config.encoding); + request.end(); + } + } else { + request.end(); + } + + out.request = request; + return out; + }, + + parse_content_type: function(header) { + if (!header || header == '') return {}; + + var charset = 'iso-8859-1', arr = header.split(';'); + try { charset = arr[1].match(/charset=(.+)/)[1] } catch (e) { /* not found */ } + + return { type: arr[0], charset: charset }; + }, + + is_stream: function(obj) { + return typeof obj.pipe === 'function'; + } +} + +exports.version = version; + +exports.defaults = function(obj) { + for (var key in obj) { + if (defaults[key] && typeof obj[key] != 'undefined') + defaults[key] = obj[key]; + } + return defaults; +} + +'head get'.split(' ').forEach(function(method) { + exports[method] = function(uri, options, callback) { + return Needle.request(method, uri, null, options, callback); + } +}) + +'post put delete'.split(' ').forEach(function(method) { + exports[method] = function(uri, data, options, callback) { + return Needle.request(method, uri, data, options, callback); + } +}) + +exports.request = function(method, uri, data, opts, callback) { + return Needle.request(method, uri, data, opts, callback); +}; diff --git a/node_modules/needle/lib/parsers.js b/node_modules/needle/lib/parsers.js new file mode 100644 index 0000000..bf9c2ea --- /dev/null +++ b/node_modules/needle/lib/parsers.js @@ -0,0 +1,73 @@ +////////////////////////////////////////// +// Defines mappings between content-type +// and the appropriate parsers. +////////////////////////////////////////// + +var Transform = require('stream').Transform; + +function parserFactory(fn) { + + return function() { + var chunks = [], + stream = new Transform({ objectMode: true }); + + // Buffer all our data + stream._transform = function(chunk, encoding, done) { + chunks.push(chunk); + done(); + } + + // And call the parser when all is there. + stream._flush = function(done) { + var self = this, + data = Buffer.concat(chunks); + + try { + fn(data, function(err, result) { + if (err) throw err; + self.push(result); + }); + } catch (err) { + // console.error('Error while processing: ', err); + self.push(data); // just pass the original data + } finally { + done(); + } + } + + return stream; + } + +} + +module.exports['application/json'] = parserFactory(function(buffer, callback) { + + var err, data; + try { + data = JSON.parse(buffer); + } catch (e) { + err = e; + } + callback(err, data); + +}); + +module.exports['text/javascript'] = module.exports['application/json']; + +try { + + var xml2js = require('xml2js'); + + // xml2js.Parser.parseString() has the exact same function signature + // as our ParseStream expects, so we can reuse this. + module.exports['application/xml'] = parserFactory(new xml2js.Parser({ + explicitRoot : true, + explicitArray: false + }).parseString, true); + + // aliases for other XML content types + module.exports['text/xml'] = module.exports['application/xml']; + module.exports['application/rss+xml'] = module.exports['application/xml']; + module.exports['application/atom+xml'] = module.exports['application/xml']; + +} catch(e) { /* xml2js not found */ } diff --git a/node_modules/needle/lib/querystring.js b/node_modules/needle/lib/querystring.js new file mode 100644 index 0000000..ae7539e --- /dev/null +++ b/node_modules/needle/lib/querystring.js @@ -0,0 +1,40 @@ +// based on the qs module, but handles null objects as expected +// fixes by Tomas Pollak. + +var stringify = function(obj, prefix) { + if (obj === null || typeof obj == 'undefined') { + return prefix + '='; + } else if (obj.constructor == Array) { + return stringifyArray(obj, prefix); + } else if (typeof obj == 'object') { + return stringifyObject(obj, prefix); + } else if (prefix) { // string inside array or hash + return prefix + '=' + encodeURIComponent(String(obj)); + } else { + throw new TypeError('Object expected.'); + } +}; + +function stringifyArray(arr, prefix) { + var ret = []; + + for (var i = 0, len = arr.length; i < len; i++) { + ret.push(stringify(arr[i], prefix + '[' + i + ']')); + } + + return ret.join('&'); +} + +function stringifyObject(obj, prefix) { + var ret = []; + + Object.keys(obj).forEach(function(key) { + ret.push(stringify(obj[key], prefix + ? prefix + '[' + encodeURIComponent(key) + ']' + : encodeURIComponent(key))); + }) + + return ret.join('&'); +} + +exports.build = stringify; \ No newline at end of file diff --git a/node_modules/needle/package.json b/node_modules/needle/package.json new file mode 100644 index 0000000..b337f6d --- /dev/null +++ b/node_modules/needle/package.json @@ -0,0 +1,91 @@ +{ + "name": "needle", + "version": "0.7.11", + "description": "Tiny yet feature-packed HTTP client. With multipart, charset decoding and proxy support.", + "keywords": [ + "http", + "https", + "simple", + "request", + "client", + "multipart", + "upload", + "proxy", + "deflate", + "timeout", + "charset", + "iconv" + ], + "tags": [ + "http", + "https", + "simple", + "request", + "client", + "multipart", + "upload", + "proxy", + "deflate", + "timeout", + "charset", + "iconv" + ], + "author": { + "name": "Tomás Pollak", + "email": "tomas@forkhq.com" + }, + "repository": { + "type": "git", + "url": "https://github.com/tomas/needle.git" + }, + "dependencies": { + "iconv-lite": "^0.4.4" + }, + "devDependencies": { + "mocha": "", + "sinon": "", + "should": "", + "xml2js": "", + "JSONStream": "", + "q": "", + "jschardet": "" + }, + "scripts": { + "test": "mocha test" + }, + "directories": { + "lib": "./lib" + }, + "main": "./lib/needle", + "bin": { + "needle": "./bin/needle" + }, + "engines": { + "node": ">= 0.10.x" + }, + "gitHead": "d373be0c8de7188e8b8546ca6aa3acd1db55ba2c", + "bugs": { + "url": "https://github.com/tomas/needle/issues" + }, + "homepage": "https://github.com/tomas/needle", + "_id": "needle@0.7.11", + "_shasum": "2b6ef44cd4260cdc68301ad0ae496c860e13b4d8", + "_from": "needle@>=0.7.10 <0.8.0", + "_npmVersion": "1.4.28", + "_npmUser": { + "name": "tomas", + "email": "tomas@forkhq.com" + }, + "maintainers": [ + { + "name": "tomas", + "email": "tomas@forkhq.com" + } + ], + "dist": { + "shasum": "2b6ef44cd4260cdc68301ad0ae496c860e13b4d8", + "tarball": "http://registry.npmjs.org/needle/-/needle-0.7.11.tgz" + }, + "_resolved": "https://registry.npmjs.org/needle/-/needle-0.7.11.tgz", + "readme": "ERROR: No README data found!" +} diff --git a/package.json b/package.json index e08d325..bbc4070 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,15 @@ { "name": "havenondemand", - "version": "1.3.0", + "version": "1.4.0", "description": "Official Haven OnDemand Node.js client", "main": "index.js", - "dependencies": { - "needle": "^0.7.10" - }, "devDependencies": {}, "scripts": { "test": "node test.js" }, "author": "Haven OnDemand", "contributors": [ + "Phong Vu ", "Tyler Nappy ", "Martin Zerbib" ], From 4dc5daf6c1ec28107c582c1762e71e7bdec33d11 Mon Sep 17 00:00:00 2001 From: Paco Vu Date: Thu, 1 Dec 2016 17:19:36 -0800 Subject: [PATCH 37/40] Update index.js --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index c392e19..f6022a6 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ var hod = require('./lib/hodneedle') +var needle = require('./node_modules/needle/lib/needle') module.exports=hod +module.exports=needle From 3f138e1abbf180c2a6f9bd99283c06efcab5e559 Mon Sep 17 00:00:00 2001 From: Paco Vu Date: Thu, 1 Dec 2016 17:25:55 -0800 Subject: [PATCH 38/40] Updated lib structure --- index.js | 2 -- lib/hodneedle.js | 2 +- {node_modules => lib}/needle/CHANGELOG.md | 0 {node_modules => lib}/needle/README.md | 0 {node_modules => lib}/needle/lib/auth.js | 0 {node_modules => lib}/needle/lib/decoder.js | 0 {node_modules => lib}/needle/lib/multipart.js | 0 {node_modules => lib}/needle/lib/needle.js | 0 {node_modules => lib}/needle/lib/parsers.js | 0 {node_modules => lib}/needle/lib/querystring.js | 0 {node_modules => lib}/needle/package.json | 0 node_modules/.bin/needle | 1 - 12 files changed, 1 insertion(+), 4 deletions(-) rename {node_modules => lib}/needle/CHANGELOG.md (100%) rename {node_modules => lib}/needle/README.md (100%) rename {node_modules => lib}/needle/lib/auth.js (100%) rename {node_modules => lib}/needle/lib/decoder.js (100%) rename {node_modules => lib}/needle/lib/multipart.js (100%) rename {node_modules => lib}/needle/lib/needle.js (100%) rename {node_modules => lib}/needle/lib/parsers.js (100%) rename {node_modules => lib}/needle/lib/querystring.js (100%) rename {node_modules => lib}/needle/package.json (100%) delete mode 120000 node_modules/.bin/needle diff --git a/index.js b/index.js index f6022a6..c392e19 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,3 @@ var hod = require('./lib/hodneedle') -var needle = require('./node_modules/needle/lib/needle') module.exports=hod -module.exports=needle diff --git a/lib/hodneedle.js b/lib/hodneedle.js index c723462..2993380 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -1,4 +1,4 @@ -var needle = require('needle') +var needle = require('./needle/lib/needle') var util = require('util') var fs = require('fs') var querystring = require('querystring') diff --git a/node_modules/needle/CHANGELOG.md b/lib/needle/CHANGELOG.md similarity index 100% rename from node_modules/needle/CHANGELOG.md rename to lib/needle/CHANGELOG.md diff --git a/node_modules/needle/README.md b/lib/needle/README.md similarity index 100% rename from node_modules/needle/README.md rename to lib/needle/README.md diff --git a/node_modules/needle/lib/auth.js b/lib/needle/lib/auth.js similarity index 100% rename from node_modules/needle/lib/auth.js rename to lib/needle/lib/auth.js diff --git a/node_modules/needle/lib/decoder.js b/lib/needle/lib/decoder.js similarity index 100% rename from node_modules/needle/lib/decoder.js rename to lib/needle/lib/decoder.js diff --git a/node_modules/needle/lib/multipart.js b/lib/needle/lib/multipart.js similarity index 100% rename from node_modules/needle/lib/multipart.js rename to lib/needle/lib/multipart.js diff --git a/node_modules/needle/lib/needle.js b/lib/needle/lib/needle.js similarity index 100% rename from node_modules/needle/lib/needle.js rename to lib/needle/lib/needle.js diff --git a/node_modules/needle/lib/parsers.js b/lib/needle/lib/parsers.js similarity index 100% rename from node_modules/needle/lib/parsers.js rename to lib/needle/lib/parsers.js diff --git a/node_modules/needle/lib/querystring.js b/lib/needle/lib/querystring.js similarity index 100% rename from node_modules/needle/lib/querystring.js rename to lib/needle/lib/querystring.js diff --git a/node_modules/needle/package.json b/lib/needle/package.json similarity index 100% rename from node_modules/needle/package.json rename to lib/needle/package.json diff --git a/node_modules/.bin/needle b/node_modules/.bin/needle deleted file mode 120000 index 8280969..0000000 --- a/node_modules/.bin/needle +++ /dev/null @@ -1 +0,0 @@ -../needle/bin/needle \ No newline at end of file From 360cbc1309044b5cb3ce0baad6bb0184bc84f9bf Mon Sep 17 00:00:00 2001 From: Paco Vu Date: Thu, 1 Dec 2016 17:29:55 -0800 Subject: [PATCH 39/40] Removed redundant codes - Remove test code --- lib/hodneedle.js | 82 ---------------------------------------- lib/needle/lib/needle.js | 2 - 2 files changed, 84 deletions(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index 2993380..180a220 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -105,89 +105,7 @@ HODClient.prototype.post_combination = function(hodApp,params,async,callback) { needle.post(url, data, { combination:true, multipart: true }, callbackmanager); } } -HODClient.prototype.post_combination_S = function(hodApp,params,async,callback) { - var data = {} - validadeParameters(hodApp,params,async,callback) - async_string = "sync"; - data.apikey = this.apikey; - data.combination = hodApp; - - for(var item in params){ - if (item == 'file'){ - var files = params[item] - var count = files.length - for(var i=0; i Date: Fri, 2 Dec 2016 09:25:14 -0800 Subject: [PATCH 40/40] Updated hodneedle Fixed get_combination --- lib/hodneedle.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/hodneedle.js b/lib/hodneedle.js index 180a220..73360b3 100644 --- a/lib/hodneedle.js +++ b/lib/hodneedle.js @@ -115,27 +115,21 @@ HODClient.prototype.get_combination = function(hodApp,params,async,callback) { if (async) { async_string="async"; } - data.apikey = this.apikey; - data.combination = hodApp; + var configs = util.format("apikey=%s&combination=%s", this.apikey, hodApp); for(var item in params){ if (item == 'file'){ throw new Error("Cannot perform GET with file. Use POST request.") } else { - var d = "" if (isJSON(params[item])) - d = util.format('{"name":"%s","value":%s}', item, params[item]) + configs += util.format('¶meters={"name":"%s","value":%s}', item, params[item]) else - d = util.format('{"name":"%s","value":"%s"}', item, params[item]) - - if (typeof data.parameters == "undefined") - data.parameters = d - else - data.parameters += d + configs += util.format('¶meters={"name":"%s","value":"%s"}', item, params[item]) } } - var url = util.format(this.endpoint, async_string,"executecombination") + "?" + querystring.stringify(data) + var url = util.format(this.endpoint, async_string,"executecombination") + "?" + configs + if (async){ var callback = callback; var callbackmanager=function(err,resp,body){