neo4j-core 8.1.4 → 9.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +71 -8
  3. data/lib/neo4j-core.rb +3 -49
  4. data/lib/neo4j/core.rb +4 -0
  5. data/lib/neo4j/core/config.rb +13 -0
  6. data/lib/neo4j/core/cypher_session/adaptors.rb +15 -15
  7. data/lib/neo4j/core/cypher_session/adaptors/bolt.rb +39 -48
  8. data/lib/neo4j/core/cypher_session/adaptors/bolt/chunk_writer_io.rb +0 -4
  9. data/lib/neo4j/core/cypher_session/adaptors/bolt/pack_stream.rb +7 -3
  10. data/lib/neo4j/core/cypher_session/adaptors/embedded.rb +1 -2
  11. data/lib/neo4j/core/cypher_session/adaptors/has_uri.rb +4 -0
  12. data/lib/neo4j/core/cypher_session/adaptors/http.rb +1 -3
  13. data/lib/neo4j/core/cypher_session/responses.rb +1 -1
  14. data/lib/neo4j/core/cypher_session/responses/bolt.rb +0 -17
  15. data/lib/neo4j/core/cypher_session/responses/embedded.rb +9 -7
  16. data/lib/neo4j/core/cypher_session/responses/http.rb +3 -4
  17. data/lib/neo4j/core/cypher_session/transactions.rb +2 -0
  18. data/lib/{neo4j-core → neo4j/core}/helpers.rb +1 -14
  19. data/lib/neo4j/core/logging.rb +44 -0
  20. data/lib/{neo4j-core → neo4j/core}/query.rb +7 -6
  21. data/lib/{neo4j-core → neo4j/core}/query_clauses.rb +9 -16
  22. data/lib/{neo4j-core → neo4j/core}/query_find_in_batches.rb +3 -5
  23. data/lib/{neo4j-core → neo4j/core}/version.rb +1 -1
  24. data/lib/neo4j/transaction.rb +6 -8
  25. data/neo4j-core.gemspec +13 -11
  26. metadata +46 -50
  27. data/lib/ext/kernel.rb +0 -9
  28. data/lib/neo4j-core/active_entity.rb +0 -11
  29. data/lib/neo4j-core/label.rb +0 -9
  30. data/lib/neo4j-embedded.rb +0 -16
  31. data/lib/neo4j-embedded/cypher_response.rb +0 -71
  32. data/lib/neo4j-embedded/embedded_database.rb +0 -26
  33. data/lib/neo4j-embedded/embedded_ha_session.rb +0 -30
  34. data/lib/neo4j-embedded/embedded_impermanent_session.rb +0 -17
  35. data/lib/neo4j-embedded/embedded_label.rb +0 -88
  36. data/lib/neo4j-embedded/embedded_node.rb +0 -206
  37. data/lib/neo4j-embedded/embedded_relationship.rb +0 -77
  38. data/lib/neo4j-embedded/embedded_session.rb +0 -203
  39. data/lib/neo4j-embedded/embedded_transaction.rb +0 -30
  40. data/lib/neo4j-embedded/label.rb +0 -66
  41. data/lib/neo4j-embedded/property.rb +0 -106
  42. data/lib/neo4j-embedded/to_java.rb +0 -44
  43. data/lib/neo4j-server.rb +0 -12
  44. data/lib/neo4j-server/cypher_label.rb +0 -35
  45. data/lib/neo4j-server/cypher_node.rb +0 -221
  46. data/lib/neo4j-server/cypher_relationship.rb +0 -142
  47. data/lib/neo4j-server/cypher_response.rb +0 -248
  48. data/lib/neo4j-server/cypher_session.rb +0 -263
  49. data/lib/neo4j-server/cypher_transaction.rb +0 -100
  50. data/lib/neo4j-server/label.rb +0 -40
  51. data/lib/neo4j-server/resource.rb +0 -57
  52. data/lib/neo4j/entity_equality.rb +0 -8
  53. data/lib/neo4j/entity_marshal.rb +0 -20
  54. data/lib/neo4j/label.rb +0 -90
  55. data/lib/neo4j/node.rb +0 -216
  56. data/lib/neo4j/property_container.rb +0 -17
  57. data/lib/neo4j/property_validator.rb +0 -22
  58. data/lib/neo4j/relationship.rb +0 -161
  59. data/lib/neo4j/session.rb +0 -222
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 62857b8d2f1a86d5c17adefa6b5866eb5efaf40e
4
- data.tar.gz: a669a4e956ea744d392104ae98e80fb673f4bb24
2
+ SHA256:
3
+ metadata.gz: 95c3a0a71e52de4f4ef573cc36ff3d206a1fcd3ba443a84890e3c42c6ca6cc39
4
+ data.tar.gz: '05885ecf4289f9fae5d67234f82324c24289e4ab0a1fff8ffc6569810e71a496'
5
5
  SHA512:
6
- metadata.gz: d2b1b59513aaf3a619f0ea1b1fe526bbf57ac9105f88e8039be13c17c367972c3286aba0c9e0d0827ce80fb44eed5bbac89aaa8b1aba165438614958c42a81d5
7
- data.tar.gz: b2fc295d422907d44afa707975ea6ba6bb5705cfa76984bd135532202c04f4e2524ea90e404f5b0582cd6979f0237bc47633b4dd8e042b31e820179acb2b7279
6
+ metadata.gz: ab2abc2fa87addc1ef0b2ebb0e3e67886d773d0542bf3a2850f17adc39c27e9faae92a0f528b8e8785de28bced39cbd19d5a264ee27f1584f1f34ccd21383049
7
+ data.tar.gz: 686135288df838098db8b40ede27157bc02d335eef6b041b18ee4c7f24a2f0f28bdc98f1d5ada1a15e864e9e24d7caf1acb8aae2003b44696041b9c9ad44d8c9
data/README.md CHANGED
@@ -1,4 +1,10 @@
1
- # Neo4j-core [![Code Climate](https://codeclimate.com/github/neo4jrb/neo4j-core.svg)](https://codeclimate.com/github/neo4jrb/neo4j-core) [![Build Status](https://travis-ci.org/neo4jrb/neo4j-core.svg)](https://travis-ci.org/neo4jrb/neo4j-core) [![Coverage Status](https://coveralls.io/repos/neo4jrb/neo4j-core/badge.svg?branch=master)](https://coveralls.io/r/neo4jrb/neo4j-core?branch=master) [![PullReview stats](https://www.pullreview.com/github/neo4jrb/neo4j-core/badges/master.svg?)](https://www.pullreview.com/github/neo4jrb/neo4j-core/reviews/master)
1
+ # Neo4j-core
2
+
3
+ [![Actively Maintained](https://img.shields.io/badge/Maintenance%20Level-Actively%20Maintained-green.svg)](https://gist.github.com/cheerfulstoic/d107229326a01ff0f333a1d3476e068d)
4
+ [![Code Climate](https://codeclimate.com/github/neo4jrb/neo4j-core.svg)](https://codeclimate.com/github/neo4jrb/neo4j-core)
5
+ [![Build Status](https://travis-ci.org/neo4jrb/neo4j-core.svg)](https://travis-ci.org/neo4jrb/neo4j-core)
6
+ [![Coverage Status](https://coveralls.io/repos/neo4jrb/neo4j-core/badge.svg?branch=master)](https://coveralls.io/r/neo4jrb/neo4j-core?branch=master)
7
+ [![PullReview stats](https://www.pullreview.com/github/neo4jrb/neo4j-core/badges/master.svg?)](https://www.pullreview.com/github/neo4jrb/neo4j-core/reviews/master)
2
8
 
3
9
  A simple Ruby wrapper around the Neo4j graph database that works with the server and embedded Neo4j API. This gem can be used both from JRuby and normal MRI.
4
10
  It can be used standalone without the neo4j gem.
@@ -9,15 +15,20 @@ It can be used standalone without the neo4j gem.
9
15
 
10
16
  To make a basic connection to Neo4j to execute Cypher queries, first choose an adaptor. Adaptors for HTTP, Bolt, and Embedded mode (jRuby only) are available. You can create an adaptor like:
11
17
 
12
- http_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new('http://neo4j:pass@localhost:7474')
18
+ require 'neo4j/core/cypher_session/adaptors/http'
19
+ http_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new('http://neo4j:pass@localhost:7474', options)
13
20
 
14
21
  # or
15
22
 
16
- bolt_adaptor = Neo4j::Core::CypherSession::Adaptors::Bolt.new('bolt://neo4j:pass@localhost:7687', timeout: 10)
23
+ require 'neo4j/core/cypher_session/adaptors/bolt'
24
+ bolt_adaptor = Neo4j::Core::CypherSession::Adaptors::Bolt.new('bolt://neo4j:pass@localhost:7687', options)
17
25
 
18
26
  # or
19
27
 
20
- neo4j_adaptor = Neo4j::Core::CypherSession::Adaptors::Embedded.new('/file/path/to/graph.db')
28
+ require 'neo4j/core/cypher_session/adaptors/embedded'
29
+ neo4j_adaptor = Neo4j::Core::CypherSession::Adaptors::Embedded.new('/file/path/to/graph.db', options)
30
+
31
+ The options are specific to each adaptor. See below for details.
21
32
 
22
33
  Once you have an adaptor you can create a session like so:
23
34
 
@@ -55,15 +66,67 @@ When doing batched queries, there is also a shortcut for getting a new `Neo4j::C
55
66
 
56
67
  results[0] # result
57
68
 
69
+ ### Adaptor Options
70
+
71
+ As mentioned above, each of the adaptors take different sets of options. They are enumerated below:
72
+
73
+ #### Shared options
74
+
75
+ All adaptors take `wrap_level` as an option. This can be used to control how nodes, relationships, and path data is returned:
76
+
77
+ * `wrap_level: :none` will return Ruby hashes
78
+ * `wrap_level: :core_entity` will return objects from the `neo4j-core` gem (`Neo4j::Core::Node`, `Neo4j::Core::Relationship`, and `Neo4j::Core::Path`
79
+ * `wrap_level: :prop` allows you to define Ruby Procs to do your own wrapping. This is how the `neo4j` gem provides `ActiveNode` and `ActiveRel` objects (see the [`node_wrapper.rb`](https://github.com/neo4jrb/neo4j/blob/master/lib/neo4j/active_node/node_wrapper.rb) and [`rel_wrapper.rb`](https://github.com/neo4jrb/neo4j/blob/master/lib/neo4j/active_rel/rel_wrapper.rb) files for examples on how this works
80
+
81
+ All adaptors will also take either a `logger` option with a Ruby logger to define where it will log to.
82
+
83
+ All adaptors will also take the `skip_instrumentation` option to skip logging of queries.
84
+
85
+ All adaptors will also take the `verbose_query_logs` option which can be `true` or `false` (`false` being the default). This will change the logging to output the source line of code which caused a query to be executed (note that the `skip_instrumentation` should not be set for logging to be produced).
86
+
87
+ #### Bolt
88
+
89
+ The Bolt adaptor takes `connect_timeout`, `read_timeout`, and `write_timeout` options which define appropriate timeouts. The `connect_timeout` is 10 seconds and the `read_timeout` and `write_timeout` are -1 (no timeout). This is to cause the underlying `net_tcp_client` gem to operate in blocking mode (as opposed to non-blocking mode). When using non-blocking mode problems were found and since the official Neo4j drivers in other languages use blocking mode, this is what this gem uses by default. This issue could potentially be a bug in the handling of the `EAGAIN` signal, but it was not investigated further. Set the read/write timeouts at your own risk.
90
+
91
+ The Bolt adaptor also takes an `ssl` option which also corresponds to `net_tcp_client`'s `ssl` option (which, in turn, corresponds to Ruby's `OpenSSL::SSL::SSLContext`). By default SSL is used. For most cloud providers that use public certificate authorities this open generally won't be needed. If you've setup Neo4j yourself you will need to provide the certificate like so:
92
+
93
+ ```ruby
94
+ cert_store = OpenSSL::X509::Store.new
95
+ cert_store.add_file('/the/path/to/your/neo4j.cert')
96
+ ssl: {cert_store: cert_store}}
97
+ bolt_adaptor = Neo4j::Core::CypherSession::Adaptors::Bolt.new('bolt://neo4j:pass@localhost:7687', ssl: {cert_store: cert_store})
98
+ ```
99
+
100
+ You can also turn SSL off by simply specifying `ssl: false`
101
+
102
+ #### HTTP
103
+
104
+ Since the HTTP adaptor uses the `faraday` gem under the covers, it takes a `faraday_configurator` option. This allows you to pass in a `Proc` which works just like a Faraday setup block:
105
+
106
+ ```ruby
107
+ faraday_configurator: proc do |faraday|
108
+ # The default configurator uses typhoeus so if you override the configurator you must specify this
109
+ faraday.adapter :typhoeus
110
+ # Optionally you can instead specify another adaptor
111
+ # faraday.use Faraday::Adapter::NetHttpPersistent
112
+
113
+ # If you need to set options which would normally be the second argument of `Faraday.new`, you can do the following:
114
+ faraday.options[:open_timeout] = 5
115
+ faraday.options[:timeout] = 65
116
+ # faraday.options[:ssl] = { verify: true }
117
+ end
118
+ ```
119
+
120
+ #### Embedded
121
+
122
+ The Embedded adaptor takes `properties_file` and `properties_map` options which are passed to `loadPropertiesFromFile` and `setConfig` on the `GraphDatabaseBuilder` class from the Neo4j Java API.
123
+
58
124
  ## Documentation
59
125
 
60
- ### 3.0+ Documentation:
126
+ Our documentation on ReadTheDocs covers both the `neo4j` and `neo4j-core` gems:
61
127
 
62
128
  * http://neo4jrb.readthedocs.org/en/stable/
63
129
 
64
- ### 2.x Documentation
65
-
66
- https://github.com/neo4jrb/neo4j-core/tree/v2.x
67
130
 
68
131
  ## Support
69
132
 
@@ -1,49 +1,3 @@
1
- require 'ext/kernel'
2
-
3
- require 'ostruct'
4
- require 'forwardable'
5
- require 'fileutils'
6
-
7
- require 'neo4j-core/version'
8
- require 'neo4j/property_validator'
9
- require 'neo4j/property_container'
10
- require 'neo4j/entity_marshal'
11
- require 'neo4j-core/active_entity'
12
- require 'neo4j-core/helpers'
13
- require 'neo4j-core/query_find_in_batches'
14
- require 'neo4j-core/query'
15
-
16
- require 'neo4j/entity_equality'
17
- require 'neo4j/node'
18
- require 'neo4j/label'
19
- require 'neo4j/session'
20
- require 'neo4j/ansi'
21
-
22
- require 'neo4j/relationship'
23
- require 'neo4j/transaction'
24
-
25
- require 'rake'
26
- load 'neo4j/core/rake_tasks_deprecation.rake'
27
-
28
- require 'logger'
29
-
30
- module Neo4j
31
- module Core
32
- ORIGINAL_FORMATTER = ::Logger::Formatter.new
33
-
34
- def self.logger(stream = STDOUT)
35
- @logger ||= Logger.new(stream).tap do |logger|
36
- logger.formatter = method(:formatter)
37
- end
38
- end
39
-
40
- def self.formatter(severity, datetime, progname, msg)
41
- output = ''
42
- if Thread.current != Thread.main
43
- output += "#{ANSI::YELLOW}Thread: #{Thread.current.object_id}: #{ANSI::CLEAR}"
44
- end
45
- output += msg
46
- ORIGINAL_FORMATTER.call(severity, datetime, progname, output)
47
- end
48
- end
49
- end
1
+ # DO NOT ADD ANYTHING HERE
2
+ # lib/neo4j/core.rb should be the base for requiring essential files
3
+ require 'neo4j/core'
@@ -0,0 +1,4 @@
1
+ require 'neo4j/core/config'
2
+
3
+ require 'neo4j/transaction'
4
+ require 'neo4j/core/query'
@@ -0,0 +1,13 @@
1
+ module Neo4j
2
+ module Core
3
+ module Config
4
+ def self.wrapping_level(level = nil)
5
+ if level.nil?
6
+ @wrapping_level || :core_entity
7
+ else
8
+ @wrapping_level = level
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,7 +1,9 @@
1
1
  require 'neo4j/core/cypher_session'
2
2
  require 'neo4j/core/instrumentable'
3
3
  require 'neo4j/core/label'
4
- require 'neo4j-core/version'
4
+ require 'neo4j/core/version'
5
+ require 'neo4j/core/logging'
6
+ require 'neo4j/ansi'
5
7
 
6
8
  module Neo4j
7
9
  module Core
@@ -22,7 +24,6 @@ ERROR
22
24
  super(msg)
23
25
  end
24
26
 
25
-
26
27
  def self.new_from(code, message, stack_trace = nil)
27
28
  error_class_from(code).new(code, message, stack_trace)
28
29
  end
@@ -67,6 +68,7 @@ ERROR
67
68
  end
68
69
 
69
70
  attr_accessor :wrap_level
71
+ attr_reader :options
70
72
 
71
73
  Query = Struct.new(:cypher, :parameters, :pretty_cypher, :context)
72
74
 
@@ -162,31 +164,29 @@ ERROR
162
164
  end
163
165
 
164
166
  def setup_queries!(queries, transaction, options = {})
165
- fail 'Query attempted without a connection' if !connected?
166
- fail "Invalid transaction object: #{transaction.inspect}" if !transaction.is_a?(self.class.transaction_class)
167
+ validate_connection!(transaction)
167
168
 
168
- # context option not yet implemented
169
- self.class.instrument_queries(queries) unless options[:skip_instrumentation]
169
+ return if options[:skip_instrumentation]
170
+ queries.each do |query|
171
+ self.class.instrument_query(query, self) {}
172
+ end
170
173
  end
171
174
 
172
175
  EMPTY = ''
173
176
  NEWLINE_W_SPACES = "\n "
174
177
 
175
- instrument(:query, 'neo4j.core.cypher_query', %w[query]) do |_, _start, _finish, _id, payload|
178
+ instrument(:query, 'neo4j.core.cypher_query', %w[query adaptor]) do |_, _start, _finish, _id, payload|
176
179
  query = payload[:query]
177
180
  params_string = (query.parameters && !query.parameters.empty? ? "| #{query.parameters.inspect}" : EMPTY)
178
181
  cypher = query.pretty_cypher ? (NEWLINE_W_SPACES if query.pretty_cypher.include?("\n")).to_s + query.pretty_cypher.gsub(/\n/, NEWLINE_W_SPACES) : query.cypher
179
182
 
180
- " #{ANSI::CYAN}#{query.context || 'CYPHER'}#{ANSI::CLEAR} #{cypher} #{params_string}"
183
+ source_line, line_number = Logging.first_external_path_and_line(caller_locations)
184
+
185
+ " #{ANSI::CYAN}#{query.context || 'CYPHER'}#{ANSI::CLEAR} #{cypher} #{params_string}" +
186
+ ("\n ↳ #{source_line}:#{line_number}" if payload[:adaptor].options[:verbose_query_logs] && source_line).to_s
181
187
  end
182
188
 
183
189
  class << self
184
- def instrument_queries(queries)
185
- queries.each do |query|
186
- instrument_query(query) {}
187
- end
188
- end
189
-
190
190
  def transaction_class
191
191
  fail '.transaction_class method not implemented on adaptor!'
192
192
  end
@@ -202,7 +202,7 @@ ERROR
202
202
  end
203
203
  end
204
204
 
205
- def validate_query_set!(transaction, _queries, _options = {})
205
+ def validate_connection!(transaction)
206
206
  fail 'Query attempted without a connection' if !connected?
207
207
  fail "Invalid transaction object: #{transaction}" if !transaction.is_a?(self.class.transaction_class)
208
208
  end
@@ -3,10 +3,9 @@ require 'neo4j/core/cypher_session/adaptors/has_uri'
3
3
  require 'neo4j/core/cypher_session/adaptors/bolt/pack_stream'
4
4
  require 'neo4j/core/cypher_session/adaptors/bolt/chunk_writer_io'
5
5
  require 'neo4j/core/cypher_session/responses/bolt'
6
- require 'io/wait'
7
- require 'socket'
6
+ require 'net/tcp_client'
8
7
 
9
- # TODO: Work with `Query` objects
8
+ # TODO: Work with `Query` objects?
10
9
  module Neo4j
11
10
  module Core
12
11
  class CypherSession
@@ -24,6 +23,10 @@ module Neo4j
24
23
  def initialize(url, options = {})
25
24
  self.url = url
26
25
  @options = options
26
+ @net_tcp_client_options = {read_timeout: options.fetch(:read_timeout, -1),
27
+ write_timeout: options.fetch(:write_timeout, -1),
28
+ connect_timeout: options.fetch(:connect_timeout, 10),
29
+ ssl: options.fetch(:ssl, {})}
27
30
 
28
31
  open_socket
29
32
  end
@@ -43,13 +46,7 @@ module Neo4j
43
46
  def query_set(transaction, queries, options = {})
44
47
  setup_queries!(queries, transaction, skip_instrumentation: options[:skip_instrumentation])
45
48
 
46
- if @socket.ready?
47
- debug_remaining_buffer
48
- fail "Making query, but expected there to be no buffer remaining!\n"\
49
- "Queries: #{queries.map(&:cypher)}"
50
- end
51
-
52
- self.class.instrument_request do
49
+ self.class.instrument_request(self) do
53
50
  send_query_jobs(queries)
54
51
 
55
52
  build_response(queries, options[:wrap_level] || @options[:wrap_level])
@@ -64,7 +61,7 @@ module Neo4j
64
61
  end
65
62
 
66
63
  def connected?
67
- !!@socket
64
+ !!@tcp_client && !@tcp_client.closed?
68
65
  end
69
66
 
70
67
  def indexes(session)
@@ -90,10 +87,16 @@ module Neo4j
90
87
  Neo4j::Core::CypherSession::Transactions::Bolt
91
88
  end
92
89
 
93
- instrument(:request, 'neo4j.core.bolt.request', %w[url body]) do |_, start, finish, _id, payload|
90
+ instrument(:request, 'neo4j.core.bolt.request', %w[adaptor body]) do |_, start, finish, _id, payload|
94
91
  ms = (finish - start) * 1000
92
+ adaptor = payload[:adaptor]
95
93
 
96
- " #{ANSI::BLUE}BOLT REQUEST:#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR} #{payload[:url]}"
94
+ type = adaptor.ssl? ? '+TLS' : ' UNSECURE'
95
+ " #{ANSI::BLUE}BOLT#{type}:#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR} #{adaptor.url_without_password}"
96
+ end
97
+
98
+ def ssl?
99
+ @tcp_client.socket.is_a?(OpenSSL::SSL::SSLSocket)
97
100
  end
98
101
 
99
102
  private
@@ -117,17 +120,6 @@ module Neo4j
117
120
  fail CypherError.new_from(error_data['code'], error_data['message'])
118
121
  end
119
122
 
120
- def debug_remaining_buffer
121
- logger.debug 'Remaining buffer:'
122
-
123
- i = 0
124
- while @socket.ready?
125
- i += 1
126
- logger.debug "Message set #{i}:"
127
- flush_messages
128
- end
129
- end
130
-
131
123
  def send_query_jobs(queries)
132
124
  send_job do |job|
133
125
  queries.each do |query|
@@ -141,8 +133,12 @@ module Neo4j
141
133
  Job.new(self)
142
134
  end
143
135
 
136
+ def secure_connection?
137
+ @is_secure_socket ||= @options.key?(:ssl)
138
+ end
139
+
144
140
  def open_socket
145
- @socket = TCPSocket.open(host, port)
141
+ @tcp_client = Net::TCPClient.new(@net_tcp_client_options.merge(buffered: false, server: "#{host}:#{port}"))
146
142
  rescue Errno::ECONNREFUSED => e
147
143
  raise Neo4j::Core::CypherSession::ConnectionFailedError, e.message
148
144
  end
@@ -156,13 +152,12 @@ module Neo4j
156
152
  agreed_version = recvmsg(4).unpack('l>*')[0]
157
153
 
158
154
  if agreed_version.zero?
159
- @socket.shutdown(Socket::SHUT_RDWR)
160
- @socket.close
155
+ @tcp_client.close
161
156
 
162
157
  fail "Couldn't agree on a version (Sent versions #{SUPPORTED_VERSIONS.inspect})"
163
158
  end
164
159
 
165
- logger.debug "Agreed to version: #{agreed_version}"
160
+ logger.debug { "Agreed to version: #{agreed_version}" }
166
161
  end
167
162
 
168
163
  def init
@@ -181,42 +176,42 @@ module Neo4j
181
176
  end
182
177
  end
183
178
 
179
+ # Don't need to calculate these every time. Cache in memory
180
+ BYTE_STRINGS = (0..255).map { |byte| byte.to_s(16).rjust(2, '0') }
181
+
184
182
  STREAM_INSPECTOR = lambda do |stream|
185
- stream.bytes.map { |byte| byte.to_s(16).rjust(2, '0') }.join(':')
183
+ stream.bytes.map { |byte| BYTE_STRINGS[byte] }.join(':')
186
184
  end
187
185
 
188
186
  def sendmsg(message)
189
187
  log_message :C, message
190
-
191
- @socket.send(message, 0)
188
+ @tcp_client.write(message)
192
189
  end
193
190
 
194
- def recvmsg(size, timeout = timeout_option)
195
- Timeout.timeout(timeout) do
196
- @socket.recv(size).tap do |result|
197
- log_message :S, result
198
- end
191
+ def recvmsg(size)
192
+ @tcp_client.read(size) do |result|
193
+ log_message :S, result
199
194
  end
200
- rescue Timeout::Error
201
- raise "Timed out waiting for #{size} bytes from Neo4j (after #{timeout} seconds)"
202
195
  end
203
196
 
204
197
  def flush_messages
205
198
  if structures = flush_response
206
199
  structures.map do |structure|
207
200
  Message.new(structure.signature, *structure.list).tap do |message|
208
- log_message :S, message.type, message.args.join(' ')
201
+ log_message :S, message.type, message.args.join(' ') if logger.debug?
209
202
  end
210
203
  end
211
204
  end
212
205
  end
213
206
 
214
207
  def log_message(side, *args)
215
- if args.size == 1
216
- logger.debug "#{side}: #{STREAM_INSPECTOR.call(args[0])}"
217
- else
218
- type, message = args
219
- logger.debug "#{side}: #{ANSI::CYAN}#{type.to_s.upcase}#{ANSI::CLEAR} #{message}"
208
+ logger.debug do
209
+ if args.size == 1
210
+ "#{side}: #{STREAM_INSPECTOR.call(args[0])}"
211
+ else
212
+ type, message = args
213
+ "#{side}: #{ANSI::CYAN}#{type.to_s.upcase}#{ANSI::CLEAR} #{message}"
214
+ end
220
215
  end
221
216
  end
222
217
 
@@ -234,10 +229,6 @@ module Neo4j
234
229
  [].tap { |r| while arg = unpacker.unpack_value!; r << arg; end }
235
230
  end
236
231
 
237
- def timeout_option
238
- @options.fetch(:timeout) { 10 }
239
- end
240
-
241
232
  # Represents messages sent to or received from the server
242
233
  class Message
243
234
  TYPE_CODES = {