diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index c38f2f6..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a7f9270 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.gem +**/.DS_Store diff --git a/Gemfile b/Gemfile index 5c9c1ae..9698777 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ source 'https://rubygems.org' -# Specify your gem's dependencies in iodruby.gemspec +# Specify your gem's dependencies in havenondemand.gemspec gemspec 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/README.md b/README.md index 9761faf..3ea8133 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,37 @@ -# Iodruby +**Note:** use `iod` branch for older compatibility syntax. -Ruby Gem to help call IDOL OnDemand API. - [http://idolondemand.com](http://idolondemand.com) +# Ruby gem for Haven OnDemand +Official Ruby gem to help with calling Haven OnDemand APIs [http://havenondemand.com](http://havenondemand.com). Gem is hosted on rubygems.org [here](https://rubygems.org/gems/havenondemand). + +## 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 +* 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.havenondemand.com/developer/apis ## Installation -To install from this git repo use the specific_install gem. +To install from rubygems.org. + +``` +gem install havenondemand +``` + +To install the latest version from this github repo, use the specific_install gem. ``` gem install specific_install -gem specific_install http://github.com/lemoogle/iodruby +gem specific_install https://github.com/HP-Haven-OnDemand/havenondemand-ruby ``` @@ -18,150 +39,182 @@ gem specific_install http://github.com/lemoogle/iodruby ### Importing - +When using rails and other frameworks with a gem file, include it in it. +```ruby +gem "havenondemand" ``` -require "iodruby" +Or, require it directly in your app. +```ruby +require "havenondemand" ``` ###Initializing the client - -``` -client= IODClient.new("http://api.idolondemand.com",$apikey) +```ruby +client = HODClient.new(apikey, version) ``` +You can find your API key [here](https://www.haveondemand.com/account/api-keys.html) after signing up. -All that is needed to initialize the client is an apikey and the url of the API. +`version` is an optional parameter (defaults to `'v1'`) and can be either `'v1'` or `'v2'`. +## Sending requests to the API - POST and GET +You can send requests to the API with either a POST or GET request, where POST requests are required for uploading files and recommended for larger size queries and GET requests are recommended for smaller size queries. -###Sending requests - +### POST request ```ruby -r=client.post('analyzesentiment',{:text=>'I like cats'}) +client.get_request(hodApp, params, async, method(:callback)) ``` -The client's *post* method takes the apipath that you're sending your request to as well as an object containing the parameters you want to send to the api. You do not need to send your apikey each time as the client will handle that automatically - -###Posting files +* `hodApp` is the name of the API you are calling (see this [list]() for available endpoints and our [documentation](https://dev.havenondemand.com/apis) for descriptions of each of the APIs) +* `params` is a dictionary of parameters passed to the API +* `async` specifies if you are calling the API asynchronously or synchronously, which is either `true` or `false`, respectively +* `callback` which is a callback function which is executed when the response from the API is received. Specify 'nil' for returning response. +### GET request ```ruby -r=client.post('ocrdocument',{:file=>File.new("/path/to/file", 'rb')}) +client.get_request(hodApp, params, async, method(:callback)) ``` -Sending files is just as easy. +* `hodApp` is the name of the API you are calling (see this [list]() for available endpoints and our [documentation](https://dev.havenondemand.com/apis) for descriptions of each of the APIs) +* `params` is a dictionary of parameters passed to the API +* `async` specifies if you are calling the API asynchronously or synchronously, which is either `true` or `false`, respectively +* `callback` which is a callback function which is executed when the response from the API is received. Specify 'nil' for returning response. +### POST request for combinations ```ruby -r=client.post('ocrdocument',{:mode=>'photo',:file=>File.new("/path/to/file", 'rb')}) -r=client.post('ocrdocument',{:mode=>'photo',:file=>File.new("/path/to/file", 'rb')}) +client.post_request_combination(hodApp, params, async, method(:callback)) ``` -Any extra parameters should be added in the same way as regular calls, or in the data parameter. +* `hodApp` is the name of the combination API you are calling +* `params` is a dictionary of parameters passed to the API +* `async` specifies if you are calling the API asynchronously or synchronously, which is either `true` or `false`, respectively +* `callback` which is a callback function which is executed when the response from the API is received. Specify 'nil' for returning response. -###Parsing the output +### GET request for combinations ```ruby -myjson=r.json() +client.get_request_combination(hodApp, params, async, method(:callback)) ``` +* `hodApp` is the name of the combination API you are calling +* `params` is a dictionary of parameters passed to the API +* `async` specifies if you are calling the API asynchronously or synchronously, which is either `true` or `false`, respectively +* `callback` which is a callback function which is executed when the response from the API is received. Specify 'nil' for returning response. -The object returned is a response object from the python [requests library](http://docs.python-requests.org/en/latest/) and can easily be turned to json. +## Synchronous vs Asynchronous +Haven OnDemand's API can be called either synchronously or asynchronously. Users are encouraged to call asynchronously if they are POSTing large files that may require a lot of time to process. If not, calling them synchronously should suffice. For more information on the two, see [here](https://dev.havenondemand.com/docs/AsynchronousAPI.htm). + +### Synchronous +To make a synchronous GET request to our Sentiment Analysis API ```ruby -docs=myjson["documents"] -array.each {|doc| puts doc["title"] } +params = {:text=> 'I love Haven OnDemand!'} +hodApp = "analyzesentiment" +response = client.get_request(hodApp, params, false, nil) ``` +where the response will be in the `response` variable. -###Indexing - -**Creating an index** +### Asynchronous +To make an asynchronous POST request to our Sentiment Analysis API ```ruby -index=client.createIndex("mytestindex",flavor="explorer") +params = {:text=> 'I love Haven OnDemand!'} +hodApp = "analyzesentiment" +response_async = post_request(hodApp, params, async=true, nil) +jobID = response_async['jobID'] ``` +which will return back the job ID of your call. Use the job ID to call the get_job_status() or get_job_result() to get the result. -An Index object can easily be created +#### Getting the results of an asynchronous request - Status API and Result API -**Fetching indexes/an index** +##### Status API +The Status API checks to see the status of your job request. If it is finished processing, it will return the result. If not, it will return you the status of the job. ```ruby -index = client.getIndex('myindex') +client.get_job_status(jobID, method(:callback)) ``` -The getIndex call will return an iodindex Index object but will not check for existence. +* `jobID` is the job ID of request returned after performing an asynchronous request +* `callback` which is a callback function which is executed when the response from the API is received. Specify 'nil' for returning response. +To get the status, or job result if the job is complete ```ruby -indexes = client.listIndexes() -indexes.fetch('myindex',client.createIndex('myindex')) +client.get_job_status(jobID, method(:callback)) ``` -Here we first check the list of our indexes and return a newly created index if the index does not already exist - -**Deleting an index** +##### Result API +The Result API checks the result of your job request. If it is finished processing, it will return the result. If it not, the call the wait until the result is returned or until it times out. **It is recommended to use the Status API over the Result API to avoid time outs** ```ruby -index.delete() -client.deleteIndex('myindex') +client.get_job_result(jobID, method(:callback)) ``` -An index can be deleted in two equivalent ways - -**Indexing documents** +* `jobID` is the job ID of request returned after performing an asynchronous request +* `callback` which is a callback function which is executed when the response from the API is received. Specify 'nil' for returning response. +To get the result ```ruby -doc1=IODDoc.new({title:"title1",reference:"doc1",content:"my content 1"}) -doc2=IODDoc.new({title:"title2",reference:"doc2",content:"my content 2"}) +response = client.get_job_result(jobID, nil) ``` -Documents can be created as regular python objects -``` -index.addDoc(doc1) -index.addDocs([doc1,doc2]) -``` - -They can be added directly one at a time or in a batch. - -``` -for doc in docs: - index.pushDoc(doc) -index.commit() -``` - -An alternative to *addDocs* and easy way to keep batch documents is to use the pushDoc method, the index will keep in memory a list of the documents it needs to index. - -``` -if index.countDocs()>10: - index.commit() -``` - -It makes it easy to batch together groups of documents. - -####Indexing - Connectors +## Using a callback function +Most methods allow optional callback functions which are executed when the response of the API is received. ```ruby -client= IODClient.new("http://api.idolondemand.com",$apikey) -conn=IODConnector.new("mytestconnector",client) -conn.create(type="web",config={ "url" => "http://www.idolondemand.com" }) -conn.delete() -``` - - -### Asynchronous request - -For each call the Async parameter can be set to true to send an asynchronous request. +def syncCallback(response) + response = $parser.parse_payload(response) + if response != nil + puts response + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + if eCode == ErrorCode::QUEUED + jobID = error["jobID"] + client.get_job_status(jobID, method(:syncCallback)) + elsif eCode == ErrorCode::IN_PROGRESS + jobID = error["jobID"] + client.get_job_status(jobID, method(:syncCallback)) + else + puts eCode + puts error["detail"] + puts error["reason"] + end + } + end +end + +def asyncCallback(response) + jobID = $parser.parse_jobid(response) + client.get_job_status(jobID, method(:syncCallback)) +end + +params = {:text=> 'I love Haven OnDemand!'} +hodApp = "analyzesentiment" +client.post_request(hodApp, params, true, method(:asyncCallback)) +``` + +## POSTing files +POSTing files is just as easy. Simply include the path to the file you're POSTing in the parameters ```ruby -r=client.post('analyzesentiment',{:text=>'I like cats'},async=True) -print r.json() - -# will return status of call, queued or finished -puts r.status().json() -# Will wait until result to return -puts r.result().json() +params = {:file=> 'path/to/file.jpg'} +hodApp = "ocrdocument" +response = hodClient.post_request(hodApp, params, false, nil) +puts response ``` -Same thing for indexing. +## POSTing files with post_request_combination +POSTing files to a combination API is slightly different from POSting files to a standalone API. ```ruby -r=index.commit(async=True) +files = [{"file1_input_name"=>"file1name.xxx"},{"file2_input_name"=>"file2name.xxx"}] +params = {} +params[:file] = files +hodApp = "name_of_combination_api" +response = client.post_request_combination(hodApp, params, false, nil) ``` - +## License +Licensed under the MIT License. ## Contributing +We encourage you to contribute to this repo! Please send pull requests with modified and updated code. -1. Fork it ( https://github.com/lemoogle/iodruby/fork ) +1. Fork it ( https://github.com/HPE-Haven-OnDemand/havenondemand-ruby/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`) diff --git a/examples/.DS_Store b/examples/.DS_Store deleted file mode 100644 index 3a48f38..0000000 Binary files a/examples/.DS_Store and /dev/null differ diff --git a/examples/attendant_test.mp3 b/examples/attendant_test.mp3 new file mode 100755 index 0000000..301131d Binary files /dev/null and b/examples/attendant_test.mp3 differ diff --git a/examples/call_post_request_combination.rb b/examples/call_post_request_combination.rb new file mode 100644 index 0000000..38fb89e --- /dev/null +++ b/examples/call_post_request_combination.rb @@ -0,0 +1,61 @@ +require_relative "../lib/havenondemand.rb" + +$client = HODClient.new("YOUR_API_KEY", "v1") +$parser = HODResponseParser.new() + +def syncCallback(response) + response = $parser.parse_payload(response) + if response != nil + puts response + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + if eCode == ErrorCode::QUEUED + jobID = error["jobID"] + sleep(2) + $client.get_job_status(jobID, method(:syncCallback)) + elsif eCode == ErrorCode::IN_PROGRESS + jobID = error["jobID"] + sleep(5) + $client.get_job_status(jobID, method(:syncCallback)) + else + puts eCode + puts error["detail"] + puts error["reason"] + end + } + end +end + +def asyncCallback(response) + jobID = $parser.parse_jobid(response) + if jobID != nil + $client.get_job_status(jobID, method(:syncCallback)) + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + puts eCode + puts error["detail"] + puts error["reason"] + } + end +end + +# supposed that a combination API takes 2 input files. ! image file for extracting text from image +# and 1 audio file for extracting text from speech. +# And the names of the file input are ocrFile and speechFile. +# And the name of the combination API is "multiplefileinput" + +files = [{"ocrFile"=>"review.jpg"},{"speechFile"=>"attendant_test.mp3"}] +# OR +=begin +#file1 = {"ocrFile"=>"review.jpg"} +#file2 = {"speechFile"=>"attendant_test.mp3"} +files = [] +files.push(file1) +files.push(file2) +=end +params["file"] = files +$client.post_request_combination('multiplefileinput', params, true, method(:asyncCallback)) diff --git a/examples/callback_async.rb b/examples/callback_async.rb new file mode 100644 index 0000000..333df5d --- /dev/null +++ b/examples/callback_async.rb @@ -0,0 +1,50 @@ +require_relative "../lib/havenondemand.rb" + +$client = HODClient.new("YOUR_API_KEY", "v1") +$parser = HODResponseParser.new() + +# call Haven OnDemand APIs using asynchronous mode + +def syncCallback(response) + response = $parser.parse_payload(response) + if response != nil + puts response + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + if eCode == ErrorCode::QUEUED + jobID = error["jobID"] + $client.get_job_status(jobID, method(:syncCallback)) + elsif eCode == ErrorCode::IN_PROGRESS + jobID = error["jobID"] + $client.get_job_status(jobID, method(:syncCallback)) + else + puts eCode + puts error["detail"] + puts error["reason"] + end + } + end +end + +def asyncCallback(response) + jobID = $parser.parse_jobid(response) + if jobID != nil + $client.get_job_status(jobID, method(:syncCallback)) + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + puts eCode + puts error["detail"] + puts error["reason"] + } + end +end + +params = {} +params["url"] = "http://www.cnn.com" +params["entity_type"] = ['people_eng','places_eng'] +hodApp = 'extractentities' +$client.post_request(hodApp, params, true, method(:asyncCallback)) diff --git a/examples/callback_sync.rb b/examples/callback_sync.rb new file mode 100644 index 0000000..032d0af --- /dev/null +++ b/examples/callback_sync.rb @@ -0,0 +1,34 @@ +require_relative "../lib/havenondemand.rb" + +$client = HODClient.new("YOUR_API_KEY", "v1") +$parser = HODResponseParser.new() + +def syncCallback(response) + response = $parser.parse_payload(response) + if response != nil + puts response + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + if eCode == ErrorCode::QUEUED + jobID = error["jobID"] + $client.get_job_status(jobID, method(:syncCallback)) + elsif eCode == ErrorCode::IN_PROGRESS + jobID = error["jobID"] + $client.get_job_status(jobID, method(:syncCallback)) + else + puts eCode + puts error["detail"] + puts error["reason"] + end + } + end +end + +# call Haven OnDemand APIs using synchronous mode +params = {} +params["url"] = "http://www.cnn.com" +params["entity_type"] = ['people_eng','places_eng'] +hodApp = 'extractentities' +$client.post_request(hodApp, params, false, method(:syncCallback)) diff --git a/examples/examples.rb b/examples/examples.rb deleted file mode 100644 index f437c26..0000000 --- a/examples/examples.rb +++ /dev/null @@ -1,67 +0,0 @@ -require_relative "../lib/iodruby.rb" - -$apikey="yourapikey" - - - -def test_post - client= IODClient.new("http://api.idolondemand.com",$apikey) - r=client.post("querytextindex",{:text=>"hello",:absolute_max_result=>1000}) - puts "\n",r.json()["documents"][0]["reference"],"\n" -end - - -def test_post_async - client= IODClient.new("http://api.idolondemand.com",$apikey) - r=client.post("querytextindex",{:text=>"hello"},async=true) - #returns jobid - puts r.jobID - # will return status of call, queued or finished - puts r.status().json() - # Will wait until result to return - puts r.result().json() -end - - - -def test_indexing(index="mytestindex") - client= IODClient.new("http://api.idolondemand.com",$apikey) - index=client.getIndex("myrssdb") - - doc={:title=>"title",:reference=>"ref",:content=>"content"} - index.pushDoc(doc) - puts index.commit().json() -end - - - -def test_createIndex - client= IODClient.new("http://api.idolondemand.com",$apikey) - index=client.createIndex("mytestindex",flavor="explorer") - puts index.json() -end - - - -def test_deleteIndex - client= IODClient.new("http://api.idolondemand.com",$apikey) - puts client.deleteIndex("mytestindex") -end - -def test_createConnector - client= IODClient.new("http://api.idolondemand.com",$apikey) - conn=IODConnector.new("mytestconnector",client) - puts conn.create(type="web",config={ "url" => "http://www.idolondemand.com" }) - puts conn.delete() -end - -def test_sentiment - - client= IODClient.new("http://api.idolondemand.com",$apikey) - r=client.post('analyzesentiment',{'text'=>'I like cats'}) - puts r.json() -end - -test_sentiment() - -#test_createIndex() diff --git a/examples/post_file.rb b/examples/post_file.rb new file mode 100644 index 0000000..92e11c5 --- /dev/null +++ b/examples/post_file.rb @@ -0,0 +1,52 @@ +require_relative "../lib/havenondemand.rb" + +$client = HODClient.new("YOUR_API_KEY", "v1") +$parser = HODResponseParser.new() + +# call Haven OnDemand APIs using asynchronous mode + +def syncCallback(response) + response = $parser.parse_payload(response) + if response != nil + puts response + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + if eCode == ErrorCode::QUEUED + jobID = error["jobID"] + sleep(2) + $client.get_job_status(jobID, method(:syncCallback)) + elsif eCode == ErrorCode::IN_PROGRESS + jobID = error["jobID"] + sleep(5) + $client.get_job_status(jobID, method(:syncCallback)) + else + puts eCode + puts error["detail"] + puts error["reason"] + end + } + end +end + +def asyncCallback(response) + jobID = $parser.parse_jobid(response) + if jobID != nil + $client.get_job_status(jobID, method(:syncCallback)) + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + puts eCode + puts error["detail"] + puts error["reason"] + } + end +end + +params = {} +params["file"] = "pathto/filename.xxx" +params["entity_type"] = ['people_eng','places_eng'] +hodApp = 'extractentities' +$client.post_request(hodApp, params, true, method(:asyncCallback)) diff --git a/examples/post_multiple_files.rb b/examples/post_multiple_files.rb new file mode 100644 index 0000000..845aed6 --- /dev/null +++ b/examples/post_multiple_files.rb @@ -0,0 +1,52 @@ +require_relative "../lib/havenondemand.rb" + +$client = HODClient.new("YOUR_API_KEY", "v1") +$parser = HODResponseParser.new() + +# call Haven OnDemand APIs using asynchronous mode + +def syncCallback(response) + response = $parser.parse_payload(response) + if response != nil + puts response + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + if eCode == ErrorCode::QUEUED + jobID = error["jobID"] + sleep(2) + $client.get_job_status(jobID, method(:syncCallback)) + elsif eCode == ErrorCode::IN_PROGRESS + jobID = error["jobID"] + sleep(5) + $client.get_job_status(jobID, method(:syncCallback)) + else + puts eCode + puts error["detail"] + puts error["reason"] + end + } + end +end + +def asyncCallback(response) + jobID = $parser.parse_jobid(response) + if jobID != nil + $client.get_job_status(jobID, method(:syncCallback)) + else + errors = $parser.get_last_errors() + errors.each { |error| + eCode = error["error"] + puts eCode + puts error["detail"] + puts error["reason"] + } + end +end + +params = {} +params["file"] = ["pathto/filename1.xxx","pathto/filename2.xxx"] +params["entity_type"] = ['people_eng','places_eng'] +hodApp = 'extractentities' +$client.post_request(hodApp, params, true, method(:asyncCallback)) diff --git a/examples/returnresponse_async.rb b/examples/returnresponse_async.rb new file mode 100644 index 0000000..fe72607 --- /dev/null +++ b/examples/returnresponse_async.rb @@ -0,0 +1,23 @@ +require_relative "../lib/havenondemand.rb" + +$client = HODClient.new("YOUR_API_KEY", "v1") +$parser = HODResponseParser.new() + + +params = {} +params["text"] = "Haven OnDemand is awesome" +params["language"] = 'eng' +hodApp = 'analyzesentiment' +# get_request with return response in asynchronous mode +r = $client.get_request(hodApp, params, true, nil) +jobID = $parser.parse_jobid(r) +r = $client.get_job_result(jobID) + +# post_request with return response in asynchronous mode +=begin +r = $client.post_request(hodApp, params, true, nil) +jobID = $parser.parse_jobid(r) +r = $client.get_job_result(jobID) +=end + +puts r diff --git a/examples/returnresponse_sync.rb b/examples/returnresponse_sync.rb new file mode 100644 index 0000000..f23704d --- /dev/null +++ b/examples/returnresponse_sync.rb @@ -0,0 +1,15 @@ +require_relative "../lib/havenondemand.rb" + +$client = HODClient.new("YOUR_API_KEY", "v1") + +params = {} +params["text"] = "Haven OnDemand is awesome" +params["language"] = 'eng' +hodApp = 'analyzesentiment' +# get_request with return response in synchronous mode +r = $client.get_request(hodApp, params, false, nil) + +# post_request with return response in synchronous mode +#r = $client.post_request(hodApp, params, false, nil) + +puts r diff --git a/examples/review.jpg b/examples/review.jpg new file mode 100755 index 0000000..5caa22a Binary files /dev/null and b/examples/review.jpg differ diff --git a/examples/testhelper.rb b/examples/testhelper.rb deleted file mode 100644 index de3d53b..0000000 --- a/examples/testhelper.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative "../lib/iodruby" -require "test/unit" diff --git a/iodruby.gemspec b/havenondemand.gemspec similarity index 61% rename from iodruby.gemspec rename to havenondemand.gemspec index fd7de83..cab8caa 100644 --- a/iodruby.gemspec +++ b/havenondemand.gemspec @@ -1,16 +1,16 @@ # coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'iodruby/version' +require 'havenondemand/version' Gem::Specification.new do |spec| - spec.name = "iodruby" - spec.version = Iodruby::VERSION - spec.authors = ["Martin Zerbib"] - spec.email = ["martin.zerbib@hp.com"] - spec.summary = %q{Idol OnDemand Ruby Client} + spec.name = "havenondemand" + spec.version = Havenondemand::VERSION + spec.authors = ["Phong Vu", "Tyler Nappy", " Martin Zerbib"] + spec.email = ["phong.vu@hpe.com"] + spec.summary = %q{Haven OnDemand Ruby Client} spec.description = %q{} - spec.homepage = "" + spec.homepage = "https://github.com/HP-Haven-OnDemand/havenondemand-ruby" spec.license = "MIT" spec.files = `git ls-files -z`.split("\x0") @@ -19,7 +19,7 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.add_runtime_dependency "unirest" - + spec.add_development_dependency "bundler", "~> 1.7" spec.add_development_dependency "rake", "~> 10.0" end diff --git a/lib/.DS_Store b/lib/.DS_Store deleted file mode 100644 index 9cbf913..0000000 Binary files a/lib/.DS_Store and /dev/null differ diff --git a/lib/havenondemand.rb b/lib/havenondemand.rb new file mode 100644 index 0000000..b48fed7 --- /dev/null +++ b/lib/havenondemand.rb @@ -0,0 +1,2 @@ +require File.join(File.dirname(__FILE__), "hodclient.rb") +require File.join(File.dirname(__FILE__), "hodresponseparser.rb") diff --git a/lib/havenondemand/version.rb b/lib/havenondemand/version.rb new file mode 100644 index 0000000..1dc2ea4 --- /dev/null +++ b/lib/havenondemand/version.rb @@ -0,0 +1,3 @@ +module Havenondemand + VERSION = "1.3.0" +end diff --git a/lib/hodclient.rb b/lib/hodclient.rb new file mode 100644 index 0000000..490d130 --- /dev/null +++ b/lib/hodclient.rb @@ -0,0 +1,275 @@ +require 'json' +require 'Unirest' + +class HODClient + def initialize(apikey, version="v1") + # Instance variables + if apikey=='http://api.havenondemand.com' || apikey=='http://api.havenondemand.com/' || apikey=='https://api.havenondemand.com' || apikey=='https://api.havenondemand.com/' + raise ArgumentError, "Using an outdated wrapper constructor method. No need to include API URL.\nInclude as such:\n client = HODClient(API_KEY, VERSION)\n where version is optional" + end + @apikey = apikey + @ver = version + @hodAppBase = "https://api.havenondemand.com/1/api/"; + @hodJobResultBase = "https://api.havenondemand.com/1/job/result/"; + @hodJobStatusBase = "https://api.havenondemand.com/1/job/status/"; + @hodCombineAsync = "async/executecombination"; + @hodCombineSync = "sync/executecombination"; + @timeoutVal = 120 + end + + + def get_job_status(jobID,callback) + data={"apikey"=>@apikey} + response=Unirest.post "#{@hodJobStatusBase}#{jobID}", + headers:{ "Accept" => "application/json" }, + parameters:data + if response.code == 200 + if callback != nil + callback.call(response.body) + else + return response.body + end + else + puts "Error: #{response.body}" + err = create_error_object(response.body["error"],response.body["reason"],response.body["detail"],"") + if callback != nil + callback.call(err) + else + return err + end + end + end + + def get_job_result(jobID,callback) + data={"apikey"=>@apikey} + response=Unirest.post "#{@hodJobResultBase}#{jobID}", + headers:{ "Accept" => "application/json" }, + parameters:data + if response.code == 200 + if callback != nil + callback.call(response.body) + else + return response.body + end + else + err = create_error_object(response.body["error"],response.body["reason"],response.body["detail"],"") + if callback != nil + callback.call(err) + else + return err + end + end + end + + def get_request(hodApp, params, async=false,callback) + url='' + if async == true + url = "#{@hodAppBase}async/#{hodApp}/#{@ver}?apikey=#{@apikey}" + else + url = "#{@hodAppBase}sync/#{hodApp}/#{@ver}?apikey=#{@apikey}" + end + params.each do |key, value| + if "#{key}" == "file" + raise ArgumentError, "File upload must be used with PostRequest method" + else + if value.kind_of?(Array) + value.each { |x| + p = "&#{key}=#{x}" + url = [url, p].join() + } + else + p = "&#{key}=#{value}" + url = [url, p].join() + end + end + end + Unirest.timeout(@timeoutVal) + + response=Unirest.get ("#{url}") + if response.code == 200 + if callback != nil + callback.call(response.body) + else + return response.body + end + else + puts "Error: #{response.body}" + err = create_error_object(response.body["error"],response.body["reason"],response.body["detail"],"") + if callback != nil + callback.call(err) + else + return err + end + end + end + + def post_request(hodApp, params, async=true, callback) + endPoint = '' + if async == true + endPoint = "#{@hodAppBase}async/#{hodApp}/#{@ver}" + else + endPoint = "#{@hodAppBase}sync/#{hodApp}/#{@ver}" + end + data = {} + data.compare_by_identity + data["apikey"]=@apikey + params.each do |key, value| + if "#{key}" == "file" + if value.kind_of?(Array) + value.each { |file| + data["file"] = File.new(file, 'rb') + } + else + data["file"] = File.new(value, 'rb') + end + else + if value.kind_of?(Array) + value.each { |x| + data["#{key}"] = x + } + else + data["#{key}"] = value + end + end + end + Unirest.timeout(@timeoutVal) + response=Unirest.post endPoint, + headers:{ "Accept" => "application/json", "Content-Type" => "application/json"}, + parameters:data + + if response.code == 200 + if callback != nil + callback.call(response.body) + else + return response.body + end + else + puts "Error: #{response.body}" + err = create_error_object(response.body["error"],response.body["reason"],response.body["detail"],"") + if callback != nil + callback.call(err) + else + return err + end + end + end + + def get_request_combination(hodApp, params, async=false, callback) + url='' + if async == true + url = "#{@hodAppBase}#{@hodCombineAsync}/#{@ver}" + else + url = "#{@hodAppBase}#{@hodCombineSync}/#{@ver}" + end + url = [url, "?apikey=#{@apikey}&combination=#{hodApp}"].join() + params.each do |key, value| + if "#{key}" == "file" + raise ArgumentError, "File upload must be used with post_combination method" + else + if valid_json?(value) + raise ArgumentError, "JSON input must be used with post_combination method" + else + p = "\"{\"name\":\"#{key}\",\"value\":\"#{value}\"}\"" + url = [url, "¶meters=",p].join() + end + end + end + Unirest.timeout(@timeoutVal) + + response=Unirest.get ("#{url}") + if response.code == 200 + if callback != nil + callback.call(response.body) + else + return response.body + end + else + puts "Error: #{response.body}" + err = create_error_object(response.body["error"],response.body["reason"],response.body["detail"],"") + if callback != nil + callback.call(err) + else + return err + end + end + end + + def post_request_combination(combinationName, params, async=false, callback) + endPoint='' + if async == true + endPoint = "#{@hodAppBase}#{@hodCombineAsync}/#{@ver}" + else + endPoint = "#{@hodAppBase}#{@hodCombineSync}/#{@ver}" + end + data = {} + data.compare_by_identity + data["apikey"]=@apikey + data["combination"] = combinationName + + params.each do |key, value| + if "#{key}" == "file" + if value.kind_of?(Array) + for index in 0 ... value.size + value[index].each_pair {|kk,vv| + data["file_parameters"] = kk + data["file"] = File.new(vv, 'rb') + } + end + else + value.each_pair {|kk,vv| + data["file_parameters"] = kk + data["file"] = File.new(vv, 'rb') + } + end + else + if valid_json?(value) + p = "{\"name\":\"#{key}\",\"value\":#{value}}" + data["parameters"] = p + else + p = "{\"name\":\"#{key}\",\"value\":\"#{value}\"}" + data["parameters"] = p + end + end + end + + Unirest.timeout(@timeoutVal) + response=Unirest.post endPoint, + headers:{ "Accept" => "application/json", "Content-Type" => "application/json"}, + parameters:data + + if response.code == 200 + if callback != nil + callback.call(response.body) + else + return response.body + end + else + puts "Error: #{response.body}" + err = create_error_object(response.body["error"],response.body["reason"],response.body["detail"],"") + if callback != nil + callback.call(err) + else + return err + end + end + end + + private + # internal utilitiy method + def valid_json?(json) + begin + JSON.parse(json) + return true + rescue JSON::ParserError => e + return false + end + end + def create_error_object(error,reason,detail,jobID) + errorObj = {} + errorObj["error"] = error + errorObj["reason"] = reason + errorObj["detail"] = detail + errorObj["jobID"] = jobID + return errorObj + end +end diff --git a/lib/hoderrorcode.rb b/lib/hoderrorcode.rb new file mode 100644 index 0000000..f550d53 --- /dev/null +++ b/lib/hoderrorcode.rb @@ -0,0 +1,13 @@ +class ErrorCode + TIMEOUT = 1600 + IN_PROGRESS = 1610 + QUEUED = 1620 + NONSTANDARD_RESPONSE = 1630 + INVALID_PARAM = 1640 + INVALID_HOD_RESPONSE = 1650 + UNKNOWN_ERROR = 1660 + HTTP_ERROR = 1670 + CONNECTION_ERROR = 1680 + IO_ERROR = 1690 + HOD_CLIENT_BUSY = 1700 +end diff --git a/lib/hodresponseparser.rb b/lib/hodresponseparser.rb new file mode 100644 index 0000000..8890818 --- /dev/null +++ b/lib/hodresponseparser.rb @@ -0,0 +1,88 @@ +require File.join(File.dirname(__FILE__), "/hoderrorcode.rb") + +class HODResponseParser + @errors + def initialize() + @errors = [] + end + + def parse_jobid(response) + @errors = [] + puts response + if response.has_key? "jobID" and response["jobID"].length > 0 + return response["jobID"] + else + if response.has_key? "error" and response.has_key? "reason" + detail = "" + if response.has_key? "detail" + detail = response["detail"] + create_error_object(response["error"], response["reason"],detail,"") + end + else + create_error_object(ErrorCode::INVALID_HOD_RESPONSE, "Invalid HOD response","","") + end + return nil + end + end +# + def parse_payload(response) + @errors = [] + if response.has_key? "actions" + actions = response["actions"] + status = actions[0]["status"] + if status == "queued" + create_error_object(ErrorCode::QUEUED, "Task is queued","", response["jobID"]) + return nil + elsif status == "in progress" + create_error_object(ErrorCode::IN_PROGRESS, "Task is in progress","", response["jobID"]) + return nil + elsif status == "failed" + errors = actions[0]["errors"] + if errors.kind_of?(Array) + errors.each { |error| + detail = "" + if error.has_key? "detail" + detail = error["detail"] + end + create_error_object(error["error"], error["reason"],detail,error["jobID"]) + } + else + detail = "" + if errors.has_key? "detail" + detail = errors["detail"] + end + create_error_object(errors["error"], errors["reason"],detail,errors["jobID"]) + end + return nil + else + return actions[0]["result"] + end + else + # must make sure this is an error message. Not just an error key from a good result + if response.has_key? "error" and response.has_key? "reason" + detail = "" + if response.has_key? "detail" + detail = response["detail"] + create_error_object(response["error"], response["reason"],detail,"") + return nil + end + else + return response + end + end + end + + def get_last_errors() + return @errors + end +# + private + def create_error_object(error,reason,detail,jobID) + errorObj = {} + errorObj["error"] = error + errorObj["reason"] = reason + errorObj["detail"] = detail + errorObj["jobID"] = jobID + @errors.push(errorObj) + end +end diff --git a/lib/iodruby.rb b/lib/iodruby.rb deleted file mode 100644 index 1e9453e..0000000 --- a/lib/iodruby.rb +++ /dev/null @@ -1,364 +0,0 @@ - - -require 'Unirest' -require 'json' -#require 'httpclient' - - - - - - -class IODError < StandardError - -end - - - -class IODResponse - - attr_accessor :response - - def initialize(response) - #@query=query - - @response=response - end - - def json() - @response.body - end - -end - -class IODAsyncResponse < IODResponse - - attr_accessor :response - attr_accessor :jobID - def initialize(response,client) - #@query=query - @response=response - @client=client - @jobID =response.body["jobID"] - end - - def status() - @client.getStatus(@jobID) - end - - def result() - @client.getResult(@jobID) - end - -end - - - -class IODClient - @@version=1 - @@apidefault=1 - def initialize(url, apikey) - # Instance variables - - @url = url - @apikey = apikey - - end - - - def getStatus(jobID) - data={"apikey"=>@apikey} - response=Unirest.post "#{@url}/#{@@version}/job/status/#{jobID}", - headers:{ "Accept" => "application/json" }, - parameters:data - return IODResponse.new(response) - - end - - def getResult(jobID) - data={"apikey"=>@apikey} - response=Unirest.post "#{@url}/#{@@version}/job/result/#{jobID}", - headers:{ "Accept" => "application/json" }, - parameters:data - return IODResponse.new(response) - end - - def deleteIndex(index) - if index.class.name=="IODIndex" - index=index.name - end - - data=Hash.new - data[:index]=index - - delete=post("deletetextindex",data) - confirm=delete.json()["confirm"] - data[:confirm]=confirm - delete=post("deletetextindex",data) - return delete - end - - def deleteConnector(connector) - data=connectorUtil(connector) - delete=post("deleteconnector",data) - return delete - end - - - def connectorUtil(connector) - if index.class.name=="IODConnector" - connector=connector.name - end - data=Hash.new - data[:connector]=connector - return data - end - - - def startConnector(connector) - data=connectorUtil(connector) - return post("startconnector",data) - end - - def retrieveConnectorConfig(connector) - data=connectorUtil(connector) - return post("retrieveconfig",data) - end - - def connectorstatus(connector) - data=connectorUtil(connector) - return post("connectorstatus",data) - end - - def post(handler, data=Hash.new, async=false) - data[:apikey]=@apikey - syncpath="sync" - if async - syncpath="async" - end - Unirest.timeout(30) - response=Unirest.post "#{@url}/#{@@version}/api/#{syncpath}/#{handler}/v#{@@apidefault}", - headers:{ "Accept" => "application/json" }, - parameters:data - if response.code == 200 - - if async - return IODAsyncResponse.new(response,self) - end - return IODResponse.new(response) - else - puts response.body - #puts data[:json].encoding.name - raise IODError.new "Error #{response.body["error"]} -- #{response.body["reason"]}" - end - end - - - - def getIndex(name) - #indexes=self.listIndexes() - - index=IODIndex.new(name,client:self) - #puts (index in indexes) - - end - - - - def createIndex(name,flavor="standard",parametric_fields=[],index_fields=[]) - data=Hash.new - data[:index]=name - data[:flavor]=flavor - data[:parametric_fields]=parametric_fields - data[:index_fields]=index_fields - self.post("createtextindex",data) - return IODIndex.new(name,client:self) - end - - def listIndexes() - r=post("listindex") - - indexes=r["index"].map { |index| IODIndex.new(index["index"],index["flavor"],index["type"],client:self)} - - end - - - def addDoc(doc, index) - self.addDocs([doc],index) - end - - def addDocs(docs, index,async=false) - - - # puts docs - # puts docs.length - #jsondocs= docs.map { |doc| doc.data} - jsondocs=docs - #puts jsondocs - docs=Hash.new - docs[:documents]=jsondocs - - #puts docs.to_json - docs=docs.to_json - puts docs.length - #puts docs - #docs=render :json => JSON::dump(docs) - data={json:docs,index:index} - - return self.post("addtotextindex",data,async) - end - -end - -class IODConnector - - attr_reader :client - attr_reader :name - - - def initialize(name,client=nil) - @name=name - @client=client - end - - def create(type="web",config=Hash.new, destination="", schedule="",description="") - config("addtotextindex",type,config,destination,schedule,description) - end - - - def update(type="web",config=Hash.new, destination="", schedule="",description="") - config("addtotextindex",type,config,destination,schedule,description) - end - - def config(method,type="",config="", destination="", schedule="",description="") - data=Hash.new - data[:connector]=@name - if type!="" - data[:type]=type - end - if config!="" - data[:config]=JSON.dump config - end - if destination!="" - destination={"action"=>"addtotextindex", "index" => destination } - data[:destination]=JSON.dump destination - end - if schedule != "" - data[:schedule]=JSON.dump schedule - end - data[:description]=description - result=@client.post(method,data) - puts result - end - - def delete() - @client.deleteConnector(@name) - end - - def config() - @client.retrieveConnectorConfig(@name) - end - - def status() - @client.connectorStatus(@name) - end - - def ==(other_object) - comparison_object.equal?(self) || (comparison_object.instance_of?(self.class) && @name == other_object.name) - end -end - - - - - -class IODIndex - - attr_reader :client - attr_reader :name - - - def initialize(name,flavor="standard",type="normal",client:nil) - @name=name - - @client=client - @docs=[] - end - - def query(text,data=Hash.new) - data[:database_match]=@name - - data[:text]=text - result=@client.post("querytextindex",data) - result["documents"].map!{|doc| IODDoc.new(doc) } - return result - end - def size() - return @docs.length - end - def pushDoc(doc) - @docs.push(doc) - - end - - def commit(async=false) -# docs={document:@docs} -# data={json:docs.to_json,index:@name} -# puts docs.to_json - - #r=@client.post("addtotextindex",data) - #@docs=[] - response=addDocs(@docs,async) - @docs=[] - return response - end - - def addDoc(doc) - docs=Hash.new - -# docs[:document]=[doc.data] -# data={json:docs.to_json,index:@name} -# @client.postasync("addtotextindex",data) - puts @client.addDoc(doc,@name) - end - - - def addDocs(docs,async=false) - -# docs[:document]=[doc.data] -# data={json:docs.to_json,index:@name} -# @client.postasync("addtotextindex",data) - - return @client.addDocs(docs,@name,async) - end - - def delete() - clientcheck() - @client.deleteIndex(self) - end - - def ==(other_object) - comparison_object.equal?(self) || (comparison_object.instance_of?(self.class) && @name == other_object.name) - end -end - - - -class IODDoc - - attr_accessor :data - attr_accessor :sentiment - attr_accessor :entities - def initialize(data) - #@query=query - @entities=Hash.new - @data=data - end - - def to_json(options={}) - return render :json => JSON::dump(@data) - end - - - -end diff --git a/lib/iodruby/.DS_Store b/lib/iodruby/.DS_Store deleted file mode 100644 index 41b3b16..0000000 Binary files a/lib/iodruby/.DS_Store and /dev/null differ diff --git a/lib/iodruby/version.rb b/lib/iodruby/version.rb deleted file mode 100644 index fcf6789..0000000 --- a/lib/iodruby/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module Iodruby - VERSION = "0.0.1" -end