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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/neo4j_bolt/version.rb +1 -1
- data/lib/neo4j_bolt.rb +85 -36
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 316d22f20084bb29755e8693c25860bd4d3afa5e5aadce5b89e415bf53157b82
|
4
|
+
data.tar.gz: 405c68b29be5578f7859cdc973b956ccb9898a4b7d105cc19b0e31e81c5615b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94766bfe86f3487582229ed0d11fa4c2bc813adac23fe1065c5dc026c692e3b82c859978b08d5dfb78915382d224425b7e7f81eb06f620eebb23014d8e4934b9
|
7
|
+
data.tar.gz: e144730f9cb75b44450c0dfb3b56d76698c9839e1f54a375c4e7608cb6eb7d6cf70d1544a7065a78d08c4d813387da66ec758bc1749d24037899233c80feb3d7
|
data/Gemfile.lock
CHANGED
data/lib/neo4j_bolt/version.rb
CHANGED
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
|
19
|
-
CONNECTED
|
20
|
-
DEFUNCT
|
21
|
-
READY
|
22
|
-
STREAMING
|
23
|
-
TX_READY
|
24
|
-
TX_STREAMING
|
25
|
-
FAILED
|
26
|
-
INTERRUPTED
|
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
|
-
@
|
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(
|
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.
|
644
|
-
version
|
645
|
-
|
646
|
-
raise "Unable to establish connection to Neo4j using Bolt
|
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(
|
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
|
-
|
661
|
-
@
|
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(
|
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
|
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(
|
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(
|
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(
|
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.
|
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-
|
11
|
+
date: 2024-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|