[gnome-boxes/wip/download: 3/3] TMP: Move download functionality to download.vala



commit b40e6ce254c80622857dfba411a34a7657781a35
Author: Lasse Schuirmann <lasse schuirmann gmail com>
Date:   Mon Oct 13 14:38:14 2014 +0200

    TMP: Move download functionality to download.vala
    
    Let the downloader only handle all downloads.
    
    This commit may not compile, it is work in progress.

 src/download.vala |  140 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 133 insertions(+), 7 deletions(-)
---
diff --git a/src/download.vala b/src/download.vala
index 9dd10e2..334b0b3 100644
--- a/src/download.vala
+++ b/src/download.vala
@@ -1,16 +1,142 @@
 // This file is part of GNOME Boxes. License: LGPLv2+
 
-private class Boxes.Download {
-    public string uri;
-    public File remote_file;
-    public File cached_file;
-    public ActivityProgress progress;
+private class Boxes.Download : GLib.Object {
+    private string uri { public get; }
+    protected File remote_file;
+    protected File local_file;
+    protected File cache_file;
 
-    public Download (File remote_file, File cached_file, ActivityProgress progress) {
+    protected ActivityProgress progress;
+    protected Cancellable? cancellable;
+
+    protected bool downloading { public get; }
+
+    public signal void download_successful ();
+    public signal void download_failed (GLib.Error error);
+
+    protected Mutex mutex = new Mutex ();
+
+
+    /**
+     * Can be used to download files.
+     *
+     * @param uri: The URI to download.
+     * @param local_file: The target file. (Will be overwritten.)
+     * @param cache_file: The temporary download file. Defaults to null which will be a file corresponding 
to the
+     *                    local_file.get_uri () + "~" path.
+     * @param progress: The ActivityProgress object to report progress to.
+     * @param cancellable: The Cancellable object for cancellation.
+     */
+    public Download (File              remote_file,
+                     File              local_file,
+                     File?             cache_file  = null,
+                     ActivityProgress? progress    = new ActivityProgress (),
+                     Cancellable?      cancellable = null) {
         this.remote_file = remote_file;
         this.uri = remote_file.get_uri ();
-        this.cached_file = cached_file;
+        this.local_file  = local_file;
+        this.cache_file  = cache_file ?? GLib.File.new_for_path (local_file.get_uri () + "~");
         this.progress = progress;
+        this.cancellable = cancellable;
+        this.downloading = false;
+    }
+
+    /**
+     * Downloads the file.
+     *
+     * If you want to override how the download works, override the download_cached () method and take a 
look at its
+     * documentation comment.
+     *
+     * @return The File object corresponding to the downloaded file.
+     */
+    public async File download () throws GLib.Error {
+        mutex.lock ();
+        {
+            downloading = true;
+        }
+        mutex.unlock ();
+
+        try {
+            download_cached ();
+
+            cache_file.move (local_file, FileCopyFlags.OVERWRITE, cancellable);
+        } catch (GLib.Error error) {
+            mutex.lock ();
+            {
+                downloading = false;
+                download_failed (error);
+            }
+            mutex.unlock ();
+
+            throw error;
+        }
+
+        mutex.lock ();
+        {
+            downloading = false;
+            download_successful ();
+        }
+        mutex.unlock ();
+
+        return local_file;
+    }
+
+    /**
+     * Waits until the current download is finished. This allows also to monitor the download.
+     *
+     * @param progress: An ActivityProgress object to monitor the download. It will not be connected to the 
download if
+     *                  the download is not active.
+     * @return The downloaded File object. Will be null if the download is not downloading anything.
+     */
+    public async File? await_download (ActivityProgress? progress = null) throws GLib.Error {
+        // Make sure that download_complete isnt called while we're preparing to listen
+        mutex.lock ();
+
+        if (!downloading)
+            mutex.unlock ();
+            debug ("Won't wait for download '%s' to finish since it is no active download.", uri);
+            return null;
+
+        try {
+            if (progress != null)
+                this.progress.bind_property ("progress", progress, "progress", BindingFlags.SYNC_CREATE);
+
+            GLib.Error download_error = null;
+            SourceFunc callback = await_download.callback;
+            var successful_id = download_successful.connect (() => { callback (); });
+            var failed_id = download_failed.connect((error) => { download_error = error; callback ();}
+        } finally {
+            mutex.unlock ();
+        }
+
+        debug ("'%s' already being downloaded. Waiting for download to complete..", uri);
+        // ATTENTION: Dont lock this.mutex below this yield statement since this will cause a deadlock
+        yield;
+        debug ("Finished waiting for '%s' to download.", uri);
+
+        disconnect (successful_id);
+        disconnect (failed_id);
+
+        if (download_error != null)
+            throw download_error;
+
+        return local_file;
+    }
+
+    protected async abstract void download_cached () throws GLib.Error;
+}
+
+private class Boxes.FilesystemDownload : GLib.Object, Boxes.Download {
+    public async override File download_cached () throws GLib.Error {
+            debug ("Copying '%s' to '%s'..", remote_file.get_path (), cache_file.get_path ());
+            yield remote_file.copy_async (cache_file,
+                                          FileCopyFlags.OVERWRITE,
+                                          Priority.DEFAULT,
+                                          cancellable,
+                                          (current, total) => {
+                progress.progress = (double) current / total;
+            });
+            debug ("Copied '%s' to '%s'.", remote_file.get_path (), cache_file.get_path ());
     }
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]