neoscout 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/.rspec +3 -0
- data/.rvmrc +2 -0
- data/AUTHORS +1 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +138 -0
- data/LICENSE.txt +21 -0
- data/README.md +194 -0
- data/Rakefile +30 -0
- data/TODO.org +27 -0
- data/etc/neo4j.yml +16 -0
- data/lib/neoscout.rb +12 -0
- data/lib/neoscout/constraints.rb +35 -0
- data/lib/neoscout/gdb_neo4j.rb +147 -0
- data/lib/neoscout/json_schema.rb +136 -0
- data/lib/neoscout/main.rb +205 -0
- data/lib/neoscout/model.rb +148 -0
- data/lib/neoscout/scout.rb +119 -0
- data/lib/neoscout/tools.rb +156 -0
- data/lib/neoscout/version.rb +3 -0
- data/neoscout.gemspec +25 -0
- data/root/README.md +3 -0
- data/script/neoscout +15 -0
- data/spec/lib/neoscout/constraints_spec.rb +25 -0
- data/spec/lib/neoscout/gdb_neo4j_spec.rb +81 -0
- data/spec/lib/neoscout/gdb_neo4j_spec_counts.json +282 -0
- data/spec/lib/neoscout/gdb_neo4j_spec_schema.json +46 -0
- data/spec/lib/neoscout/model_spec.rb +42 -0
- data/spec/lib/neoscout/tools_spec.rb +139 -0
- data/spec/spec_helper.rb +5 -0
- metadata +84 -0
data/etc/neo4j.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
neostore.nodestore.db.mapped_memory: 400M
|
2
|
+
neostore.relationshipstore.db.mapped_memory: 1G
|
3
|
+
neostore.propertystore.db.mapped_memory: 4G
|
4
|
+
neostore.propertystore.db.index.mapped_memory: 50M
|
5
|
+
neostore.propertystore.db.index.keys.mapped_memory: 50M
|
6
|
+
neostore.propertystore.db.strings.mapped_memory: 500M
|
7
|
+
neostore.propertystore.db.arrays.mapped_memory: 500M
|
8
|
+
|
9
|
+
# Keeping the defaults here for reference
|
10
|
+
# neostore.nodestore.db.mapped_memory: 25M
|
11
|
+
# neostore.relationshipstore.db.mapped_memory: 50M
|
12
|
+
# neostore.propertystore.db.mapped_memory: 90M
|
13
|
+
# neostore.propertystore.db.index.mapped_memory: 1M
|
14
|
+
# neostore.propertystore.db.index.keys.mapped_memory: 1M
|
15
|
+
# neostore.propertystore.db.strings.mapped_memory: 130M
|
16
|
+
# neostore.propertystore.db.arrays.mapped_memory: 130M
|
data/lib/neoscout.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'neo4j'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
require 'neoscout/version'
|
6
|
+
|
7
|
+
require 'neoscout/tools'
|
8
|
+
require 'neoscout/constraints'
|
9
|
+
require 'neoscout/model'
|
10
|
+
require 'neoscout/json_schema'
|
11
|
+
require 'neoscout/scout'
|
12
|
+
require 'neoscout/gdb_neo4j'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module NeoScout
|
2
|
+
|
3
|
+
module Constraints
|
4
|
+
|
5
|
+
class Constraint
|
6
|
+
def satisfied_by_node?(typer, node) ; satisfied_by?(typer, node) end
|
7
|
+
def satisfied_by_edge?(typer, edge) ; satisfied_by?(typer, edge) end
|
8
|
+
|
9
|
+
def satisfied_by?(typer, obj) ; raise NotImplementedError end
|
10
|
+
end
|
11
|
+
|
12
|
+
class PropConstraint < Constraint
|
13
|
+
attr_reader :name, :opt, :type
|
14
|
+
|
15
|
+
def initialize(args = {})
|
16
|
+
super(args)
|
17
|
+
@name = args[:name]
|
18
|
+
@opt = args[:opt]
|
19
|
+
@type = args[:type]
|
20
|
+
|
21
|
+
raise ArgumentError unless @name.kind_of? String
|
22
|
+
raise ArgumentError unless @name.length > 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
opt_s = if @opt then " (opt.)" else '' end
|
27
|
+
type_s = if @type then ": #{@type}" else '' end
|
28
|
+
|
29
|
+
"#{@name}#{type_s}#{opt_s}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module NeoScout
|
2
|
+
|
3
|
+
module GDB_Neo4j
|
4
|
+
|
5
|
+
module Constraints
|
6
|
+
|
7
|
+
class PropConstraint < NeoScout::Constraints::PropConstraint
|
8
|
+
|
9
|
+
def satisfied_by?(typer, obj)
|
10
|
+
if obj.property?(@name)
|
11
|
+
then satisfies_type?(typer, @type, obj[@name])
|
12
|
+
else self.opt
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def satisfies_type?(typer, type, value)
|
17
|
+
if type then typer.valid_value?(type, value) else true end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class Typer < NeoScout::Typer
|
24
|
+
|
25
|
+
attr_accessor :type_attr
|
26
|
+
attr_accessor :nil_type
|
27
|
+
attr_accessor :value_type_table
|
28
|
+
attr_accessor :node_mapper
|
29
|
+
attr_accessor :edge_mapper
|
30
|
+
|
31
|
+
include TyperValueTableMixin
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
@type_attr = '_classname'
|
35
|
+
@nil_type = '__NOTYPE__'
|
36
|
+
@node_mapper = nil
|
37
|
+
@edge_mapper = nil
|
38
|
+
@value_type_table = {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def node_type(node)
|
42
|
+
props = node.props
|
43
|
+
return node_mapped(props[@type_attr]) if props.has_key? @type_attr
|
44
|
+
@nil_type
|
45
|
+
end
|
46
|
+
|
47
|
+
def edge_type(edge)
|
48
|
+
type = edge.rel_type
|
49
|
+
if type then edge_mapped(type.to_s) else @nil_type end
|
50
|
+
end
|
51
|
+
|
52
|
+
def checked_node_type?(node_type) ; node_type != self.nil_type end
|
53
|
+
def checked_edge_type?(edge_type) ; edge_type != self.nil_type end
|
54
|
+
|
55
|
+
def unknown_node_type?(type) ; type == @nil_type end
|
56
|
+
def unknown_edge_type?(type) ; type == @nil_type end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def node_mapped(t)
|
61
|
+
if self.node_mapper then self.node_mapper.call(t) else t end
|
62
|
+
end
|
63
|
+
|
64
|
+
def edge_mapped(t)
|
65
|
+
if self.edge_mapper then self.edge_mapper.call(t) else t end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
class ElementIterator < NeoScout::ElementIterator
|
71
|
+
|
72
|
+
def iter_nodes(args)
|
73
|
+
if args[:report_progress]
|
74
|
+
then report = args[:report_progress]
|
75
|
+
else report = lambda { |mode, what, num| } end
|
76
|
+
glops = org.neo4j.tooling.GlobalGraphOperations.at(Neo4j.db.graph)
|
77
|
+
iter = glops.getAllNodes.iterator
|
78
|
+
num = 0
|
79
|
+
while iter.hasNext do
|
80
|
+
node = iter.next
|
81
|
+
num = num + 1
|
82
|
+
report.call(:progress, :nodes, num)
|
83
|
+
yield node unless node.getId == 0
|
84
|
+
end
|
85
|
+
|
86
|
+
report.call(:finish, :nodes, num)
|
87
|
+
num
|
88
|
+
end
|
89
|
+
|
90
|
+
def iter_edges(args)
|
91
|
+
if args[:report_progress]
|
92
|
+
then report = args[:report_progress]
|
93
|
+
else report = lambda { |mode, what, num| } end
|
94
|
+
glops = org.neo4j.tooling.GlobalGraphOperations.at(Neo4j.db.graph)
|
95
|
+
iter = glops.getAllRelationships.iterator
|
96
|
+
num = 0
|
97
|
+
while iter.hasNext do
|
98
|
+
num = num + 1
|
99
|
+
report.call(:progress, :edges, num)
|
100
|
+
yield iter.next
|
101
|
+
end
|
102
|
+
|
103
|
+
report.call(:finish, :edges, num)
|
104
|
+
num
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
class Verifier < NeoScout::Verifier
|
110
|
+
def initialize(typer)
|
111
|
+
super()
|
112
|
+
@typer = typer
|
113
|
+
end
|
114
|
+
|
115
|
+
def new_node_prop_constr(args={})
|
116
|
+
Constraints::PropConstraint.new args
|
117
|
+
end
|
118
|
+
|
119
|
+
def new_edge_prop_constr(args={})
|
120
|
+
Constraints::PropConstraint.new args
|
121
|
+
end
|
122
|
+
|
123
|
+
def init_from_json(json)
|
124
|
+
super(json)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class Scout < NeoScout::Scout
|
129
|
+
|
130
|
+
def initialize(args={})
|
131
|
+
args[:typer] = Typer.new unless args[:typer]
|
132
|
+
args[:verifier] = Verifier.new(args[:typer]) unless args[:verifier]
|
133
|
+
args[:iterator] = ElementIterator.new unless args[:iterator]
|
134
|
+
super args
|
135
|
+
end
|
136
|
+
|
137
|
+
def prep_counts(counts)
|
138
|
+
# Ensure __NOTYPE__entries always have a counts array
|
139
|
+
counts.typed_nodes[typer.nil_type]
|
140
|
+
counts.typed_edges[typer.nil_type]
|
141
|
+
counts
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module NeoScout
|
2
|
+
|
3
|
+
class Counter
|
4
|
+
|
5
|
+
def to_json
|
6
|
+
{ 'num_failed' => num_failed, 'num_total' => num_total }
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
# TODO indexes
|
13
|
+
# TODO edges
|
14
|
+
# TODO testing
|
15
|
+
|
16
|
+
class Verifier
|
17
|
+
|
18
|
+
def init_from_json(json)
|
19
|
+
JSON.cd(json, %w(nodes)).each_pair do |type_name, type_json|
|
20
|
+
JSON.cd(type_json, %w(properties)).each_pair do |prop_name, prop_json|
|
21
|
+
prop_constr = new_node_prop_constr name: prop_name, opt: !prop_json['relevant']
|
22
|
+
prop_set = self.node_props[type_name]
|
23
|
+
prop_set << prop_constr
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
JSON.cd(json, %w(connections)).each_pair do |type_name, type_json|
|
28
|
+
JSON.cd(type_json, %w(properties)).each_pair do |prop_name, prop_json|
|
29
|
+
prop_constr = new_edge_prop_constr name: prop_name, opt: !prop_json['relevant']
|
30
|
+
prop_set = self.edge_props[type_name]
|
31
|
+
prop_set << prop_constr
|
32
|
+
end
|
33
|
+
|
34
|
+
sources_json = if type_json.has_key?('sources') then type_json['sources'] else [] end
|
35
|
+
targets_json = if type_json.has_key?('targets') then type_json['targets'] else [] end
|
36
|
+
add_valid_edge_sets type_name, sources_json, targets_json
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class HashWithDefault
|
44
|
+
|
45
|
+
def to_json
|
46
|
+
self.map_value { |v| v.to_json }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#noinspection RubyTooManyInstanceVariablesInspection
|
51
|
+
class Counts
|
52
|
+
|
53
|
+
def add_to_json(json)
|
54
|
+
all_json = JSON.cd json, %w(all)
|
55
|
+
all_json['node_counts'] = @all_nodes.to_json
|
56
|
+
all_json['connection_counts'] = @all_edges.to_json
|
57
|
+
|
58
|
+
nodes_json = JSON.cd(json, %w(nodes))
|
59
|
+
@typed_nodes.each_pair do |type, count|
|
60
|
+
skip = skip_from_json(:node, type, count)
|
61
|
+
JSON.cd(nodes_json, [type])['counts'] = count.to_json unless skip
|
62
|
+
end
|
63
|
+
|
64
|
+
nodes_json = JSON.cd(json, %w(nodes))
|
65
|
+
@typed_node_props.each_pair do |type, props|
|
66
|
+
props.each_pair do |name, count|
|
67
|
+
skip = skip_from_json(:node, type, count)
|
68
|
+
JSON.cd(nodes_json, [type, 'properties', name])['counts'] = count.to_json unless skip
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
edges_json = JSON.cd(json, %w(connections))
|
73
|
+
@typed_edges.each_pair do |type, count|
|
74
|
+
skip = skip_from_json(:edge, type, count)
|
75
|
+
JSON.cd(edges_json, [type])['counts'] = count.to_json unless skip
|
76
|
+
end
|
77
|
+
|
78
|
+
edges_json = JSON.cd(json, %w(connections))
|
79
|
+
@typed_edge_props.each_pair do |type, props|
|
80
|
+
props.each_pair do |name, count|
|
81
|
+
skip = skip_from_json(:edge, type, count)
|
82
|
+
JSON.cd(edges_json, [type, 'properties', name])['counts'] = count.to_json unless skip
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
add_link_stats_to_json(json)
|
87
|
+
end
|
88
|
+
|
89
|
+
def skip_from_json(kind, type, count)
|
90
|
+
false unless count.empty?
|
91
|
+
case kind
|
92
|
+
when :node
|
93
|
+
@typer.unknown_node_type?(type)
|
94
|
+
when :edge
|
95
|
+
@typer.unknown_edge_type?(type)
|
96
|
+
else
|
97
|
+
raise ArgumentError
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
def add_link_stats_to_json(json)
|
104
|
+
nodes_json = JSON.cd(json, %w(nodes))
|
105
|
+
|
106
|
+
@node_link_src_stats.each_pair do |type, hash|
|
107
|
+
JSON.cd(nodes_json, [type])['src_stats'] = hash.to_json
|
108
|
+
end
|
109
|
+
|
110
|
+
@node_link_dst_stats.each_pair do |type, hash|
|
111
|
+
JSON.cd(nodes_json, [type])['dst_stats'] = hash.to_json
|
112
|
+
end
|
113
|
+
|
114
|
+
edges_json = JSON.cd(json, %w(connections))
|
115
|
+
@edge_link_src_stats.each_pair do |type, hash|
|
116
|
+
JSON.cd(edges_json, [type])['src_stats'] = hash_to_json_array('to_dst', hash)
|
117
|
+
end
|
118
|
+
|
119
|
+
@edge_link_dst_stats.each_pair do |type, hash|
|
120
|
+
JSON.cd(edges_json, [type])['dst_stats'] = hash_to_json_array('from_src', hash)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def hash_to_json_array(target, hash)
|
125
|
+
result = []
|
126
|
+
hash.each_pair do |key, value|
|
127
|
+
inner = []
|
128
|
+
value.each_pair do |i_key, i_value|
|
129
|
+
inner << { 'name' => i_key, 'counts' => i_value.to_json }
|
130
|
+
end
|
131
|
+
result << { 'name' => key, target => inner }
|
132
|
+
end
|
133
|
+
result
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'yaml'
|
3
|
+
require 'optparse'
|
4
|
+
require 'json'
|
5
|
+
require 'httparty'
|
6
|
+
require 'date'
|
7
|
+
require 'active_model'
|
8
|
+
require 'active_support/inflector'
|
9
|
+
|
10
|
+
module NeoScout
|
11
|
+
|
12
|
+
class Main
|
13
|
+
attr_reader :opt_db
|
14
|
+
attr_reader :opt_schema
|
15
|
+
attr_reader :opt_port
|
16
|
+
attr_reader :opt_webservice
|
17
|
+
attr_reader :opt_bind
|
18
|
+
attr_reader :opt_report
|
19
|
+
attr_reader :opt_no_nodes
|
20
|
+
attr_reader :opt_db_config
|
21
|
+
attr_reader :opt_no_edges
|
22
|
+
attr_reader :opt_type_mapper
|
23
|
+
attr_reader :opt_pre_mapper
|
24
|
+
attr_reader :opt_output_file
|
25
|
+
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@opt_report = 0
|
29
|
+
@opt_webservice = false
|
30
|
+
@opt_output_file = nil
|
31
|
+
@opt_no_nodes = false
|
32
|
+
@opt_db_config = nil
|
33
|
+
@opt_no_edges = false
|
34
|
+
@opt_pre_mapper = lambda { |t| t }
|
35
|
+
@opt_type_mapper = lambda { |t| t }
|
36
|
+
parse_opts
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_opts
|
40
|
+
optparse = OptionParser.new do |opts|
|
41
|
+
opts.banner = "Usage: --db <neo4j:path> --schema <url> [--port <port>]"
|
42
|
+
opts.on('-d', '--db DB', 'Path to database in the form neo4j:<path>)') do |db|
|
43
|
+
@opt_db = db
|
44
|
+
end
|
45
|
+
opts.on('-u', '--schema-url URL', 'URL to database schema') do |url|
|
46
|
+
@opt_schema = lambda { || ::JSON.parse(HTTParty.get(url)) }
|
47
|
+
end
|
48
|
+
opts.on('-s', '--schema-file FILE', 'schema file') do |file|
|
49
|
+
@opt_schema = lambda { || ::JSON.parse(IO::read(file)) }
|
50
|
+
end
|
51
|
+
opts.on('-o', '--output-file FILE', 'output file in standalone mode') do |f|
|
52
|
+
@opt_output_file = f
|
53
|
+
end
|
54
|
+
opts.on('-w', '--webservice', 'Run inside sinatra') do
|
55
|
+
@opt_webservice = true
|
56
|
+
end
|
57
|
+
opts.on('-p', '--port PORT', 'Port to be used') do |port|
|
58
|
+
@opt_port = port.to_i
|
59
|
+
end
|
60
|
+
opts.on('-b', '--bind ITF', 'Interface to be used') do |itf|
|
61
|
+
@port = itf
|
62
|
+
end
|
63
|
+
opts.on('-r', '--report NUM', 'Report progress every NUM graph elements') do |num|
|
64
|
+
@opt_report = num.to_i
|
65
|
+
end
|
66
|
+
opts.on('--no-nodes', 'Do not iterate over nodes') do
|
67
|
+
@opt_no_nodes = true
|
68
|
+
end
|
69
|
+
opts.on('--no-edges', 'Do not iterate over edges') do
|
70
|
+
@opt_no_edges = true
|
71
|
+
end
|
72
|
+
opts.on('-P', '--pluralize-types', 'Pluralize type names') do
|
73
|
+
@opt_pre_mapper = lambda { |t| t.pluralize }
|
74
|
+
end
|
75
|
+
opts.on('-S', '--singularize-types', 'Singularize type names') do
|
76
|
+
@opt_pre_mapper = lambda { |t| t.singularize }
|
77
|
+
end
|
78
|
+
opts.on('-M', '--type-mapper MAPPER',
|
79
|
+
'Set the type mapper (underscore, downcase, upcase)') do |mapper|
|
80
|
+
@opt_type_mapper = case mapper
|
81
|
+
when 'underscore'
|
82
|
+
lambda { |t| t.underscore }
|
83
|
+
when 'downcase'
|
84
|
+
lambda { |t| t.downcase }
|
85
|
+
when 'upcase'
|
86
|
+
lambda { |t| t.upcase }
|
87
|
+
else
|
88
|
+
raise ArgumentException('Unsupported mapper')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
opts.on('-C', '--db-config FILE', 'Set config file for db driver') do |file|
|
92
|
+
@opt_db_config = file
|
93
|
+
end
|
94
|
+
opts.on('-h', '--help', 'Display this screen') do
|
95
|
+
puts opts
|
96
|
+
exit 1
|
97
|
+
end
|
98
|
+
end
|
99
|
+
optparse.parse!
|
100
|
+
@opt_output_file = nil if @opt_webservice
|
101
|
+
end
|
102
|
+
|
103
|
+
def start_db
|
104
|
+
@opt_db.match(/(neo4j:)(.*)/) do |m|
|
105
|
+
Neo4j.config[:storage_path] = m[2] unless (m[2].length == 0)
|
106
|
+
YAML.load_file(@opt_db_config).each_pair { |k,v| Neo4j.config[k] = v } if @opt_db_config
|
107
|
+
Neo4j.start
|
108
|
+
return lambda do
|
109
|
+
scout = ::NeoScout::GDB_Neo4j::Scout.new
|
110
|
+
pre_mapper = self.opt_pre_mapper
|
111
|
+
scout.typer.node_mapper = lambda { |t| self.opt_type_mapper.call(pre_mapper.call(t)) }
|
112
|
+
scout.typer.edge_mapper = lambda { |t| self.opt_type_mapper.call(pre_mapper.call(t)) }
|
113
|
+
scout
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
raise ArgumentError("Unsupported database type")
|
118
|
+
end
|
119
|
+
|
120
|
+
def shutdown_db
|
121
|
+
@opt_db.match(/(neo4j:)(.*)/) do |m|
|
122
|
+
Neo4j.shutdown
|
123
|
+
return
|
124
|
+
end
|
125
|
+
|
126
|
+
raise ArgumentError("Unsupported database type")
|
127
|
+
end
|
128
|
+
|
129
|
+
class SimpleConsoleLogger
|
130
|
+
def method_missing(key, *args)
|
131
|
+
print key
|
132
|
+
print ': '
|
133
|
+
puts *args
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def run
|
138
|
+
### Load schema at least once to know that we're safe
|
139
|
+
self.opt_schema.call()
|
140
|
+
### Run as service if requested
|
141
|
+
return run_webservice(self.opt_schema, self.start_db) if self.opt_webservice
|
142
|
+
|
143
|
+
json = run_standalone(self.opt_schema, self.start_db, SimpleConsoleLogger.new)
|
144
|
+
if self.opt_output_file
|
145
|
+
then File.open(self.opt_output_file, 'w') { |f| f.write(json) }
|
146
|
+
else puts(json) end
|
147
|
+
shutdown_db
|
148
|
+
end
|
149
|
+
|
150
|
+
def run_standalone(schema_maker, scout_maker, logger)
|
151
|
+
schema = schema_maker.call()
|
152
|
+
scout = scout_maker.call()
|
153
|
+
scout.verifier.init_from_json schema
|
154
|
+
counts = scout.new_counts
|
155
|
+
logger = SimpleConsoleLogger.new unless logger
|
156
|
+
progress = lambda do |mode, what, num|
|
157
|
+
if ((num % self.opt_report) == 0) || (mode == :finish)
|
158
|
+
logger.info("#{DateTime.now}: #{what} ITERATOR PROGRESS (#{mode} / #{num})")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
scout.count_edges counts: counts, report_progress: progress unless self.opt_no_edges
|
162
|
+
scout.count_nodes counts: counts, report_progress: progress unless self.opt_no_nodes
|
163
|
+
counts.add_to_json schema
|
164
|
+
schema.to_json
|
165
|
+
end
|
166
|
+
|
167
|
+
def run_webservice(schema_maker, scout_maker)
|
168
|
+
### Run sinatra
|
169
|
+
require 'sinatra'
|
170
|
+
|
171
|
+
set :port, @opt_port if @opt_port
|
172
|
+
set :bind, @opt_bind if @opt_bind
|
173
|
+
set :show_exceptions, true
|
174
|
+
set :sessions, false
|
175
|
+
set :logging, true
|
176
|
+
set :dump_errors, true
|
177
|
+
set :lock, true # -- really?
|
178
|
+
set :root, File.expand_path("../../root", __FILE__)
|
179
|
+
set :run, true
|
180
|
+
# set :public_folder
|
181
|
+
|
182
|
+
### Keep self around for calling helpers in sinatra handlers
|
183
|
+
main = self
|
184
|
+
|
185
|
+
### Return schema
|
186
|
+
get '/schema' do
|
187
|
+
content_type :json
|
188
|
+
schema_maker.call().to_json
|
189
|
+
end
|
190
|
+
|
191
|
+
### Run verify over database and report results
|
192
|
+
get '/verify' do
|
193
|
+
content_type :json
|
194
|
+
main.run_standalone(schema_maker, scout_maker, self.logger)
|
195
|
+
end
|
196
|
+
|
197
|
+
### Shutdown server, the hard way
|
198
|
+
get '/shutdown' do
|
199
|
+
main.shutdown_db
|
200
|
+
java.lang.System.exit(0)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|