blob: 5c51f2507b4b7c0d3a1a7b9592aa69c188bbd1b6 [file]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
from gremlin_python.driver.connection import GremlinServerError
from gremlin_python.process.traversal import Traverser
from gremlin_python.structure.io import graphbinaryV4
from gremlin_python.structure.io.util import Marker
__author__ = 'David M. Brown (davebshow@gmail.com), Lyndon Bauto (lyndonb@bitquilltech.com)'
"""
GraphBinaryV4
"""
class GraphBinarySerializersV4(object):
DEFAULT_READER_CLASS = graphbinaryV4.GraphBinaryReader
DEFAULT_WRITER_CLASS = graphbinaryV4.GraphBinaryWriter
DEFAULT_VERSION = b"application/vnd.graphbinary-v4.0"
int_pack = graphbinaryV4.int32_pack
def __init__(self, reader=None, writer=None, version=None):
if not version:
version = self.DEFAULT_VERSION
self._version = version
if not reader:
reader = self.DEFAULT_READER_CLASS()
self._graphbinary_reader = reader
if not writer:
writer = self.DEFAULT_WRITER_CLASS()
self._graphbinary_writer = writer
@property
def version(self):
"""Read only property"""
return self._version
def serialize_message(self, request_message):
message = self.build_message(request_message.fields, request_message.gremlin)
return message
def build_message(self, fields, gremlin):
message = {
'fields': fields,
'gremlin': gremlin
}
return self.finalize_message(message)
def finalize_message(self, message):
ba = bytearray()
ba.extend(graphbinaryV4.uint8_pack(0x84))
fields = message["fields"]
ba.extend(self.int_pack(len(fields)))
for k, v in fields.items():
self._graphbinary_writer.to_dict(k, ba)
self._graphbinary_writer.to_dict(v, ba)
gremlin = message['gremlin']
# TODO: hack to remove type code from gremlin value for V4 message format, writer doesn't seem to have a way to
# write value directly by passing serializer types, check back when removing bytecode
gremlin_ba = bytearray()
self._graphbinary_writer.to_dict(gremlin, gremlin_ba)
ba.extend(gremlin_ba[2:])
return bytes(ba)
def deserialize_response_stream(self, stream):
"""
Yield each result item from a GraphBinary response stream as it is read
off the wire, then raise ``GremlinServerError`` if the trailing status
is not a success code. ``Connection._receive`` dispatches through this
method so custom response serializers can replace GraphBinary parsing.
"""
reader = self._graphbinary_reader
# Response header: version byte + flags byte
stream.read(1)
flags = stream.read(1)[0]
bulked = flags == 0x01
while True:
obj = reader.to_object(stream)
if obj == Marker.end_of_stream():
break
if bulked:
bulk = reader.to_object(stream)
yield Traverser(obj, bulk)
else:
yield obj
# Trailer: status code, message, exception
status_code = graphbinaryV4.int32_unpack(stream.read(4))
msg_is_null = stream.read(1)[0] == 0x01
status_message = '' if msg_is_null else reader.to_object(
stream, graphbinaryV4.DataType.string, False)
exc_is_null = stream.read(1)[0] == 0x01
status_exception = '' if exc_is_null else reader.to_object(
stream, graphbinaryV4.DataType.string, False)
if status_code not in (200, 204):
raise GremlinServerError({
'code': status_code,
'message': status_message,
'exception': status_exception
})