i2x 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +17 -0
- data/LICENSE +22 -0
- data/README.md +31 -0
- data/Rakefile +12 -0
- data/i2x.gemspec +21 -0
- data/lib/i2x.rb +6 -5
- data/lib/i2x/cashier.rb +77 -0
- data/lib/i2x/checkup.rb +37 -0
- data/lib/i2x/client.rb +13 -0
- data/lib/i2x/csvdetector.rb +53 -0
- data/lib/i2x/csvseedreader.rb +47 -0
- data/lib/i2x/detector.rb +109 -0
- data/lib/i2x/helper.rb +153 -0
- data/lib/i2x/jsondetector.rb +64 -0
- data/lib/i2x/jsonseedreader.rb +52 -0
- data/lib/i2x/seedreader.rb +21 -0
- data/lib/i2x/sqldetector.rb +48 -0
- data/lib/i2x/sqlseedreader.rb +47 -0
- data/lib/i2x/version.rb +3 -0
- data/lib/i2x/xmldetector.rb +57 -0
- data/lib/i2x/xmlseedreader.rb +52 -0
- data/test/lib/i2x/version_test.rb +9 -0
- data/test/test_helper.rb +4 -0
- metadata +63 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 335a577dfae00f0024b44efe43882721190a5397
|
4
|
+
data.tar.gz: 0ea51a5523b9f0a2b52b001ff853b5219b0a5cbc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b835461966de12b01bb793e512d105f48186408f08529e0b163ff14cd39d7580d9c2215b023b3474dc00d614141bd4140221bdd262dcd69560b525fd35ab87ec
|
7
|
+
data.tar.gz: fb868fdbe8c44735db9d2b831343d90e2a8d2fc71dd1c3460917bad87545c873222c1e65494249da1439943b6aa7a7390c9ea0ae27b1da342bea9fa226bbce65
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Pedro Lopes
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# I2X
|
2
|
+
|
3
|
+
### Automated real-time integration
|
4
|
+
|
5
|
+
Ruby gem for distributed client agents.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'i2x'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install i2x
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( http://github.com/pdrlps/i2x-gem/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/i2x.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'i2x/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "i2x"
|
8
|
+
spec.version = I2X::VERSION
|
9
|
+
spec.authors = ["Pedro Lopes"]
|
10
|
+
spec.email = ["hello@pedrolopes.net"]
|
11
|
+
spec.summary = %q{i2x client library for distributed agents.}
|
12
|
+
spec.description = %q{i2x: integrate everything. Automated real-time integration framework.}
|
13
|
+
spec.homepage = "https://bioinformatics.ua.pt/i2x/"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
20
|
+
spec.add_development_dependency "rake"
|
21
|
+
end
|
data/lib/i2x.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require_relative "./i2x/version"
|
2
|
+
require_relative "./i2x/client"
|
3
|
+
|
4
|
+
module I2X
|
5
|
+
|
6
|
+
end
|
data/lib/i2x/cashier.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'slog'
|
2
|
+
|
3
|
+
|
4
|
+
module Services
|
5
|
+
class Cashier
|
6
|
+
|
7
|
+
|
8
|
+
public
|
9
|
+
|
10
|
+
##
|
11
|
+
# = Verify
|
12
|
+
# => Verify if items have already been seen in the past (on the cache).
|
13
|
+
#
|
14
|
+
# == Params
|
15
|
+
# - *memory*: the key identifier to be verified
|
16
|
+
# - *payload*: the value for matching/verification
|
17
|
+
# - *agent*: the agent performing the verification
|
18
|
+
# - *seed*: seed data (if available)
|
19
|
+
#
|
20
|
+
def self.verify memory, agent, payload, seed
|
21
|
+
##
|
22
|
+
# => Redis implementation, use cache.
|
23
|
+
#
|
24
|
+
begin
|
25
|
+
|
26
|
+
# if Redis is enabled...
|
27
|
+
if ENV["CACHE_REDIS"] then
|
28
|
+
# give me some cache!
|
29
|
+
@redis = Redis.new :host => ENV["CACHE_HOST"], :port => ENV["CACHE_PORT"]
|
30
|
+
end
|
31
|
+
rescue Exception => e
|
32
|
+
Services::Slog.exception e
|
33
|
+
end
|
34
|
+
|
35
|
+
# the actual verification
|
36
|
+
if ENV["CACHE_REDIS"] then
|
37
|
+
# commented, do not log all cache verifications
|
38
|
+
#Services::Slog.debug({:message => "Verifying cache", :module => "Cashier", :task => "cache", :extra => {:agent => agent[:identifier], :memory => memory, :payload => payload, :seed => seed}})
|
39
|
+
begin
|
40
|
+
if @redis.hexists("#{agent[:identifier]}:#{seed}","#{memory}") then
|
41
|
+
response = {:status => 200, :message => "[i2x][Cashier] Nothing to update"}
|
42
|
+
else
|
43
|
+
@redis.hset("#{agent[:identifier]}:#{seed}", "#{memory}", payload)
|
44
|
+
response = {:status => 100, :message => "[i2x][Cashier] Memory recorded to cache"}
|
45
|
+
end
|
46
|
+
rescue Exception => e
|
47
|
+
response = {:message => "[i2x][Cashier] unable to verify cache content, #{e}", :status => 301}
|
48
|
+
Services::Slog.exception e
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# => SQL implementation, use internal database.
|
54
|
+
#
|
55
|
+
# => To Do: Recheck implementation.
|
56
|
+
#
|
57
|
+
if ENV["CACHE_INTERNAL"] then
|
58
|
+
results = Cache.where memory: memory, agent_id: agent.id, seed: seed
|
59
|
+
if results.size == 0 then
|
60
|
+
begin
|
61
|
+
@cached = Cache.new({:memory => memory, :agent_id => agent.id, :payload => payload, :seed => seed})
|
62
|
+
@cached.save
|
63
|
+
response = {:status => 100, :message => "[i2x][Cashier] Memory recorded to cache"}
|
64
|
+
rescue Exception => e
|
65
|
+
response = {:message => "[i2x][Cashier] unable to save new cache content, #{e}", :status => 300}
|
66
|
+
Services::Slog.exception e
|
67
|
+
end
|
68
|
+
else
|
69
|
+
response = {:status => 200, :message => "[i2x][Cashier] Nothing to update"}
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
response
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/i2x/checkup.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module I2X
|
2
|
+
class Checkup
|
3
|
+
|
4
|
+
##
|
5
|
+
# = Perform the actual check execution
|
6
|
+
#
|
7
|
+
# + *agent*: the agent to verify
|
8
|
+
#
|
9
|
+
def execute agent
|
10
|
+
begin
|
11
|
+
@response = agent.execute
|
12
|
+
rescue Exception => e
|
13
|
+
|
14
|
+
@response = {:status => 400, :error => e}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
##
|
20
|
+
# = Initiate real-time (poll) check
|
21
|
+
#
|
22
|
+
# + *schedule*: the scheduling being checked
|
23
|
+
def check schedule
|
24
|
+
Integration.all.each do |integration|
|
25
|
+
@agents = integration.agents.where( :schedule => schedule).where("last_check_at < CURRENT_TIMESTAMP - INTERVAL 5 MINUTE")
|
26
|
+
@agents.each do |agent|
|
27
|
+
begin
|
28
|
+
self.execute agent
|
29
|
+
rescue Exception => e
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/i2x/client.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'csv'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'seedreader'
|
5
|
+
require 'csvseedreader'
|
6
|
+
require 'sqlseedreader'
|
7
|
+
require 'xmlseedreader'
|
8
|
+
require 'jsonseedreader'
|
9
|
+
|
10
|
+
module I2X
|
11
|
+
|
12
|
+
##
|
13
|
+
# = CSVDetector
|
14
|
+
#
|
15
|
+
# Detect changes in CSV files (using column numbers).
|
16
|
+
#
|
17
|
+
class CSVDetector < Detector
|
18
|
+
|
19
|
+
public
|
20
|
+
##
|
21
|
+
# == Detect the changes
|
22
|
+
#
|
23
|
+
def detect object
|
24
|
+
begin
|
25
|
+
CSV.new(open(object[:uri]), :headers => :first_row).each do |row|
|
26
|
+
unless object[:cache].nil? then
|
27
|
+
@cache = Cashier.verify row[object[:cache].to_i], object, row, object[:seed]
|
28
|
+
else
|
29
|
+
@cache = Cashier.verify row[0], object, row, object[:seed]
|
30
|
+
end
|
31
|
+
# The actual processing
|
32
|
+
#
|
33
|
+
if @cache[:status] == 100 then
|
34
|
+
|
35
|
+
# add row data to payload from selectors (key => key, value => column name)
|
36
|
+
payload = Hash.new
|
37
|
+
JSON.parse(object[:selectors]).each do |selector|
|
38
|
+
selector.each do |k,v|
|
39
|
+
payload[k] = row[v.to_i]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
# add payload object to payloads list
|
43
|
+
@payloads.push payload
|
44
|
+
end
|
45
|
+
end
|
46
|
+
rescue Exception => e
|
47
|
+
I2X::Slog.exception e
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module I2X
|
4
|
+
|
5
|
+
# = CSVSeedReader
|
6
|
+
#
|
7
|
+
# Load content from CSV seed.
|
8
|
+
#
|
9
|
+
class CSVSeedReader < SeedReader
|
10
|
+
##
|
11
|
+
# == Read
|
12
|
+
#
|
13
|
+
# => Load the seed data into the @objects array for processing.
|
14
|
+
#
|
15
|
+
def read
|
16
|
+
begin
|
17
|
+
CSV.new(open(@seed[:payload][:uri]), :headers => :first_row).each do |row|
|
18
|
+
begin
|
19
|
+
object = @help.deep_copy @agent[:payload]
|
20
|
+
object.each_pair do |key,value|
|
21
|
+
variables = @help.identify_variables(object[key])
|
22
|
+
variables.each do |v|
|
23
|
+
object[key].gsub!("%{#{v}}", row[@seed[:payload][:selectors][v].to_i])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
unless @seed[:payload][:cache].nil? then
|
28
|
+
object[:seed] = row[@seed[:payload][:cache].to_i]
|
29
|
+
else
|
30
|
+
object[:seed] = row[0]
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
object[:identifier] = @agent.identifier
|
35
|
+
@objects.push object
|
36
|
+
rescue Exception => e
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
rescue Exception => e
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
@objects
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/i2x/detector.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'seedreader'
|
2
|
+
require 'csvseedreader'
|
3
|
+
require 'sqlseedreader'
|
4
|
+
require 'xmlseedreader'
|
5
|
+
require 'jsonseedreader'
|
6
|
+
|
7
|
+
|
8
|
+
module I2X
|
9
|
+
|
10
|
+
##
|
11
|
+
# = Detector
|
12
|
+
#
|
13
|
+
# Main change detection class, to be inherited by SQL, CSV, JSON and XML detectors (and others to come).
|
14
|
+
#
|
15
|
+
class Detector
|
16
|
+
attr_accessor :identifier, :agent, :objects, :payloads, :content
|
17
|
+
|
18
|
+
def initialize identifier
|
19
|
+
begin
|
20
|
+
@agent = Agent.find_by! identifier: identifier
|
21
|
+
@payloads = Array.new
|
22
|
+
@objects = Array.new
|
23
|
+
@help = I2X::Helper.new
|
24
|
+
rescue Exception => e
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
##
|
31
|
+
# == Start original source detection process
|
32
|
+
#
|
33
|
+
def checkup
|
34
|
+
# update checkup time
|
35
|
+
@agent.update_check_at @help.datetime
|
36
|
+
|
37
|
+
begin
|
38
|
+
|
39
|
+
##
|
40
|
+
# => Process seed data, if available.
|
41
|
+
#
|
42
|
+
if @agent.seeds.size != 0 then
|
43
|
+
@agent.seeds.each do |seed|
|
44
|
+
case seed[:publisher]
|
45
|
+
when 'csv'
|
46
|
+
begin
|
47
|
+
@sr = I2X::CSVSeedReader.new(@agent, seed)
|
48
|
+
rescue Exception => e
|
49
|
+
|
50
|
+
end
|
51
|
+
when 'sql'
|
52
|
+
begin
|
53
|
+
@sr = I2X::SQLSeedReader.new(@agent, seed)
|
54
|
+
rescue Exception => e
|
55
|
+
|
56
|
+
end
|
57
|
+
when 'xml'
|
58
|
+
begin
|
59
|
+
@sr = I2X::XMLSeedReader.new(@agent, seed)
|
60
|
+
rescue Exception => e
|
61
|
+
|
62
|
+
end
|
63
|
+
when 'json'
|
64
|
+
begin
|
65
|
+
@sr = I2X::JSONSeedReader.new(@agent, seed)
|
66
|
+
rescue Exception => e
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
begin
|
71
|
+
@reads = @sr.read
|
72
|
+
@reads.each do |read|
|
73
|
+
@objects.push read
|
74
|
+
end
|
75
|
+
rescue Exception => e
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
else
|
81
|
+
##
|
82
|
+
# no seeds, simply copy agent data
|
83
|
+
object = @help.deep_copy @agent[:payload]
|
84
|
+
object[:identifier] = @agent[:identifier]
|
85
|
+
object[:seed] = object[:identifier]
|
86
|
+
unless self.content.nil? then
|
87
|
+
object[:content] = self.content
|
88
|
+
end
|
89
|
+
@objects.push object
|
90
|
+
end
|
91
|
+
rescue Exception => e
|
92
|
+
@response = {:status => 404, :message => "[i2x][Detector] failed to load doc, #{e}"}
|
93
|
+
I2X::Slog.exception e
|
94
|
+
end
|
95
|
+
|
96
|
+
begin
|
97
|
+
# increase detected events count
|
98
|
+
@agent.increment!(:events_count, @payloads.size)
|
99
|
+
@response = { :payload => @payloads, :status => 100}
|
100
|
+
rescue Exception => e
|
101
|
+
@response = {:status => 404, :message => "[i2x][Detector] failed to process queries, #{e}"}
|
102
|
+
I2X::Slog.exception e
|
103
|
+
end
|
104
|
+
@response
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
data/lib/i2x/helper.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'slog'
|
2
|
+
|
3
|
+
module I2X
|
4
|
+
|
5
|
+
##
|
6
|
+
# = Helper Class
|
7
|
+
# => Miscellaneous helper methods and utils to deal with data.
|
8
|
+
#
|
9
|
+
class Helper
|
10
|
+
attr_accessor :replacements
|
11
|
+
@replacements
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
# load each helper function into a map for replacement in the delivery
|
15
|
+
@replacements = [ ["%{i2x.date}", self.date], ["%{i2x.datetime}", self.datetime], ["%{i2x.hostname}", self.hostname]]
|
16
|
+
end
|
17
|
+
|
18
|
+
public
|
19
|
+
def hostname
|
20
|
+
ENV["APP_HOST"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def datetime
|
24
|
+
Time.now.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def date
|
28
|
+
Time.now.strftime("%Y-%m-%d").to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# == Identify Variables
|
33
|
+
# => Identifies variables on string set, generates array with all scanned variables for processing.
|
34
|
+
# => Variables are enclosed in %{variable} string.
|
35
|
+
#
|
36
|
+
# * +text+ - string to be scanned
|
37
|
+
#
|
38
|
+
def identify_variables text
|
39
|
+
begin
|
40
|
+
results = Array.new
|
41
|
+
text.scan(/%{(.*?)}/).each do |m|
|
42
|
+
results.push m[0]
|
43
|
+
end
|
44
|
+
rescue Exception => e
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
results
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# == Validate payload
|
53
|
+
# => Validates content payload.
|
54
|
+
#
|
55
|
+
# + *publisher* - for publisher-specific validations
|
56
|
+
# + *payload* - content for validation
|
57
|
+
#
|
58
|
+
def self.validate_payload publisher, payload
|
59
|
+
@database_servers = ["mysql","sqlite","postgresql"]
|
60
|
+
valid = true
|
61
|
+
|
62
|
+
begin
|
63
|
+
case publisher
|
64
|
+
when 'csv', 'xml', 'json', 'file', 'js'
|
65
|
+
# file content URI is mandatory
|
66
|
+
if payload[:uri].nil? then
|
67
|
+
valid = false
|
68
|
+
end
|
69
|
+
when 'sql'
|
70
|
+
|
71
|
+
# check if database server is available
|
72
|
+
unless database_servers.include? payload[:server] then
|
73
|
+
valid = false
|
74
|
+
end
|
75
|
+
|
76
|
+
# database username is mandatory
|
77
|
+
if payload[:username].nil? then
|
78
|
+
valid = false
|
79
|
+
end
|
80
|
+
|
81
|
+
# database user password is mandatory
|
82
|
+
if payload[:password].nil? then
|
83
|
+
valid = false
|
84
|
+
end
|
85
|
+
|
86
|
+
# database name is mandatory
|
87
|
+
if payload[:database].nil? then
|
88
|
+
valid = false
|
89
|
+
end
|
90
|
+
|
91
|
+
# database query is mandatory
|
92
|
+
if payload[:query].nil? then
|
93
|
+
valid = false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
rescue Exception => e
|
97
|
+
|
98
|
+
end
|
99
|
+
valid
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# == Validate Seed
|
104
|
+
# => Validates Seed-specific properties
|
105
|
+
#
|
106
|
+
# + *publisher* - for publisher-specific validations
|
107
|
+
# + *seed* - the seed hash
|
108
|
+
#
|
109
|
+
def self.validate_seed publisher, seed
|
110
|
+
begin
|
111
|
+
valid = self.validate_payload publisher, seed
|
112
|
+
if valid then
|
113
|
+
# seed must have selectors
|
114
|
+
if seed[:selectors].nil? then
|
115
|
+
valid = false
|
116
|
+
end
|
117
|
+
else
|
118
|
+
valid = false
|
119
|
+
end
|
120
|
+
rescue Exception => e
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
valid
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# == Validate Agent
|
129
|
+
# => Validates Agent-specific properties
|
130
|
+
#
|
131
|
+
# + *agent* - the agent for validation
|
132
|
+
#
|
133
|
+
def self.validate_agent
|
134
|
+
begin
|
135
|
+
valid = self.validate_seed(agent[:publisher], agent[:payload]) && self.validate_payload(agent[:publisher], agent[:payload])
|
136
|
+
rescue Exception => e
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
valid
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# == Copy Object/Hash/Array...
|
145
|
+
# => Copies any object into new object (overcome references).
|
146
|
+
#
|
147
|
+
# + *o* - the object being copied
|
148
|
+
#
|
149
|
+
def deep_copy object
|
150
|
+
Marshal.load(Marshal.dump(object))
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'jsonpath'
|
4
|
+
require 'rest-client'
|
5
|
+
require 'csv'
|
6
|
+
require 'json'
|
7
|
+
require 'seedreader'
|
8
|
+
require 'csvseedreader'
|
9
|
+
require 'sqlseedreader'
|
10
|
+
require 'xmlseedreader'
|
11
|
+
require 'jsonseedreader'
|
12
|
+
|
13
|
+
module I2X
|
14
|
+
|
15
|
+
# = JSONDetector
|
16
|
+
#
|
17
|
+
# Detect changes in JSON content files (uses JSONPath).
|
18
|
+
#
|
19
|
+
class JSONDetector < Detector
|
20
|
+
|
21
|
+
public
|
22
|
+
|
23
|
+
##
|
24
|
+
# == Detect the changes
|
25
|
+
#
|
26
|
+
def detect object
|
27
|
+
begin
|
28
|
+
if object[:uri] == '' then
|
29
|
+
@doc = object[:content]
|
30
|
+
else
|
31
|
+
url = RestClient.get object[:uri]
|
32
|
+
@doc = url.to_str
|
33
|
+
end
|
34
|
+
JsonPath.on(@doc,object[:query]).each do |element|
|
35
|
+
JsonPath.on(element, object[:cache]).each do |c|
|
36
|
+
@cache = Cashier.verify c, object, c, object[:seed]
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# If not on cache, add to payload for processing
|
41
|
+
#
|
42
|
+
if @cache[:status] == 100 then
|
43
|
+
|
44
|
+
# add row data to payload from selectors (key => key, value => column name)
|
45
|
+
payload = Hash.new
|
46
|
+
JSON.parse(object[:selectors]).each do |selector|
|
47
|
+
selector.each do |k,v|
|
48
|
+
JsonPath.on(element, v).each do |el|
|
49
|
+
payload[k] = el
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
# add payload object to payloads list
|
54
|
+
@payloads.push payload
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
rescue Exception => e
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module I2X
|
4
|
+
|
5
|
+
# = JSONSeedReader
|
6
|
+
#
|
7
|
+
# Load content from JSON seed.
|
8
|
+
#
|
9
|
+
class JSONSeedReader < SeedReader
|
10
|
+
##
|
11
|
+
# == Read
|
12
|
+
#
|
13
|
+
# => Load the seed data into the @objects array for processing.
|
14
|
+
#
|
15
|
+
def read
|
16
|
+
begin
|
17
|
+
url = RestClient.get @seed[:payload][:uri]
|
18
|
+
@doc = url.to_str
|
19
|
+
JsonPath.on(@doc,@seed[:payload][:query]).each do |element|
|
20
|
+
|
21
|
+
begin
|
22
|
+
object = @help.deep_copy @agent[:payload]
|
23
|
+
object.each_pair do |key,value|
|
24
|
+
variables = @help.identify_variables(object[key])
|
25
|
+
variables.each do |v|
|
26
|
+
|
27
|
+
JsonPath.on(element, @seed[:payload][:selectors][v]).each do |el|
|
28
|
+
|
29
|
+
object[key].gsub!("%{#{v}}", el.to_s)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
JsonPath.on(element,@seed[:payload][:cache]).each do |el|
|
35
|
+
object[:seed] = el
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
object[:identifier] = @agent.identifier
|
40
|
+
@objects.push object
|
41
|
+
rescue Exception => e
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue Exception => e
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
@objects
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module I2X
|
4
|
+
|
5
|
+
##
|
6
|
+
# = Seed Reader
|
7
|
+
#
|
8
|
+
# Main seed reading class, passing data for seeds to agent, to be inherited by SQL, File and URL templates
|
9
|
+
#
|
10
|
+
class SeedReader
|
11
|
+
attr_accessor :seed, :objects, :agent
|
12
|
+
|
13
|
+
def initialize agent, seed
|
14
|
+
@agent = agent
|
15
|
+
@help = I2X::Helper.new
|
16
|
+
@seed = seed
|
17
|
+
@objects = Array.new
|
18
|
+
puts "\t\tSeed: #{@seed[:identifier]}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'mysql2'
|
3
|
+
|
4
|
+
module I2X
|
5
|
+
|
6
|
+
##
|
7
|
+
# = SQLDetector
|
8
|
+
#
|
9
|
+
# Detec changes in SQL databases. MySQL support only.
|
10
|
+
#
|
11
|
+
class SQLDetector < Detector
|
12
|
+
|
13
|
+
public
|
14
|
+
##
|
15
|
+
# == Detect the changes
|
16
|
+
#
|
17
|
+
def detect object
|
18
|
+
puts "Detecting SQL to #{object[:identifier]}"
|
19
|
+
begin
|
20
|
+
@client = Mysql2::Client.new(:host => object[:host], :username => object[:username] , :password => object[:password] , :database => object[:database])
|
21
|
+
@client.query(@agent[:payload][:query]).each(:symbolize_keys => false) do |row|
|
22
|
+
unless object[:cache].nil? then
|
23
|
+
@cache = Cashier.verify row[object[:cache]], object, row, object[:seed]
|
24
|
+
else
|
25
|
+
@cache = Cashier.verify row["id"], object, row, object[:seed]
|
26
|
+
end
|
27
|
+
|
28
|
+
# The actual processing
|
29
|
+
#
|
30
|
+
if @cache[:status] == 100 then
|
31
|
+
|
32
|
+
# add row data to payload from selectors (key => key, value => column name)
|
33
|
+
payload = Hash.new
|
34
|
+
JSON.parse(object[:selectors]).each do |selector|
|
35
|
+
selector.each do |k,v|
|
36
|
+
payload[k] = row[v]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
# add payload object to payloads list
|
40
|
+
@payloads.push payload
|
41
|
+
end
|
42
|
+
end
|
43
|
+
rescue Exception => e
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'slog'
|
2
|
+
require 'mysql2'
|
3
|
+
|
4
|
+
module Services
|
5
|
+
|
6
|
+
# = SQLSeedReader
|
7
|
+
#
|
8
|
+
# Load content from SQL seed.
|
9
|
+
#
|
10
|
+
class SQLSeedReader < SeedReader
|
11
|
+
##
|
12
|
+
# == Read
|
13
|
+
#
|
14
|
+
# => Load the seed data into the @objects array for processing.
|
15
|
+
#
|
16
|
+
def read
|
17
|
+
begin
|
18
|
+
@client = Mysql2::Client.new(:host => @seed[:payload][:host], :username => @seed[:payload][:username] , :password => @seed[:payload][:password] , :database => @seed[:payload][:database])
|
19
|
+
@client.query(@seed[:payload][:query], :cast => false).each(:symbolize_keys => false) do |row|
|
20
|
+
begin
|
21
|
+
object = @help.deep_copy @agent[:payload]
|
22
|
+
object.each_pair do |key,value|
|
23
|
+
variables = @help.identify_variables(object[key])
|
24
|
+
variables.each do |v|
|
25
|
+
object[key].gsub!("%{#{v}}", row[@seed[:payload][:selectors][v]].to_str)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
unless @seed[:payload][:cache].nil? then
|
30
|
+
object[:seed] = row[@seed[:payload][:cache]]
|
31
|
+
else
|
32
|
+
object[:seed] = row["id"]
|
33
|
+
end
|
34
|
+
object[:identifier] = @agent.identifier
|
35
|
+
@objects.push object
|
36
|
+
rescue Exception => e
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
rescue Exception => e
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
@objects
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/i2x/version.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'cashier'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'raven'
|
5
|
+
require 'slog'
|
6
|
+
|
7
|
+
module I2X
|
8
|
+
|
9
|
+
# = XMLDetector
|
10
|
+
#
|
11
|
+
# Detect changes in XML files (uses XPath).
|
12
|
+
#
|
13
|
+
class XMLDetector < Detector
|
14
|
+
|
15
|
+
public
|
16
|
+
##
|
17
|
+
# == Detect the changes
|
18
|
+
#
|
19
|
+
def detect object
|
20
|
+
begin
|
21
|
+
if object[:uri] == '' then
|
22
|
+
@doc = Nokogiri::XML(object[:content])
|
23
|
+
else
|
24
|
+
@doc = Nokogiri::XML(open(object[:uri]))
|
25
|
+
end
|
26
|
+
@doc.remove_namespaces!
|
27
|
+
@doc.xpath(object[:query]).each do |element|
|
28
|
+
element.xpath(object[:cache]).each do |c|
|
29
|
+
@cache = Cashier.verify c.content, object, c.content, object[:seed]
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# If not on cache, add to payload for processing
|
34
|
+
#
|
35
|
+
if @cache[:status] == 100 then
|
36
|
+
|
37
|
+
# add row data to payload from selectors (key => key, value => column name)
|
38
|
+
payload = Hash.new
|
39
|
+
JSON.parse(object[:selectors]).each do |selector|
|
40
|
+
|
41
|
+
selector.each do |k,v|
|
42
|
+
element.xpath(v).each do |el|
|
43
|
+
payload[k] = el.content
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
# add payload object to payloads list
|
48
|
+
@payloads.push payload
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
rescue Exception => e
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module I2X
|
2
|
+
|
3
|
+
# = XMLSeedReader
|
4
|
+
#
|
5
|
+
# Load content from XML seed.
|
6
|
+
#
|
7
|
+
class XMLSeedReader < SeedReader
|
8
|
+
##
|
9
|
+
# == Read
|
10
|
+
#
|
11
|
+
# => Load the seed data into the @objects array for processing.
|
12
|
+
#
|
13
|
+
def read
|
14
|
+
begin
|
15
|
+
@doc = Nokogiri::XML(open(@seed[:payload][:uri]))
|
16
|
+
@doc.remove_namespaces!
|
17
|
+
@doc.xpath(@seed[:payload][:query]).each do |element|
|
18
|
+
begin
|
19
|
+
object = @help.deep_copy @agent[:payload]
|
20
|
+
object.each_pair do |key,value|
|
21
|
+
variables = @help.identify_variables(object[key])
|
22
|
+
variables.each do |v|
|
23
|
+
element.xpath(@seed[:payload][:selectors][v]).each do |el|
|
24
|
+
object[key].gsub!("%{#{v}}", el.content)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
unless @seed[:payload][:cache].nil? then
|
30
|
+
element.xpath(@seed[:payload][:cache]).each do |el|
|
31
|
+
object[:seed] = el.content
|
32
|
+
end
|
33
|
+
else
|
34
|
+
element.xpath('id').each do |el|
|
35
|
+
object[:seed] = el.content
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
object[:identifier] = @agent.identifier
|
40
|
+
@objects.push object
|
41
|
+
rescue Exception => e
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue Exception => e
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
@objects
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,23 +1,76 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i2x
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pedro Lopes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
12
|
-
dependencies:
|
13
|
-
|
14
|
-
|
11
|
+
date: 2014-01-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: 'i2x: integrate everything. Automated real-time integration framework.'
|
42
|
+
email:
|
43
|
+
- hello@pedrolopes.net
|
15
44
|
executables: []
|
16
45
|
extensions: []
|
17
46
|
extra_rdoc_files: []
|
18
47
|
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- LICENSE
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- i2x.gemspec
|
19
55
|
- lib/i2x.rb
|
20
|
-
|
56
|
+
- lib/i2x/cashier.rb
|
57
|
+
- lib/i2x/checkup.rb
|
58
|
+
- lib/i2x/client.rb
|
59
|
+
- lib/i2x/csvdetector.rb
|
60
|
+
- lib/i2x/csvseedreader.rb
|
61
|
+
- lib/i2x/detector.rb
|
62
|
+
- lib/i2x/helper.rb
|
63
|
+
- lib/i2x/jsondetector.rb
|
64
|
+
- lib/i2x/jsonseedreader.rb
|
65
|
+
- lib/i2x/seedreader.rb
|
66
|
+
- lib/i2x/sqldetector.rb
|
67
|
+
- lib/i2x/sqlseedreader.rb
|
68
|
+
- lib/i2x/version.rb
|
69
|
+
- lib/i2x/xmldetector.rb
|
70
|
+
- lib/i2x/xmlseedreader.rb
|
71
|
+
- test/lib/i2x/version_test.rb
|
72
|
+
- test/test_helper.rb
|
73
|
+
homepage: https://bioinformatics.ua.pt/i2x/
|
21
74
|
licenses:
|
22
75
|
- MIT
|
23
76
|
metadata: {}
|
@@ -40,5 +93,7 @@ rubyforge_project:
|
|
40
93
|
rubygems_version: 2.2.0
|
41
94
|
signing_key:
|
42
95
|
specification_version: 4
|
43
|
-
summary:
|
44
|
-
test_files:
|
96
|
+
summary: i2x client library for distributed agents.
|
97
|
+
test_files:
|
98
|
+
- test/lib/i2x/version_test.rb
|
99
|
+
- test/test_helper.rb
|