|
@@ -38,8 +38,7 @@ logger = create_logger(__name__)
|
|
|
|
|
|
RPC_PROTOCOL_VERSION = 2
|
|
|
BORG_VERSION = parse_version(__version__)
|
|
|
-MSGID, MSG, ARGS, RESULT = 'i', 'm', 'a', 'r' # pack
|
|
|
-MSGIDB, MSGB, ARGSB, RESULTB = b'i', b'm', b'a', b'r' # unpack
|
|
|
+MSGID, MSG, ARGS, RESULT = 'i', 'm', 'a', 'r'
|
|
|
|
|
|
MAX_INFLIGHT = 100
|
|
|
|
|
@@ -139,10 +138,6 @@ compatMap = {
|
|
|
}
|
|
|
|
|
|
|
|
|
-def decode_keys(d):
|
|
|
- return {k.decode(): d[k] for k in d}
|
|
|
-
|
|
|
-
|
|
|
class RepositoryServer: # pragma: no cover
|
|
|
rpc_methods = (
|
|
|
'__len__',
|
|
@@ -217,14 +212,13 @@ class RepositoryServer: # pragma: no cover
|
|
|
for unpacked in unpacker:
|
|
|
if isinstance(unpacked, dict):
|
|
|
dictFormat = True
|
|
|
- msgid = unpacked[MSGIDB]
|
|
|
- method = unpacked[MSGB].decode()
|
|
|
- args = decode_keys(unpacked[ARGSB])
|
|
|
+ msgid = unpacked[MSGID]
|
|
|
+ method = unpacked[MSG]
|
|
|
+ args = unpacked[ARGS]
|
|
|
elif isinstance(unpacked, tuple) and len(unpacked) == 4:
|
|
|
dictFormat = False
|
|
|
# The first field 'type' was always 1 and has always been ignored
|
|
|
_, msgid, method, args = unpacked
|
|
|
- method = method.decode()
|
|
|
args = self.positional_to_named(method, args)
|
|
|
else:
|
|
|
if self.repository is not None:
|
|
@@ -308,7 +302,7 @@ class RepositoryServer: # pragma: no cover
|
|
|
# clients since 1.1.0b3 use a dict as client_data
|
|
|
# clients since 1.1.0b6 support json log format from server
|
|
|
if isinstance(client_data, dict):
|
|
|
- self.client_version = client_data[b'client_version']
|
|
|
+ self.client_version = client_data['client_version']
|
|
|
level = logging.getLevelName(logging.getLogger('').level)
|
|
|
setup_logging(is_serve=True, json=True, level=level)
|
|
|
logger.debug('Initialized logging system for JSON-based protocol')
|
|
@@ -370,7 +364,6 @@ class RepositoryServer: # pragma: no cover
|
|
|
return self.repository.id
|
|
|
|
|
|
def inject_exception(self, kind):
|
|
|
- kind = kind.decode()
|
|
|
s1 = 'test string'
|
|
|
s2 = 'test string2'
|
|
|
if kind == 'DoesNotExist':
|
|
@@ -484,35 +477,35 @@ class RemoteRepository:
|
|
|
|
|
|
class RPCError(Exception):
|
|
|
def __init__(self, unpacked):
|
|
|
- # for borg < 1.1: unpacked only has b'exception_class' as key
|
|
|
- # for borg 1.1+: unpacked has keys: b'exception_args', b'exception_full', b'exception_short', b'sysinfo'
|
|
|
+ # for borg < 1.1: unpacked only has 'exception_class' as key
|
|
|
+ # for borg 1.1+: unpacked has keys: 'exception_args', 'exception_full', 'exception_short', 'sysinfo'
|
|
|
self.unpacked = unpacked
|
|
|
|
|
|
def get_message(self):
|
|
|
- if b'exception_short' in self.unpacked:
|
|
|
- return b'\n'.join(self.unpacked[b'exception_short']).decode()
|
|
|
+ if 'exception_short' in self.unpacked:
|
|
|
+ return '\n'.join(self.unpacked['exception_short'])
|
|
|
else:
|
|
|
return self.exception_class
|
|
|
|
|
|
@property
|
|
|
def traceback(self):
|
|
|
- return self.unpacked.get(b'exception_trace', True)
|
|
|
+ return self.unpacked.get('exception_trace', True)
|
|
|
|
|
|
@property
|
|
|
def exception_class(self):
|
|
|
- return self.unpacked[b'exception_class'].decode()
|
|
|
+ return self.unpacked['exception_class']
|
|
|
|
|
|
@property
|
|
|
def exception_full(self):
|
|
|
- if b'exception_full' in self.unpacked:
|
|
|
- return b'\n'.join(self.unpacked[b'exception_full']).decode()
|
|
|
+ if 'exception_full' in self.unpacked:
|
|
|
+ return '\n'.join(self.unpacked['exception_full'])
|
|
|
else:
|
|
|
return self.get_message() + '\nRemote Exception (see remote log for the traceback)'
|
|
|
|
|
|
@property
|
|
|
def sysinfo(self):
|
|
|
- if b'sysinfo' in self.unpacked:
|
|
|
- return self.unpacked[b'sysinfo'].decode()
|
|
|
+ if 'sysinfo' in self.unpacked:
|
|
|
+ return self.unpacked['sysinfo']
|
|
|
else:
|
|
|
return ''
|
|
|
|
|
@@ -577,9 +570,9 @@ class RemoteRepository:
|
|
|
raise ConnectionClosedWithHint('Is borg working on the server?') from None
|
|
|
if version == RPC_PROTOCOL_VERSION:
|
|
|
self.dictFormat = False
|
|
|
- elif isinstance(version, dict) and b'server_version' in version:
|
|
|
+ elif isinstance(version, dict) and 'server_version' in version:
|
|
|
self.dictFormat = True
|
|
|
- self.server_version = version[b'server_version']
|
|
|
+ self.server_version = version['server_version']
|
|
|
else:
|
|
|
raise Exception('Server insisted on using unsupported protocol version %s' % version)
|
|
|
|
|
@@ -734,9 +727,9 @@ This problem will go away as soon as the server has been upgraded to 1.0.7+.
|
|
|
return msgid
|
|
|
|
|
|
def handle_error(unpacked):
|
|
|
- error = unpacked[b'exception_class'].decode()
|
|
|
- old_server = b'exception_args' not in unpacked
|
|
|
- args = unpacked.get(b'exception_args')
|
|
|
+ error = unpacked['exception_class']
|
|
|
+ old_server = 'exception_args' not in unpacked
|
|
|
+ args = unpacked.get('exception_args')
|
|
|
|
|
|
if error == 'DoesNotExist':
|
|
|
raise Repository.DoesNotExist(self.location.processed)
|
|
@@ -748,29 +741,29 @@ This problem will go away as soon as the server has been upgraded to 1.0.7+.
|
|
|
if old_server:
|
|
|
raise IntegrityError('(not available)')
|
|
|
else:
|
|
|
- raise IntegrityError(args[0].decode())
|
|
|
+ raise IntegrityError(args[0])
|
|
|
elif error == 'AtticRepository':
|
|
|
if old_server:
|
|
|
raise Repository.AtticRepository('(not available)')
|
|
|
else:
|
|
|
- raise Repository.AtticRepository(args[0].decode())
|
|
|
+ raise Repository.AtticRepository(args[0])
|
|
|
elif error == 'PathNotAllowed':
|
|
|
if old_server:
|
|
|
raise PathNotAllowed('(unknown)')
|
|
|
else:
|
|
|
- raise PathNotAllowed(args[0].decode())
|
|
|
+ raise PathNotAllowed(args[0])
|
|
|
elif error == 'ParentPathDoesNotExist':
|
|
|
- raise Repository.ParentPathDoesNotExist(args[0].decode())
|
|
|
+ raise Repository.ParentPathDoesNotExist(args[0])
|
|
|
elif error == 'ObjectNotFound':
|
|
|
if old_server:
|
|
|
raise Repository.ObjectNotFound('(not available)', self.location.processed)
|
|
|
else:
|
|
|
- raise Repository.ObjectNotFound(args[0].decode(), self.location.processed)
|
|
|
+ raise Repository.ObjectNotFound(args[0], self.location.processed)
|
|
|
elif error == 'InvalidRPCMethod':
|
|
|
if old_server:
|
|
|
raise InvalidRPCMethod('(not available)')
|
|
|
else:
|
|
|
- raise InvalidRPCMethod(args[0].decode())
|
|
|
+ raise InvalidRPCMethod(args[0])
|
|
|
else:
|
|
|
raise self.RPCError(unpacked)
|
|
|
|
|
@@ -789,10 +782,10 @@ This problem will go away as soon as the server has been upgraded to 1.0.7+.
|
|
|
try:
|
|
|
unpacked = self.responses.pop(waiting_for[0])
|
|
|
waiting_for.pop(0)
|
|
|
- if b'exception_class' in unpacked:
|
|
|
+ if 'exception_class' in unpacked:
|
|
|
handle_error(unpacked)
|
|
|
else:
|
|
|
- yield unpacked[RESULTB]
|
|
|
+ yield unpacked[RESULT]
|
|
|
if not waiting_for and not calls:
|
|
|
return
|
|
|
except KeyError:
|
|
@@ -809,10 +802,10 @@ This problem will go away as soon as the server has been upgraded to 1.0.7+.
|
|
|
else:
|
|
|
return
|
|
|
else:
|
|
|
- if b'exception_class' in unpacked:
|
|
|
+ if 'exception_class' in unpacked:
|
|
|
handle_error(unpacked)
|
|
|
else:
|
|
|
- yield unpacked[RESULTB]
|
|
|
+ yield unpacked[RESULT]
|
|
|
if self.to_send or ((calls or self.preload_ids) and len(waiting_for) < MAX_INFLIGHT):
|
|
|
w_fds = [self.stdin_fd]
|
|
|
else:
|
|
@@ -829,26 +822,26 @@ This problem will go away as soon as the server has been upgraded to 1.0.7+.
|
|
|
self.unpacker.feed(data)
|
|
|
for unpacked in self.unpacker:
|
|
|
if isinstance(unpacked, dict):
|
|
|
- msgid = unpacked[MSGIDB]
|
|
|
+ msgid = unpacked[MSGID]
|
|
|
elif isinstance(unpacked, tuple) and len(unpacked) == 4:
|
|
|
# The first field 'type' was always 1 and has always been ignored
|
|
|
_, msgid, error, res = unpacked
|
|
|
if error:
|
|
|
# ignore res, because it is only a fixed string anyway.
|
|
|
- unpacked = {MSGIDB: msgid, b'exception_class': error}
|
|
|
+ unpacked = {MSGID: msgid, 'exception_class': error}
|
|
|
else:
|
|
|
- unpacked = {MSGIDB: msgid, RESULTB: res}
|
|
|
+ unpacked = {MSGID: msgid, RESULT: res}
|
|
|
else:
|
|
|
raise UnexpectedRPCDataFormatFromServer(data)
|
|
|
if msgid in self.ignore_responses:
|
|
|
self.ignore_responses.remove(msgid)
|
|
|
# async methods never return values, but may raise exceptions.
|
|
|
- if b'exception_class' in unpacked:
|
|
|
+ if 'exception_class' in unpacked:
|
|
|
self.async_responses[msgid] = unpacked
|
|
|
else:
|
|
|
# we currently do not have async result values except "None",
|
|
|
# so we do not add them into async_responses.
|
|
|
- if unpacked[RESULTB] is not None:
|
|
|
+ if unpacked[RESULT] is not None:
|
|
|
self.async_responses[msgid] = unpacked
|
|
|
else:
|
|
|
self.responses[msgid] = unpacked
|