neo4j_bolt 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ee97cadb6f90804ce6e67ea21a41f7a4e2b422bb2e81adb41b437e2b31c51e4
4
- data.tar.gz: 8e5c66489482f3b1e113b2b8874fa3a5f1cea0e05d9496b1705165803230bcb8
3
+ metadata.gz: 316d22f20084bb29755e8693c25860bd4d3afa5e5aadce5b89e415bf53157b82
4
+ data.tar.gz: 405c68b29be5578f7859cdc973b956ccb9898a4b7d105cc19b0e31e81c5615b3
5
5
  SHA512:
6
- metadata.gz: 98d9897e3f1a76eff59c0669fc78b81c25e37c027f53534cfe32633ec7eae7a2fe68b676a72c8c91359b54b182fc82cfccf43a7ffcf0b70ed685483c0f61a9ba
7
- data.tar.gz: 424754f578f63f73181d60d49e4efbdde993defe092942b94ce1d17973961681ecb3c6561621d304588ba18492a9c5db7fbd0bfc7c3890eed9f8d850472259fb
6
+ metadata.gz: 94766bfe86f3487582229ed0d11fa4c2bc813adac23fe1065c5dc026c692e3b82c859978b08d5dfb78915382d224425b7e7f81eb06f620eebb23014d8e4934b9
7
+ data.tar.gz: e144730f9cb75b44450c0dfb3b56d76698c9839e1f54a375c4e7608cb6eb7d6cf70d1544a7065a78d08c4d813387da66ec758bc1749d24037899233c80feb3d7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- neo4j_bolt (0.2.0)
4
+ neo4j_bolt (0.3.0)
5
5
  gli
6
6
  pry
7
7
 
@@ -1,3 +1,3 @@
1
1
  module Neo4jBolt
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/neo4j_bolt.rb CHANGED
@@ -15,15 +15,16 @@ module Neo4jBolt
15
15
  CONSTRAINT_INDEX_PREFIX = 'neo4j_bolt_'
16
16
 
17
17
  module ServerState
18
- DISCONNECTED = 0
19
- CONNECTED = 1
20
- DEFUNCT = 2
21
- READY = 3
22
- STREAMING = 4
23
- TX_READY = 5
24
- TX_STREAMING = 6
25
- FAILED = 7
26
- INTERRUPTED = 8
18
+ DISCONNECTED = 0
19
+ CONNECTED = 1
20
+ DEFUNCT = 2
21
+ READY = 3
22
+ STREAMING = 4
23
+ TX_READY = 5
24
+ TX_STREAMING = 6
25
+ FAILED = 7
26
+ INTERRUPTED = 8
27
+ AUTHENTICATION = 10
27
28
  end
28
29
  SERVER_STATE_LABELS = Hash[ServerState::constants.map { |value| [ServerState::const_get(value), value] }]
29
30
 
@@ -39,6 +40,7 @@ module Neo4jBolt
39
40
  BOLT_PULL = 0x3F
40
41
  BOLT_NODE = 0x4E
41
42
  BOLT_RELATIONSHIP = 0x52
43
+ BOLT_LOGON = 0x6A
42
44
  BOLT_SUCCESS = 0x70
43
45
  BOLT_RECORD = 0x71
44
46
  BOLT_IGNORED = 0x7E
@@ -285,7 +287,7 @@ module Neo4jBolt
285
287
  @transaction_failed = false
286
288
  @state = State.new()
287
289
  @neo4j_version = nil
288
- @pid = Process.pid
290
+ @pidtid = "#{Process.pid}/#{Thread.current.object_id}"
289
291
  end
290
292
 
291
293
  def assert(condition)
@@ -301,7 +303,7 @@ module Neo4jBolt
301
303
  end
302
304
 
303
305
  def append_token(i)
304
- # STDERR.puts BOLT_MARKER_LABELS[i]
306
+ # STDERR.puts "Appending token: [#{BOLT_MARKER_LABELS[i]}]"
305
307
  append_uint8(i)
306
308
  end
307
309
 
@@ -335,6 +337,7 @@ module Neo4jBolt
335
337
 
336
338
  def append_s(s)
337
339
  s = s.to_s
340
+ # STDERR.puts "Appending string: [#{s}]"
338
341
  if s.bytesize < 16
339
342
  append_uint8(0x80 + s.bytesize)
340
343
  elsif s.bytesize < 0x100
@@ -398,6 +401,7 @@ module Neo4jBolt
398
401
  end
399
402
 
400
403
  def append_dict(d)
404
+ # STDERR.puts "Appending dict: [#{d.to_json}]"
401
405
  if d.size < 16
402
406
  append_uint8(0xA0 + d.size)
403
407
  elsif d.size < 0x100
@@ -439,6 +443,35 @@ module Neo4jBolt
439
443
  end
440
444
 
441
445
  def flush()
446
+ # STDERR.puts "Flushing buffer with #{@buffer.size} bytes..."
447
+
448
+ # offset = 0
449
+ # last_offset = 0
450
+ # while offset < @buffer.size
451
+ # if offset % 16 == 0
452
+ # STDERR.write sprintf('%04x | ', offset)
453
+ # end
454
+ # STDERR.write sprintf("%02x ", @buffer[offset])
455
+ # offset += 1
456
+ # if offset % 16 == 0
457
+ # STDERR.write ' ' * 4
458
+ # (last_offset...offset).each do |i|
459
+ # b = @buffer[i]
460
+ # STDERR.write (b >= 32 && b < 128) ? b.chr : '.'
461
+ # end
462
+ # STDERR.puts
463
+ # last_offset = offset
464
+ # end
465
+ # end
466
+ # (16 - offset + last_offset).times { STDERR.write ' ' }
467
+ # STDERR.write ' ' * 4
468
+ # (last_offset...offset).each do |i|
469
+ # b = @buffer[i]
470
+ # STDERR.write (b >= 32 && b < 128) ? b.chr : '.'
471
+ # end
472
+ # STDERR.puts
473
+
474
+
442
475
  size = @buffer.size
443
476
  offset = 0
444
477
  while size > 0
@@ -602,12 +635,16 @@ module Neo4jBolt
602
635
 
603
636
  def read_response(&block)
604
637
  loop do
638
+ # STDERR.puts "Reading response:"
605
639
  buffer = BoltBuffer.new(@socket)
640
+ # buffer.dump
606
641
  response_dict = parse(buffer)
607
642
  buffer.flush()
643
+ # STDERR.puts "Response marker: #{BOLT_MARKER_LABELS[response_dict[:marker]]}"
644
+ # STDERR.puts response_dict.to_yaml
608
645
  if response_dict[:marker] == BoltMarker::BOLT_FAILURE
609
646
  # STDERR.puts "RESETTING CONNECTION"
610
- append_uint8(0xb1)
647
+ append_uint8(0xb0)
611
648
  append_token(BoltMarker::BOLT_RESET)
612
649
  flush()
613
650
  read_response() do |data|
@@ -627,38 +664,50 @@ module Neo4jBolt
627
664
  end
628
665
 
629
666
  def connect()
630
- # STDERR.write "Connecting to Neo4j via Bolt..."
631
667
  @socket = TCPSocket.new(Neo4jBolt.bolt_host, Neo4jBolt.bolt_port)
632
- # @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
633
- # @socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE, 50)
634
- # @socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL, 10)
635
- # @socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT, 5)
636
668
  # The line below is important, otherwise we'll have to wait 40ms before every read
637
669
  @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
638
670
  @buffer = []
639
671
  @socket.write("\x60\x60\xB0\x17")
672
+ @socket.write("\x00\x00\x04\x05")
640
673
  @socket.write("\x00\x00\x04\x04")
641
674
  @socket.write("\x00\x00\x00\x00")
642
675
  @socket.write("\x00\x00\x00\x00")
643
- @socket.write("\x00\x00\x00\x00")
644
- version = @socket.read(4).unpack('N').first
645
- if version != 0x00000404
646
- raise "Unable to establish connection to Neo4j using Bolt protocol version 4.4!"
676
+ @bolt_version = @socket.read(4).unpack('V').first >> 16
677
+ # STDERR.puts "Handshake Bolt version: 0x%08x" % @bolt_version
678
+ unless [0x0504, 0x0404].include?(@bolt_version)
679
+ raise "Unable to establish connection to Neo4j using Bolt!"
647
680
  end
648
681
  @state.set(ServerState::CONNECTED)
649
- data = {
650
- :routing => nil,
651
- :scheme => 'none',
652
- :user_agent => 'neo4j_bolt/0.1'
653
- }
654
682
  append_uint8(0xb1)
655
683
  append_token(BoltMarker::BOLT_HELLO)
656
- append_dict(data)
684
+ append_dict({
685
+ :routing => nil,
686
+ :scheme => 'none',
687
+ :user_agent => "neo4j_bolt/#{Neo4jBolt::VERSION}",
688
+ :bolt_agent => {
689
+ :product => "neo4j_bolt/#{Neo4jBolt::VERSION}",
690
+ },
691
+ })
657
692
  flush()
658
693
  read_response() do |data|
659
694
  if data[:marker] == BoltMarker::BOLT_SUCCESS
660
- @state.set(ServerState::READY)
661
- @neo4j_version = data[:data]['server']
695
+ parts = data[:data]['server'].split('/')[1].split('.').map { |x| x.to_i}
696
+ if @bolt_version >= 0x0501
697
+ @state.set(ServerState::AUTHENTICATION)
698
+ append_uint8(0xb1)
699
+ append_token(BoltMarker::BOLT_LOGON)
700
+ append_dict({:scheme => 'none'})
701
+ flush()
702
+ read_response() do |data2|
703
+ @state.set(ServerState::READY)
704
+ if data2[:marker] == BoltMarker::BOLT_SUCCESS
705
+ @state.set(ServerState::READY)
706
+ end
707
+ end
708
+ else
709
+ @state.set(ServerState::READY)
710
+ end
662
711
  elsif data[:marker] == BoltMarker::BOLT_FAILURE
663
712
  @state.set(ServerState::DEFUNCT)
664
713
  else
@@ -671,14 +720,14 @@ module Neo4jBolt
671
720
  end
672
721
 
673
722
  def disconnect()
674
- append_uint8(0xb1)
723
+ append_uint8(0xb0)
675
724
  append_token(BoltMarker::BOLT_GOODBYE)
676
725
  flush()
677
726
  @state.set(ServerState::DEFUNCT)
678
727
  end
679
728
 
680
729
  def transaction(&block)
681
- reset() if Process.pid != @pid
730
+ reset() if @pidtid != "#{Process.pid}/#{Thread.current.object_id}"
682
731
  connect() if @socket.nil?
683
732
  if @transaction == 0
684
733
  # STDERR.puts '*' * 40
@@ -708,13 +757,13 @@ module Neo4jBolt
708
757
  raise
709
758
  ensure
710
759
  @transaction -= 1
711
- if @transaction == 0 && @transaction_failed &&
760
+ if @transaction == 0 && @transaction_failed
712
761
  # TODO: Not sure about this, read remaining response but don't block
713
762
  # read_response()
714
- # STDERR.puts "!!! Rolling back transaction !!!"
763
+ # STDERR.puts "!!! Rolling back transaction !!! --- state is #{@state}"
715
764
  if @state == ServerState::TX_READY
716
765
  assert(@state == ServerState::TX_READY)
717
- append_uint8(0xb1)
766
+ append_uint8(0xb0)
718
767
  append_token(BoltMarker::BOLT_ROLLBACK)
719
768
  flush()
720
769
  read_response do |data|
@@ -730,7 +779,7 @@ module Neo4jBolt
730
779
  end
731
780
  end
732
781
  if (@transaction == 0) && (!@transaction_failed)
733
- append_uint8(0xb1)
782
+ append_uint8(0xb0)
734
783
  append_token(BoltMarker::BOLT_COMMIT)
735
784
  flush()
736
785
  read_response() do |data|
@@ -769,7 +818,7 @@ module Neo4jBolt
769
818
  end
770
819
  transaction do
771
820
  assert(@state == ServerState::TX_READY || @state == ServerState::TX_STREAMING || @state == ServerState::FAILED)
772
- append_uint8(0xb1)
821
+ append_uint8(0xb3)
773
822
  append_token(BoltMarker::BOLT_RUN)
774
823
  append_s(query)
775
824
  # Because something might go wrong while filling the buffer with
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neo4j_bolt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Specht
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-09 00:00:00.000000000 Z
11
+ date: 2024-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec