From f96848a9fb4537e01994c096659541a967dd749f Mon Sep 17 00:00:00 2001 From: Manuel Kaufmann Date: Mon, 17 Sep 2012 14:19:02 +0000 Subject: Cancel a download if space is very tight SL #394 It checks for enough space[1] before downloading the file. If there is no enough space, Browse will cancel the download process before starting it and an Alert will be shown to the user to inform this situation. [1] this check is: free_space - file_to_download > 50Mb Signed-off-by: Manuel Kaufmann Acked-by: Manuel QuiƱones --- diff --git a/downloadmanager.py b/downloadmanager.py index 9950c16..155864a 100644 --- a/downloadmanager.py +++ b/downloadmanager.py @@ -38,6 +38,8 @@ DS_DBUS_PATH = '/org/laptop/sugar/DataStore' _active_downloads = [] _dest_to_window = {} +SPACE_THRESHOLD = 52428800 + def can_quit(): return len(_active_downloads) == 0 @@ -61,7 +63,6 @@ class Download(object): self._activity = browser.get_toplevel() self._source = download.get_uri() - self._download.connect('notify::progress', self.__progress_change_cb) self._download.connect('notify::status', self.__state_change_cb) self._download.connect('error', self.__error_cb) @@ -74,16 +75,18 @@ class Download(object): self._stop_alert = None # figure out download URI - temp_path = os.path.join(activity.get_activity_root(), 'instance') - if not os.path.exists(temp_path): - os.makedirs(temp_path) + self.temp_path = os.path.join(activity.get_activity_root(), 'instance') + if not os.path.exists(self.temp_path): + os.makedirs(self.temp_path) - fd, self._dest_path = tempfile.mkstemp(dir=temp_path, + fd, self._dest_path = tempfile.mkstemp(dir=self.temp_path, suffix=download.get_suggested_filename(), prefix='tmp') os.close(fd) logging.debug('Download destination path: %s' % self._dest_path) + # We have to start the download to get 'total-size' + # property. It not, 0 is returned self._download.set_destination_uri('file://' + self._dest_path) self._download.start() @@ -95,17 +98,50 @@ class Download(object): def __state_change_cb(self, download, gparamspec): state = self._download.get_status() if state == WebKit.DownloadStatus.STARTED: - self._create_journal_object() - self._object_id = self.dl_jobject.object_id - - alert = TimeoutAlert(9) - alert.props.title = _('Download started') - alert.props.msg = _('%s' % self._download.get_suggested_filename()) - self._activity.add_alert(alert) - alert.connect('response', self.__start_response_cb) - alert.show() - global _active_downloads - _active_downloads.append(self) + # Check free space and cancel the download if there is not enough. + total_size = self._download.get_total_size() + logging.debug('Total size of the file: %s', total_size) + enough_space = self.enough_space( + total_size, path=self.temp_path) + if not enough_space: + logging.debug('Download canceled because of Disk Space') + self.cancel() + + self._canceled_alert = Alert() + self._canceled_alert.props.title = _('Not enough space ' + 'to download') + + total_size_mb = total_size / 1024.0 ** 2 + free_space_mb = self._free_available_space( + path=self.temp_path) - SPACE_THRESHOLD \ + / 1024.0 ** 2 + filename = self._download.get_suggested_filename() + self._canceled_alert.props.msg = \ + _('Download "%s" requires %.2f MB of free space, only ' + '%.2f MB is available' % (filename, total_size_mb, + free_space_mb)) + ok_icon = Icon(icon_name='dialog-ok') + self._canceled_alert.add_button(Gtk.ResponseType.OK, + _('Ok'), ok_icon) + ok_icon.show() + self._canceled_alert.connect('response', + self.__stop_response_cb) + self._activity.add_alert(self._canceled_alert) + else: + self._download.connect('notify::progress', + self.__progress_change_cb) + self._create_journal_object() + self._object_id = self.dl_jobject.object_id + + alert = TimeoutAlert(9) + alert.props.title = _('Download started') + alert.props.msg = _('%s' % + self._download.get_suggested_filename()) + self._activity.add_alert(alert) + alert.connect('response', self.__start_response_cb) + alert.show() + global _active_downloads + _active_downloads.append(self) elif state == WebKit.DownloadStatus.FINISHED: self._stop_alert = Alert() @@ -197,6 +233,26 @@ class Download(object): def cancel(self): self._download.cancel() + def enough_space(self, size, path='/'): + """Check if there is enough (size) free space on path + + size -- free space requested in Kb + + path -- device where the check will be done. For example: '/tmp' + + This method is useful to check the free space, for example, + before starting a download from internet, creating a big map + in some game or whatever action that needs some space in the + Hard Disk. + """ + + free_space = self._free_available_space(path=path) + return free_space - size > SPACE_THRESHOLD + + def _free_available_space(self, path='/'): + s = os.statvfs(path) + return s.f_bavail * s.f_frsize + def _create_journal_object(self): self.dl_jobject = datastore.create() self.dl_jobject.metadata['title'] = \ -- cgit v0.9.1