Don't close file prematurely

This commit is contained in:
Erik Johnston 2017-10-12 17:37:21 +01:00
parent e283b555b1
commit 802ca12d05
2 changed files with 18 additions and 8 deletions

View File

@ -97,16 +97,20 @@ class MediaRepository(object):
os.makedirs(dirname) os.makedirs(dirname)
@staticmethod @staticmethod
def write_file_synchronously(source, fname): def _write_file_synchronously(source, fname):
source.seek(0) # Ensure we read from the start of the file source.seek(0) # Ensure we read from the start of the file
with open(fname, "wb") as f: with open(fname, "wb") as f:
shutil.copyfileobj(source, f) shutil.copyfileobj(source, f)
source.close()
@defer.inlineCallbacks @defer.inlineCallbacks
def write_to_file(self, source, path): def write_to_file(self, source, path):
"""Write `source` to the on disk media store, and also the backup store """Write `source` to the on disk media store, and also the backup store
if configured. if configured.
Will close source once finished.
Args: Args:
source: A file like object that should be written source: A file like object that should be written
path: Relative path to write file to path: Relative path to write file to
@ -120,7 +124,7 @@ class MediaRepository(object):
# Write to the main repository # Write to the main repository
yield preserve_context_over_fn( yield preserve_context_over_fn(
threads.deferToThread, threads.deferToThread,
self.write_file_synchronously, source, fname, self._write_file_synchronously, source, fname,
) )
# Write to backup repository # Write to backup repository
@ -130,6 +134,10 @@ class MediaRepository(object):
@defer.inlineCallbacks @defer.inlineCallbacks
def copy_to_backup(self, source, path): def copy_to_backup(self, source, path):
"""Copy file like object source to the backup media store, if configured.
Will close source after its done.
"""
if self.backup_base_path: if self.backup_base_path:
backup_fname = os.path.join(self.backup_base_path, path) backup_fname = os.path.join(self.backup_base_path, path)
self._makedirs(backup_fname) self._makedirs(backup_fname)
@ -139,12 +147,14 @@ class MediaRepository(object):
if self.synchronous_backup_media_store: if self.synchronous_backup_media_store:
yield preserve_context_over_fn( yield preserve_context_over_fn(
threads.deferToThread, threads.deferToThread,
self.write_file_synchronously, source, backup_fname, self._write_file_synchronously, source, backup_fname,
) )
else: else:
preserve_fn(threads.deferToThread)( preserve_fn(threads.deferToThread)(
self.write_file_synchronously, source, backup_fname, self._write_file_synchronously, source, backup_fname,
) )
else:
source.close()
@defer.inlineCallbacks @defer.inlineCallbacks
def create_content(self, media_type, upload_name, content, content_length, def create_content(self, media_type, upload_name, content, content_length,
@ -248,8 +258,8 @@ class MediaRepository(object):
server_name, media_id) server_name, media_id)
raise SynapseError(502, "Failed to fetch remote media") raise SynapseError(502, "Failed to fetch remote media")
with open(fname) as f: # Will close the file after its done
yield self.copy_to_backup(f, fpath) yield self.copy_to_backup(open(fname), fpath)
media_type = headers["Content-Type"][0] media_type = headers["Content-Type"][0]
time_now_ms = self.clock.time_msec() time_now_ms = self.clock.time_msec()

View File

@ -275,8 +275,8 @@ class PreviewUrlResource(Resource):
) )
# FIXME: pass through 404s and other error messages nicely # FIXME: pass through 404s and other error messages nicely
with open(fname) as f: # Will close the file after its done
yield self.media_repo.copy_to_backup(f, fpath) yield self.media_repo.copy_to_backup(open(fname), fpath)
media_type = headers["Content-Type"][0] media_type = headers["Content-Type"][0]
time_now_ms = self.clock.time_msec() time_now_ms = self.clock.time_msec()