[rygel] core: Implement 'CreateObject' action of CDS



commit 054e14f466b8663de9b20504c17c61a53bf85a8b
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date:   Tue Jan 26 17:39:56 2010 +0200

    core: Implement 'CreateObject' action of CDS
    
    Currently we can only deal with 'no URI provided' case, i-e upload but OTOH
    actual uploading isn't implemented yet. :)

 data/xml/ContentDirectory.xml          |   26 +++---
 src/rygel/Makefile.am                  |    1 +
 src/rygel/rygel-content-directory.vala |   10 +++
 src/rygel/rygel-item-creator.vala      |  138 ++++++++++++++++++++++++++++++++
 src/rygel/rygel-media-container.vala   |   31 +++++++
 5 files changed, 193 insertions(+), 13 deletions(-)
---
diff --git a/data/xml/ContentDirectory.xml b/data/xml/ContentDirectory.xml
index c687d0d..a129d78 100644
--- a/data/xml/ContentDirectory.xml
+++ b/data/xml/ContentDirectory.xml
@@ -328,19 +328,6 @@ feature provided by your editor.
 			</argumentList>
 		</action>
 
-<!-- Optional actions that are not implemented yet
-                <action>
-			<Optional/>
-			<name>GetSortExtensionCapabilities</name>
-			<argumentList>
-				<argument>
-					<name>SortExtensionCaps</name>
-					<direction>out</direction>
-					<relatedStateVariable>SortExtensionCapabilities</relatedStateVariable>
-				</argument>
-			</argumentList>
-		</action>
-
 		<action>
 			<Optional/>
 			<name>CreateObject</name>
@@ -368,6 +355,19 @@ feature provided by your editor.
 			</argumentList>
 		</action>
 
+<!-- Optional actions that are not implemented yet
+                <action>
+			<Optional/>
+			<name>GetSortExtensionCapabilities</name>
+			<argumentList>
+				<argument>
+					<name>SortExtensionCaps</name>
+					<direction>out</direction>
+					<relatedStateVariable>SortExtensionCapabilities</relatedStateVariable>
+				</argument>
+			</argumentList>
+		</action>
+
 		<action>
 			<Optional/>
 			<name>DestroyObject</name>
diff --git a/src/rygel/Makefile.am b/src/rygel/Makefile.am
index e83b227..2f72214 100644
--- a/src/rygel/Makefile.am
+++ b/src/rygel/Makefile.am
@@ -75,6 +75,7 @@ VAPI_SOURCE_FILES = rygel-configuration.vala \
 		    rygel-thumbnailer.vala \
 		    rygel-browse.vala \
 		    rygel-search.vala \
+		    rygel-item-creator.vala \
 		    rygel-search-expression.vala \
 		    rygel-relational-expression.vala \
 		    rygel-logical-expression.vala \
diff --git a/src/rygel/rygel-content-directory.vala b/src/rygel/rygel-content-directory.vala
index 19a8da3..8615d35 100644
--- a/src/rygel/rygel-content-directory.vala
+++ b/src/rygel/rygel-content-directory.vala
@@ -30,6 +30,7 @@ using Gee;
  */
 public errordomain Rygel.ContentDirectoryError {
     NO_SUCH_OBJECT = 701,
+    RESTRICTED_PARENT = 713,
     CANT_PROCESS = 720,
     INVALID_ARGS = 402
 }
@@ -97,6 +98,7 @@ public class Rygel.ContentDirectory: Service {
 
         this.action_invoked["Browse"] += this.browse_cb;
         this.action_invoked["Search"] += this.search_cb;
+        this.action_invoked["CreateObject"] += this.create_object_cb;
 
         /* Connect SystemUpdateID related signals */
         this.action_invoked["GetSystemUpdateID"] +=
@@ -145,6 +147,14 @@ public class Rygel.ContentDirectory: Service {
         search.run.begin ();
     }
 
+    /* CreateObject action implementation */
+    private virtual void create_object_cb (ContentDirectory    content_dir,
+                                           owned ServiceAction action) {
+        var creator = new ItemCreator (this, action);
+
+        creator.run.begin ();
+    }
+
     /* GetSystemUpdateID action implementation */
     private void get_system_update_id_cb (ContentDirectory    content_dir,
                                           owned ServiceAction action) {
diff --git a/src/rygel/rygel-item-creator.vala b/src/rygel/rygel-item-creator.vala
new file mode 100644
index 0000000..a9e00ba
--- /dev/null
+++ b/src/rygel/rygel-item-creator.vala
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using GUPnP;
+
+/**
+ * CreateObject action implementation.
+ */
+internal class Rygel.ItemCreator: GLib.Object, Rygel.StateMachine {
+    // In arguments
+    public string container_id;
+    public string elements;
+
+    public DIDLLiteItem didl_item;
+    public MediaItem item;
+
+    private ContentDirectory content_dir;
+    private ServiceAction action;
+    private Rygel.DIDLLiteWriter didl_writer;
+    private DIDLLiteParser didl_parser;
+
+    public Cancellable cancellable { get; set; }
+
+    public ItemCreator (ContentDirectory    content_dir,
+                        owned ServiceAction action) {
+        this.content_dir = content_dir;
+        this.cancellable = content_dir.cancellable;
+        this.action = (owned) action;
+        this.didl_writer = new Rygel.DIDLLiteWriter (content_dir.http_server);
+        this.didl_parser = new DIDLLiteParser ();
+    }
+
+    public async void run () {
+        try {
+            this.parse_args ();
+
+            var container = yield this.fetch_container ();
+
+            this.didl_parser.item_available.connect ((didl_item) => {
+                    this.didl_item = didl_item;
+            });
+            this.didl_parser.parse_didl (this.elements);
+
+            this.item = new MediaItem (didl_item.id,
+                                       container,
+                                       didl_item.title,
+                                       didl_item.upnp_class);
+            this.item.mime_type = this.get_generic_mime_type ();
+            this.item.place_holder = true;
+
+            yield container.add_item (this.item, this.cancellable);
+            this.didl_writer.serialize (this.item);
+
+            // Conclude the successful action
+            this.conclude ();
+        } catch (Error err) {
+            this.handle_error (err);
+        }
+    }
+
+    private async void parse_args () throws Error {
+        /* Start by parsing the 'in' arguments */
+        this.action.get ("ContainerID", typeof (string), out this.container_id,
+                         "Elements", typeof (string), out this.elements);
+
+        if (this.container_id == null || this.elements == null) {
+            // Sorry we can't do anything without ContainerID
+            throw new ContentDirectoryError.NO_SUCH_OBJECT ("No such object");
+        }
+    }
+
+    private async MediaContainer fetch_container () throws Error {
+        var media_object = yield this.content_dir.root_container.find_object (
+                                        this.container_id,
+                                        this.cancellable);
+        if (media_object == null || !(media_object is MediaContainer)) {
+            throw new ContentDirectoryError.NO_SUCH_OBJECT ("No such object");
+        }
+
+        return media_object as MediaContainer;
+    }
+
+    private void conclude () {
+        /* Retrieve generated string */
+        string didl = this.didl_writer.get_string ();
+
+        /* Set action return arguments */
+        this.action.set ("Result", typeof (string), didl,
+                         "ObjectID", typeof (string), this.item.id);
+
+        this.action.return ();
+        this.completed ();
+    }
+
+    private void handle_error (Error error) {
+        if (error is ContentDirectoryError) {
+            this.action.return_error (error.code, error.message);
+        } else {
+            this.action.return_error (701, error.message);
+        }
+
+        warning ("Failed to create '%s': %s", this.item.id, error.message);
+
+        this.completed ();
+    }
+
+    private string get_generic_mime_type () {
+        switch (this.item.upnp_class) {
+            case MediaItem.IMAGE_CLASS:
+                return "image";
+            case MediaItem.VIDEO_CLASS:
+                return "video";
+            case MediaItem.AUDIO_CLASS:
+            default:
+                return "audio";
+        }
+    }
+}
+
diff --git a/src/rygel/rygel-media-container.vala b/src/rygel/rygel-media-container.vala
index 8ce6519..0dd0677 100644
--- a/src/rygel/rygel-media-container.vala
+++ b/src/rygel/rygel-media-container.vala
@@ -159,6 +159,37 @@ public abstract class Rygel.MediaContainer : MediaObject {
     }
 
     /**
+     * Add a new item directly under this container.
+     *
+     * @param didl_item The item to add to this container.
+     *
+     * return nothing.
+     *
+     * This implementation is very basic: It only creates the file under the
+     * first writable URI it can find for this container & sets the ID of the
+     * item to that of the URI of the newly created item. If your subclass
+     * doesn't ID the items by their original URIs, you definitely want to
+     * override this method.
+     */
+    public async virtual void add_item (MediaItem    item,
+                                        Cancellable? cancellable)
+                                        throws Error {
+        var dir = yield this.get_writable (cancellable);
+        if (dir == null) {
+           throw new ContentDirectoryError.RESTRICTED_PARENT (
+                                        "Object creation in %s no allowed",
+                                        this.id);
+        }
+
+        var file = dir.get_child_for_display_name (item.title);
+        yield file.create_async (FileCreateFlags.NONE,
+                                 Priority.DEFAULT,
+                                 cancellable);
+        var uri = file.get_uri ();
+        item.id = uri;
+    }
+
+    /**
      * Method to be be called each time this container is updated (metadata
      * changes for this container, items under it gets removed/added or their
      * metadata changes etc).



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