7
7
import time
8
8
import errno
9
9
import socket
10
+ import copy
10
11
try :
11
12
import ssl
12
13
is_ssl_supported = True
55
56
REQUEST_TYPE_ERROR ,
56
57
IPROTO_GREETING_SIZE ,
57
58
ITERATOR_EQ ,
58
- ITERATOR_ALL
59
+ ITERATOR_ALL ,
60
+ IPROTO_CHUNK
59
61
)
60
62
from tarantool .error import (
61
63
Error ,
@@ -748,7 +750,7 @@ def _read_response(self):
748
750
# Read the packet
749
751
return self ._recv (length )
750
752
751
- def _send_request_wo_reconnect (self , request ):
753
+ def _send_request_wo_reconnect (self , request , pushed_data = [], on_push = None , on_push_res = [] ):
752
754
"""
753
755
Send request without trying to reconnect.
754
756
Reload schema, if required.
@@ -767,12 +769,30 @@ def _send_request_wo_reconnect(self, request):
767
769
768
770
assert isinstance (request , Request )
769
771
772
+ # Flag for detecting the last message as out-of-band.
773
+ iproto_chunk_detected = False
774
+
770
775
response = None
771
776
while True :
772
777
try :
773
- self ._socket .sendall (bytes (request ))
778
+ if not iproto_chunk_detected :
779
+ # If the last received message is out-of-band,
780
+ # the request will not be sent.
781
+ self ._socket .sendall (bytes (request ))
774
782
response = request .response_class (self , self ._read_response ())
775
- break
783
+ if response ._code == IPROTO_CHUNK :
784
+ # Сase of receiving an out-of-band message.
785
+ pushed_data .append (copy .deepcopy (response ._data ))
786
+ if callable (on_push ):
787
+ # Callback function with data from out-of-band
788
+ # message is being called.
789
+ on_push_res .append (on_push (copy .deepcopy (response ._data )))
790
+ iproto_chunk_detected = True
791
+ # Receiving the next message.
792
+ continue
793
+ else :
794
+ # Сase of receiving main message.
795
+ break
776
796
except SchemaReloadException as e :
777
797
self .update_schema (e .schema_version )
778
798
continue
@@ -851,7 +871,7 @@ def check(): # Check that connection is alive
851
871
self .wrap_socket_ssl ()
852
872
self .handshake ()
853
873
854
- def _send_request (self , request ):
874
+ def _send_request (self , request , pushed_data = [], on_push = None , on_push_res = [] ):
855
875
"""
856
876
Send a request to the server through the socket.
857
877
@@ -872,7 +892,7 @@ def _send_request(self, request):
872
892
873
893
self ._opt_reconnect ()
874
894
875
- return self ._send_request_wo_reconnect (request )
895
+ return self ._send_request_wo_reconnect (request , pushed_data , on_push , on_push_res )
876
896
877
897
def load_schema (self ):
878
898
"""
@@ -914,7 +934,7 @@ def flush_schema(self):
914
934
self .schema .flush ()
915
935
self .load_schema ()
916
936
917
- def call (self , func_name , * args ):
937
+ def call (self , func_name , * args , ** kwargs ):
918
938
"""
919
939
Execute a CALL request: call a stored Lua function.
920
940
@@ -930,19 +950,30 @@ def call(self, func_name, *args):
930
950
:exc:`~tarantool.error.SchemaError`,
931
951
:exc:`~tarantool.error.NetworkError`,
932
952
:exc:`~tarantool.error.SslError`
953
+
954
+ !!!
955
+ TODO: write docs
956
+ !!!
933
957
"""
934
958
935
959
assert isinstance (func_name , str )
936
960
937
961
# This allows to use a tuple or list as an argument
938
962
if len (args ) == 1 and isinstance (args [0 ], (list , tuple )):
939
963
args = args [0 ]
964
+ # Case for absence of optional arg for accepting out-of-band msg data
965
+ if not 'pushed_data' in kwargs :
966
+ kwargs ['pushed_data' ] = []
967
+ if not 'on_push' in kwargs :
968
+ kwargs ['on_push' ] = None
969
+ if not 'on_push_res' in kwargs :
970
+ kwargs ['on_push_res' ] = []
940
971
941
972
request = RequestCall (self , func_name , args , self .call_16 )
942
- response = self ._send_request (request )
973
+ response = self ._send_request (request , kwargs [ 'pushed_data' ], kwargs [ 'on_push' ], kwargs [ 'on_push_res' ] )
943
974
return response
944
975
945
- def eval (self , expr , * args ):
976
+ def eval (self , expr , * args , ** kwargs ):
946
977
"""
947
978
Execute an EVAL request: evaluate a Lua expression.
948
979
@@ -966,12 +997,19 @@ def eval(self, expr, *args):
966
997
# This allows to use a tuple or list as an argument
967
998
if len (args ) == 1 and isinstance (args [0 ], (list , tuple )):
968
999
args = args [0 ]
1000
+ # Case for absence of optional arg for accepting out-of-band msg data
1001
+ if not 'pushed_data' in kwargs :
1002
+ kwargs ['pushed_data' ] = []
1003
+ if not 'on_push' in kwargs :
1004
+ kwargs ['on_push' ] = None
1005
+ if not 'on_push_res' in kwargs :
1006
+ kwargs ['on_push_res' ] = []
969
1007
970
1008
request = RequestEval (self , expr , args )
971
- response = self ._send_request (request )
1009
+ response = self ._send_request (request , kwargs [ 'pushed_data' ], kwargs [ 'on_push' ], kwargs [ 'on_push_res' ] )
972
1010
return response
973
1011
974
- def replace (self , space_name , values ):
1012
+ def replace (self , space_name , values , ** kwargs ):
975
1013
"""
976
1014
Execute a REPLACE request: `replace`_ a tuple in the space.
977
1015
Doesn't throw an error if there is no tuple with the specified
@@ -994,10 +1032,18 @@ def replace(self, space_name, values):
994
1032
.. _replace: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/replace/
995
1033
"""
996
1034
1035
+ # Case for absence of optional arg for accepting out-of-band msg data
1036
+ if not 'pushed_data' in kwargs :
1037
+ kwargs ['pushed_data' ] = []
1038
+ if not 'on_push' in kwargs :
1039
+ kwargs ['on_push' ] = None
1040
+ if not 'on_push_res' in kwargs :
1041
+ kwargs ['on_push_res' ] = []
1042
+
997
1043
if isinstance (space_name , str ):
998
1044
space_name = self .schema .get_space (space_name ).sid
999
1045
request = RequestReplace (self , space_name , values )
1000
- return self ._send_request (request )
1046
+ return self ._send_request (request , kwargs [ 'pushed_data' ], kwargs [ 'on_push' ], kwargs [ 'on_push_res' ] )
1001
1047
1002
1048
def authenticate (self , user , password ):
1003
1049
"""
@@ -1149,7 +1195,7 @@ def subscribe(self, cluster_uuid, server_uuid, vclock=None):
1149
1195
return
1150
1196
self .close () # close connection after SUBSCRIBE
1151
1197
1152
- def insert (self , space_name , values ):
1198
+ def insert (self , space_name , values , ** kwargs ):
1153
1199
"""
1154
1200
Execute an INSERT request: `insert`_ a tuple to the space.
1155
1201
Throws an error if there is already a tuple with the same
@@ -1172,12 +1218,20 @@ def insert(self, space_name, values):
1172
1218
.. _insert: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/insert/
1173
1219
"""
1174
1220
1221
+ # Case for absence of optional arg for accepting out-of-band msg data
1222
+ if not 'pushed_data' in kwargs :
1223
+ kwargs ['pushed_data' ] = []
1224
+ if not 'on_push' in kwargs :
1225
+ kwargs ['on_push' ] = None
1226
+ if not 'on_push_res' in kwargs :
1227
+ kwargs ['on_push_res' ] = []
1228
+
1175
1229
if isinstance (space_name , str ):
1176
1230
space_name = self .schema .get_space (space_name ).sid
1177
1231
request = RequestInsert (self , space_name , values )
1178
- return self ._send_request (request )
1232
+ return self ._send_request (request , kwargs [ 'pushed_data' ], kwargs [ 'on_push' ], kwargs [ 'on_push_res' ] )
1179
1233
1180
- def delete (self , space_name , key , * , index = 0 ):
1234
+ def delete (self , space_name , key , * , index = 0 , ** kwargs ):
1181
1235
"""
1182
1236
Execute a DELETE request: `delete`_ a tuple in the space.
1183
1237
@@ -1202,15 +1256,23 @@ def delete(self, space_name, key, *, index=0):
1202
1256
.. _delete: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/delete/
1203
1257
"""
1204
1258
1259
+ # Case for absence of optional arg for accepting out-of-band msg data
1260
+ if not 'pushed_data' in kwargs :
1261
+ kwargs ['pushed_data' ] = []
1262
+ if not 'on_push' in kwargs :
1263
+ kwargs ['on_push' ] = None
1264
+ if not 'on_push_res' in kwargs :
1265
+ kwargs ['on_push_res' ] = []
1266
+
1205
1267
key = check_key (key )
1206
1268
if isinstance (space_name , str ):
1207
1269
space_name = self .schema .get_space (space_name ).sid
1208
1270
if isinstance (index , str ):
1209
1271
index = self .schema .get_index (space_name , index ).iid
1210
1272
request = RequestDelete (self , space_name , index , key )
1211
- return self ._send_request (request )
1273
+ return self ._send_request (request , kwargs [ 'pushed_data' ], kwargs [ 'on_push' ], kwargs [ 'on_push_res' ] )
1212
1274
1213
- def upsert (self , space_name , tuple_value , op_list , * , index = 0 ):
1275
+ def upsert (self , space_name , tuple_value , op_list , * , index = 0 , ** kwargs ):
1214
1276
"""
1215
1277
Execute an UPSERT request: `upsert`_ a tuple to the space.
1216
1278
@@ -1252,16 +1314,24 @@ def upsert(self, space_name, tuple_value, op_list, *, index=0):
1252
1314
.. _upsert: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/upsert/
1253
1315
"""
1254
1316
1317
+ # Case for absence of optional arg for accepting out-of-band msg data
1318
+ if not 'pushed_data' in kwargs :
1319
+ kwargs ['pushed_data' ] = []
1320
+ if not 'on_push' in kwargs :
1321
+ kwargs ['on_push' ] = None
1322
+ if not 'on_push_res' in kwargs :
1323
+ kwargs ['on_push_res' ] = []
1324
+
1255
1325
if isinstance (space_name , str ):
1256
1326
space_name = self .schema .get_space (space_name ).sid
1257
1327
if isinstance (index , str ):
1258
1328
index = self .schema .get_index (space_name , index ).iid
1259
1329
op_list = self ._ops_process (space_name , op_list )
1260
1330
request = RequestUpsert (self , space_name , index , tuple_value ,
1261
1331
op_list )
1262
- return self ._send_request (request )
1332
+ return self ._send_request (request , kwargs [ 'pushed_data' ], kwargs [ 'on_push' ], kwargs [ 'on_push_res' ] )
1263
1333
1264
- def update (self , space_name , key , op_list , * , index = 0 ):
1334
+ def update (self , space_name , key , op_list , * , index = 0 , ** kwargs ):
1265
1335
"""
1266
1336
Execute an UPDATE request: `update`_ a tuple in the space.
1267
1337
@@ -1331,14 +1401,22 @@ def update(self, space_name, key, op_list, *, index=0):
1331
1401
.. _update: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/update/
1332
1402
"""
1333
1403
1404
+ # Case for absence of optional arg for accepting out-of-band msg data
1405
+ if not 'pushed_data' in kwargs :
1406
+ kwargs ['pushed_data' ] = []
1407
+ if not 'on_push' in kwargs :
1408
+ kwargs ['on_push' ] = None
1409
+ if not 'on_push_res' in kwargs :
1410
+ kwargs ['on_push_res' ] = []
1411
+
1334
1412
key = check_key (key )
1335
1413
if isinstance (space_name , str ):
1336
1414
space_name = self .schema .get_space (space_name ).sid
1337
1415
if isinstance (index , str ):
1338
1416
index = self .schema .get_index (space_name , index ).iid
1339
1417
op_list = self ._ops_process (space_name , op_list )
1340
1418
request = RequestUpdate (self , space_name , index , key , op_list )
1341
- return self ._send_request (request )
1419
+ return self ._send_request (request , kwargs [ 'pushed_data' ], kwargs [ 'on_push' ], kwargs [ 'on_push_res' ] )
1342
1420
1343
1421
def ping (self , notime = False ):
1344
1422
"""
@@ -1368,7 +1446,7 @@ def ping(self, notime=False):
1368
1446
return "Success"
1369
1447
return t1 - t0
1370
1448
1371
- def select (self , space_name , key = None , * , offset = 0 , limit = 0xffffffff , index = 0 , iterator = None ):
1449
+ def select (self , space_name , key = None , * , offset = 0 , limit = 0xffffffff , index = 0 , iterator = None , ** kwargs ):
1372
1450
"""
1373
1451
Execute a SELECT request: `select`_ a tuple from the space.
1374
1452
@@ -1518,13 +1596,21 @@ def select(self, space_name, key=None, *, offset=0, limit=0xffffffff, index=0, i
1518
1596
# tuples)
1519
1597
key = check_key (key , select = True )
1520
1598
1599
+ # Case for absence of optional arg for accepting out-of-band msg data
1600
+ if not 'pushed_data' in kwargs :
1601
+ kwargs ['pushed_data' ] = []
1602
+ if not 'on_push' in kwargs :
1603
+ kwargs ['on_push' ] = None
1604
+ if not 'on_push_res' in kwargs :
1605
+ kwargs ['on_push_res' ] = []
1606
+
1521
1607
if isinstance (space_name , str ):
1522
1608
space_name = self .schema .get_space (space_name ).sid
1523
1609
if isinstance (index , str ):
1524
1610
index = self .schema .get_index (space_name , index ).iid
1525
1611
request = RequestSelect (self , space_name , index , key , offset ,
1526
1612
limit , iterator )
1527
- response = self ._send_request (request )
1613
+ response = self ._send_request (request , kwargs [ 'pushed_data' ], kwargs [ 'on_push' ], kwargs [ 'on_push_res' ] )
1528
1614
return response
1529
1615
1530
1616
def space (self , space_name ):
0 commit comments