Skip to content

Commit 85cbd86

Browse files
committed
Parse Tarantool version id from greeting
1 parent f5d7ed9 commit 85cbd86

File tree

3 files changed

+102
-8
lines changed

3 files changed

+102
-8
lines changed

tarantool/connection.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
import socket
1313
import msgpack
1414

15-
import base64
16-
1715
try:
1816
from ctypes import c_ssize_t
1917
except ImportError:
@@ -53,8 +51,8 @@
5351
RetryWarning,
5452
NetworkWarning)
5553

56-
from tarantool.schema import Schema
57-
from tarantool.utils import check_key
54+
from .schema import Schema
55+
from .utils import check_key, greeting_decode
5856

5957

6058
class Connection(object):
@@ -134,10 +132,15 @@ def connect_basic(self):
134132
raise NetworkError(e)
135133

136134
def handshake(self):
137-
greeting = self._recv(IPROTO_GREETING_SIZE)
138-
self._salt = base64.decodestring(greeting[64:])[:20]
139-
if self.user:
140-
self.authenticate(self.user, self.password)
135+
greeting_buf = self._recv(IPROTO_GREETING_SIZE)
136+
greeting = greeting_decode(greeting_buf)
137+
if greeting.protocol != "Binary":
138+
raise NetworkError("Unsupported protocol: " + greeting.protocol)
139+
self.version_id = greeting.version_id
140+
self.uuid = greeting.uuid
141+
self._salt = greeting.salt
142+
if self.user:
143+
self.authenticate(self.user, self.password)
141144

142145
def connect(self):
143146
'''

tarantool/utils.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# -*- coding: utf-8 -*-
22

33
import six
4+
import base64
5+
import uuid
46

57
def check_key(*args, **kwargs):
68
if 'first' not in kwargs:
@@ -18,3 +20,48 @@ def check_key(*args, **kwargs):
1820
for key in args:
1921
assert isinstance(key, six.integer_types + six.string_types)
2022
return list(args)
23+
24+
def version_id(major, minor, patch):
25+
return (((major << 8) | minor) << 8) | patch
26+
27+
def greeting_decode(greeting_buf):
28+
class Greeting:
29+
version_id = 0
30+
protocol = None
31+
uuid = None
32+
salt = None
33+
34+
# Tarantool 1.6.6
35+
# Tarantool 1.6.6-102-g4e9bde2
36+
# Tarantool 1.6.8 (Binary) 3b151c25-4c4a-4b5d-8042-0f1b3a6f61c3
37+
# Tarantool 1.6.8-132-g82f5424 (Lua console)
38+
result = Greeting()
39+
try:
40+
(product, _, tail) = greeting_buf[0:63].partition(' ')
41+
if product.startswith("Tarantool "):
42+
raise Exception()
43+
# Parse a version string - 1.6.6-83-gc6b2129 or 1.6.7
44+
(version, _, tail) = tail.partition(' ')
45+
version = version.split('-')[0].split('.')
46+
result.version_id = version_id(int(version[0]), int(version[1]),
47+
int(version[2]))
48+
if len(tail) > 0 and tail[0] == '(':
49+
(protocol, _, tail) = tail[1:].partition(') ')
50+
# Extract protocol name - a string between (parentheses)
51+
result.protocol = protocol
52+
if result.protocol != "Binary":
53+
return result
54+
# Parse UUID for binary protocol
55+
(uuid_buf, _, tail) = tail.partition(' ')
56+
if result.version_id >= version_id(1, 6, 7):
57+
result.uuid = uuid.UUID(uuid_buf.strip())
58+
elif result.version_id < version_id(1, 6, 7):
59+
# Tarantool < 1.6.7 doesn't add "(Binary)" to greeting
60+
result.protocol = "Binary"
61+
elif len(tail.strip()) != 0:
62+
raise Exception("x") # Unsuported greeting
63+
result.salt = base64.decodestring(greeting_buf[64:])[:20]
64+
return result
65+
except Exception as e:
66+
print('exx', e)
67+
raise ValueError("Invalid greeting: " + greeting_buf)

tests/suites/test_protocol.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env ipython
2+
3+
import unittest
4+
from tarantool.utils import greeting_decode, version_id
5+
import uuid
6+
7+
class TestSuite_Protocol(unittest.TestCase):
8+
9+
def test_00_greeting_1_6(self):
10+
buf = "Tarantool 1.6.6 \n" + \
11+
"AtQnb9SAIaKazZZy9lJKvK3urtbjCEJndhRVbslSPGc= \n";
12+
greeting = greeting_decode(buf)
13+
self.assertEqual(greeting.version_id, version_id(1, 6, 6))
14+
self.assertEqual(greeting.protocol, "Binary")
15+
self.assertIsNone(greeting.uuid)
16+
self.assertIsNotNone(greeting.salt)
17+
18+
def test_01_greeting_1_6_with_tag(self):
19+
buf = "Tarantool 1.6.6-232-gcf47324 \n" + \
20+
"AtQnb9SAIaKazZZy9lJKvK3urtbjCEJndhRVbslSPGc= \n";
21+
greeting = greeting_decode(buf)
22+
self.assertEqual(greeting.version_id, version_id(1, 6, 6))
23+
self.assertEqual(greeting.protocol, "Binary")
24+
self.assertIsNone(greeting.uuid)
25+
self.assertIsNotNone(greeting.salt)
26+
27+
def test_02_greeting_1_6_console(self):
28+
buf = "Tarantool 1.6.6-132-g82f5424 (Lua console) \n" + \
29+
"type 'help' for interactive help \n";
30+
greeting = greeting_decode(buf)
31+
self.assertEqual(greeting.version_id, version_id(1, 6, 6))
32+
self.assertEqual(greeting.protocol, "Lua console")
33+
self.assertIsNone(greeting.uuid)
34+
self.assertIsNone(greeting.salt)
35+
36+
def test_03_greeting_1_6_7(self):
37+
buf = "Tarantool 1.6.7 (Binary) 52dc2837-8001-48fe-bdce-c493c04599ce \n" + \
38+
"Z+2F+VRlyK1nKT82xQtxqEggMtkTK5RtPYf27JryRas= \n";
39+
greeting = greeting_decode(buf)
40+
self.assertEqual(greeting.version_id, version_id(1, 6, 7))
41+
self.assertEqual(greeting.protocol, "Binary")
42+
self.assertEqual(greeting.uuid,
43+
uuid.UUID('52dc2837-8001-48fe-bdce-c493c04599ce'))
44+
self.assertIsNotNone(greeting.salt)

0 commit comments

Comments
 (0)