mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 14:18:26 +02:00
Send a response indicating transmission was successful
This commit is contained in:
@@ -201,6 +201,11 @@ class ActiveCommand:
|
|||||||
def __init__(self, ftc: FileTransmissionCommand) -> None:
|
def __init__(self, ftc: FileTransmissionCommand) -> None:
|
||||||
self.ftc = ftc
|
self.ftc = ftc
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
if self.file is not None:
|
||||||
|
self.file.close()
|
||||||
|
self.file = None
|
||||||
|
|
||||||
|
|
||||||
class FileTransmission:
|
class FileTransmission:
|
||||||
|
|
||||||
@@ -210,6 +215,11 @@ class FileTransmission:
|
|||||||
self.window_id = window_id
|
self.window_id = window_id
|
||||||
self.active_cmds = {}
|
self.active_cmds = {}
|
||||||
|
|
||||||
|
def __del__(self) -> None:
|
||||||
|
for cmd in self.active_cmds.values():
|
||||||
|
cmd.close()
|
||||||
|
self.active_cmds = {}
|
||||||
|
|
||||||
def handle_serialized_command(self, data: str) -> None:
|
def handle_serialized_command(self, data: str) -> None:
|
||||||
try:
|
try:
|
||||||
cmd = parse_command(data)
|
cmd = parse_command(data)
|
||||||
@@ -227,9 +237,16 @@ class FileTransmission:
|
|||||||
if cmd.id not in self.active_cmds:
|
if cmd.id not in self.active_cmds:
|
||||||
log_error('File transmission data command received with unknown id')
|
log_error('File transmission data command received with unknown id')
|
||||||
return
|
return
|
||||||
|
try:
|
||||||
self.add_data(cmd)
|
self.add_data(cmd)
|
||||||
|
except Exception:
|
||||||
|
self.abort_in_flight(cmd.id)
|
||||||
|
raise
|
||||||
if cmd.action is Action.end_data and cmd.id in self.active_cmds:
|
if cmd.action is Action.end_data and cmd.id in self.active_cmds:
|
||||||
|
try:
|
||||||
self.commit(cmd.id)
|
self.commit(cmd.id)
|
||||||
|
except Exception:
|
||||||
|
self.abort_in_flight(cmd.id)
|
||||||
|
|
||||||
def send_response(self, ac: Optional[FileTransmissionCommand], **fields: str) -> None:
|
def send_response(self, ac: Optional[FileTransmissionCommand], **fields: str) -> None:
|
||||||
if ac is None:
|
if ac is None:
|
||||||
@@ -263,6 +280,7 @@ class FileTransmission:
|
|||||||
if cmd.ftc.quiet:
|
if cmd.ftc.quiet:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
|
cmd.close()
|
||||||
del self.active_cmds[cmd_id]
|
del self.active_cmds[cmd_id]
|
||||||
if cmd.ftc.quiet > 1:
|
if cmd.ftc.quiet > 1:
|
||||||
return
|
return
|
||||||
@@ -274,13 +292,18 @@ class FileTransmission:
|
|||||||
errname = errno.errorcode.get(err.errno, 'EFAIL')
|
errname = errno.errorcode.get(err.errno, 'EFAIL')
|
||||||
self.send_response(ac, status=f'{errname}:{msg}')
|
self.send_response(ac, status=f'{errname}:{msg}')
|
||||||
|
|
||||||
|
def abort_in_flight(self, cmd_id: str) -> None:
|
||||||
|
c = self.active_cmds.pop(cmd_id, None)
|
||||||
|
if c is not None:
|
||||||
|
c.close()
|
||||||
|
|
||||||
def add_data(self, cmd: FileTransmissionCommand) -> None:
|
def add_data(self, cmd: FileTransmissionCommand) -> None:
|
||||||
ac = self.active_cmds.get(cmd.id)
|
ac = self.active_cmds.get(cmd.id)
|
||||||
|
|
||||||
def abort_in_flight() -> None:
|
def abort_in_flight() -> None:
|
||||||
self.active_cmds.pop(cmd.id, None)
|
self.abort_in_flight(cmd.id)
|
||||||
|
|
||||||
if ac is None or not ac.dest:
|
if ac is None or not ac.dest or ac.ftc.action is not Action.send:
|
||||||
return abort_in_flight()
|
return abort_in_flight()
|
||||||
|
|
||||||
if ac.file is None:
|
if ac.file is None:
|
||||||
@@ -310,9 +333,20 @@ class FileTransmission:
|
|||||||
|
|
||||||
def commit(self, cmd_id: str) -> None:
|
def commit(self, cmd_id: str) -> None:
|
||||||
cmd = self.active_cmds.pop(cmd_id, None)
|
cmd = self.active_cmds.pop(cmd_id, None)
|
||||||
if cmd is not None and cmd.ftc.container_fmt and cmd.file is not None:
|
if cmd is not None:
|
||||||
|
try:
|
||||||
|
if cmd.ftc.container_fmt is not Container.none and cmd.file is not None:
|
||||||
cmd.file.seek(0, os.SEEK_SET)
|
cmd.file.seek(0, os.SEEK_SET)
|
||||||
|
try:
|
||||||
Container.extractor_for_container_fmt(cmd.file, cmd.ftc.container_fmt)(cmd.dest)
|
Container.extractor_for_container_fmt(cmd.file, cmd.ftc.container_fmt)(cmd.dest)
|
||||||
|
except OSError as e:
|
||||||
|
self.send_fail_on_os_error(cmd.ftc, e, 'Failed to extract files from container')
|
||||||
|
except Exception:
|
||||||
|
self.send_response(cmd.ftc, status='EFAIL:Failed to extract files from container')
|
||||||
|
if not cmd.ftc.quiet:
|
||||||
|
self.send_response(cmd.ftc, status='COMPLETED')
|
||||||
|
finally:
|
||||||
|
cmd.close()
|
||||||
|
|
||||||
|
|
||||||
class TestFileTransmission(FileTransmission):
|
class TestFileTransmission(FileTransmission):
|
||||||
|
|||||||
@@ -36,8 +36,24 @@ class TestFileTransmission(BaseTest):
|
|||||||
shutil.rmtree(self.tdir)
|
shutil.rmtree(self.tdir)
|
||||||
|
|
||||||
def test_file_put(self):
|
def test_file_put(self):
|
||||||
|
# send refusal
|
||||||
|
for quiet in (0, 1, 2):
|
||||||
ft = FileTransmission()
|
ft = FileTransmission()
|
||||||
ft.handle_serialized_command(serialized_cmd(action='send', id='1', dest=os.path.join(self.tdir, '1.bin')))
|
ft.handle_serialized_command(serialized_cmd(action='send', id='x', quiet=quiet))
|
||||||
self.assertIn('1', ft.active_cmds)
|
self.ae(ft.test_responses, [] if quiet == 2 else [{'status': 'EPERM:User refused the transfer', 'id': 'x'}])
|
||||||
self.ae(os.path.basename(ft.active_cmds['1'].dest), '1.bin')
|
self.assertFalse(ft.active_cmds)
|
||||||
self.assertIsNone(ft.active_cmds['1'].file)
|
# simple single file send
|
||||||
|
ft = FileTransmission()
|
||||||
|
dest = os.path.join(self.tdir, '1.bin')
|
||||||
|
ft.handle_serialized_command(serialized_cmd(action='send', dest=dest))
|
||||||
|
self.assertIn('', ft.active_cmds)
|
||||||
|
self.ae(os.path.basename(ft.active_cmds[''].dest), '1.bin')
|
||||||
|
self.assertIsNone(ft.active_cmds[''].file)
|
||||||
|
self.ae(ft.test_responses, [{'status': 'OK'}])
|
||||||
|
ft.handle_serialized_command(serialized_cmd(action='data', data='abcd'))
|
||||||
|
self.assertIsNotNone(ft.active_cmds[''].file)
|
||||||
|
ft.handle_serialized_command(serialized_cmd(action='end_data', data='123'))
|
||||||
|
self.assertFalse(ft.active_cmds)
|
||||||
|
self.ae(ft.test_responses, [{'status': 'OK'}, {'status': 'COMPLETED'}])
|
||||||
|
with open(dest) as f:
|
||||||
|
self.ae(f.read(), 'abcd123')
|
||||||
|
|||||||
Reference in New Issue
Block a user