diff options
author | Regis Merlino <regis.merlino@intel.com> | 2013-09-02 15:21:17 +0200 |
---|---|---|
committer | Mark Ryan <mark.d.ryan@intel.com> | 2013-09-06 12:17:40 +0200 |
commit | 4d959b08882574b605b8dce48a1fb4d9bf2f7cee (patch) | |
tree | d3c0388d03926c1f114d6b1815beaa78e41e6187 | |
parent | 8c460ff2e476eeb2b7e35471e97308652a0197f2 (diff) | |
download | dleyna-server-4d959b08882574b605b8dce48a1fb4d9bf2f7cee.tar.gz |
[Device] Deprecate LastChange in favor of Changed signal
Fix issue #109
* Remove LastChange signal
* Add Changed signal
* A Changed signal is emitted along with a ContainerUpdateID
signal when LastChange is not managed by the DLNA server.
Signed-off-by: Regis Merlino <regis.merlino@intel.com>
-rw-r--r-- | doc/server/dbus/API.txt | 82 | ||||
-rw-r--r-- | libdleyna/server/device.c | 154 | ||||
-rw-r--r-- | libdleyna/server/device.h | 1 | ||||
-rw-r--r-- | libdleyna/server/interface.h | 9 | ||||
-rw-r--r-- | libdleyna/server/server.c | 5 | ||||
-rwxr-xr-x | test/dbus/monitor_changed.py (renamed from test/dbus/monitor_last_change.py) | 12 |
6 files changed, 187 insertions, 76 deletions
diff --git a/doc/server/dbus/API.txt b/doc/server/dbus/API.txt index 9664ed9..378daf9 100644 --- a/doc/server/dbus/API.txt +++ b/doc/server/dbus/API.txt @@ -391,73 +391,47 @@ Signals: The com.intel.dLeynaServer.MediaDevice interface also exposes three signals. -LastChange (a(sv) StateEvent) +Changed (aa{sv} ChangedObjects) -The LastChange signal is generated by servers to provide precise information -of changes that have taken place to their content. LastChange is useful for +The Changed signal is generated by servers to provide precise information +of changes that have taken place to their content. Changed is useful for synchronisation controllers. It allows them to dynamically update their local -cache of the server's content. This signal contains an array of zero or more -elements, each of which represents a change to a specific object. -The value of each dictionary entry depends on the key value. +cache of the server's content. This signal contains an array of zero or more +dictionary elements, each of which represents a change to a specific object. +The dictionary is composed of the following keys: |------------------------------------------------------------------------------| -| Key values | R/O | Description | +| Key | Type | m/o | Description | |------------------------------------------------------------------------------| -| "ADD" | O | Indicates that an object has been added. | +| ChangeType | u | m | Contains the Type of the notification: | +| | | | 1 (ADD) an object has been added | +| | | | 2 (MOD) an object has been modified | +| | | | 3 (DEL) an object has been deleted | +| | | | 4 (DONE) an update to a sub-tree has | +| | | | completed | +| | | | 5 (CONTAINER) a container has been updated | |------------------------------------------------------------------------------| -| "MOD" | O | Indicates that an object has been modified. | +| Path | o | m | Contains the Object Path property of the | +| | | | object that was changed. | |------------------------------------------------------------------------------| -| "DEL" | O | Indicates that an object has been deleted | +| UpdateID | u | m | ContainerUpdateID or SystemUpdateID when the | +| | | | object was changed. | |------------------------------------------------------------------------------| -| "DONE" | O | Indicates that an update to a sub-tree has completed. | +| SubTreeUpdate | b | o | True if the object was added as part of a | +| | | | subtree update. | |------------------------------------------------------------------------------| - - -|------------------------------------------------------------------------------| -| Dictionary value for key "ADD": Format (oubos) | -|------------------------------------------------------------------------------| -| o | M | Contains the Object Path property of the object that was added. | -|------------------------------------------------------------------------------| -| u | M | Contains the value of the SystemUpdateID when the object was added. | -|------------------------------------------------------------------------------| -| b | M | True if the object was added as part of a subtree update | -|------------------------------------------------------------------------------| -| o | M | Contains the Object Path property of the parent container to which | -| | | this object was added. | -|------------------------------------------------------------------------------| -| s | M | Contains the value of the TypeEx (converted upnp:class property) | -| | | of the object that was added. | -|------------------------------------------------------------------------------| - -|------------------------------------------------------------------------------| -| Dictionary value for key "MOD": Format (oub) | -|------------------------------------------------------------------------------| -| o | M | Contains the Object Path property of the object that was modified. | +| Parent | o | o | Contains the Object Path property of the | +| | | | parent container of the changed object. | |------------------------------------------------------------------------------| -| u | M | Contains the value of the SystemUpdateID when the object was added. | +| TypeEx | s | o | Contains the value of the TypeEx property | +| | | | (converted upnp:class property) of the | +| | | | object that was changed. | |------------------------------------------------------------------------------| -| b | M | True if the object was modified as part of a subtree update | +| Type | s | o | Contains the value of the Type property | +| | | | (converted upnp:class property) of the object | +| | | | that was changed. | |------------------------------------------------------------------------------| -|------------------------------------------------------------------------------| -| Dictionary value for key "DEL": Format (oub) | -|------------------------------------------------------------------------------| -| o | M | Contains the Object Path property of the object that was deleted. | -|------------------------------------------------------------------------------| -| u | M | Contains the value of the SystemUpdateID when the object was added. | -|------------------------------------------------------------------------------| -| b | M | True if the object was deleted as part of a subtree update | -|------------------------------------------------------------------------------| - -|------------------------------------------------------------------------------| -| Dictionary value for key "DONE": Format (ou) | -|------------------------------------------------------------------------------| -| o | M | Contains the Object Path of the updated sub-tree | -|------------------------------------------------------------------------------| -| u | M | Contains the value of the SystemUpdateID when the object was added. | -|------------------------------------------------------------------------------| - - ContainerUpdateIDs(a(ou) ContainerPathsIDs) Is generated when the contents of one or more folders maintained by the diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c index 4864f43..612a85d 100644 --- a/libdleyna/server/device.c +++ b/libdleyna/server/device.c @@ -98,6 +98,15 @@ struct prv_new_device_ct_t_ { GHashTable *property_map; }; +enum prv_changed_event_type_t_ { + PRV_CHANGED_EVENT_ADD = 1, + PRV_CHANGED_EVENT_MOD, + PRV_CHANGED_EVENT_DEL, + PRV_CHANGED_EVENT_DONE, + PRV_CHANGED_EVENT_CONTAINER +}; +typedef enum prv_changed_event_type_t_ prv_changed_event_type_t; + static void prv_get_child_count(dls_async_task_t *cb_data, dls_device_count_cb_t cb, const gchar *id); static void prv_retrieve_child_count_for_list(dls_async_task_t *cb_data); @@ -265,16 +274,19 @@ static void prv_last_change_decode(GUPnPCDSLastChangeEntry *entry, const char *root_path) { GUPnPCDSLastChangeEvent event; - GVariant *state; const char *object_id; const char *parent_id; const char *mclass; const char *media_class; - char *key[] = {"ADD", "DEL", "MOD", "DONE"}; + const char *media_class_ex; char *parent_path; char *path = NULL; gboolean sub_update; guint32 update_id; + GVariantBuilder *dict; + gboolean mod; + + dict = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); object_id = gupnp_cds_last_change_entry_get_object_id(entry); if (!object_id) @@ -295,21 +307,79 @@ static void prv_last_change_decode(GUPnPCDSLastChangeEntry *entry, if (!mclass) goto on_error; - media_class = dls_props_upnp_class_to_media_spec_ex(mclass); + media_class = dls_props_upnp_class_to_media_spec(mclass); if (!media_class) goto on_error; + media_class_ex = dls_props_upnp_class_to_media_spec_ex(mclass); + parent_path = dls_path_from_id(root_path, parent_id); - state = g_variant_new("(oubos)", path, update_id, sub_update, - parent_path, media_class); + + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_CHANGE_TYPE, + g_variant_new_uint32(PRV_CHANGED_EVENT_ADD)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_PATH, + g_variant_new_string(path)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_UPDATE_ID, + g_variant_new_uint32(update_id)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_SUBTREE_UPDATE, + g_variant_new_boolean(sub_update)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_PARENT, + g_variant_new_string(parent_path)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_TYPE, + g_variant_new_string(media_class)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_TYPE_EX, + g_variant_new_string(media_class_ex)); + g_free(parent_path); break; case GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_REMOVED: case GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_MODIFIED: - state = g_variant_new("(oub)", path, update_id, sub_update); + mod = (event == GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_MODIFIED); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_CHANGE_TYPE, + g_variant_new_uint32(mod ? PRV_CHANGED_EVENT_MOD : + PRV_CHANGED_EVENT_DEL)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_PATH, + g_variant_new_string(path)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_UPDATE_ID, + g_variant_new_uint32(update_id)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_SUBTREE_UPDATE, + g_variant_new_boolean(sub_update)); break; case GUPNP_CDS_LAST_CHANGE_EVENT_ST_DONE: - state = g_variant_new("(ou)", path, update_id); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_CHANGE_TYPE, + g_variant_new_uint32(PRV_CHANGED_EVENT_DONE)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_PATH, + g_variant_new_string(path)); + g_variant_builder_add( + dict, "{sv}", + DLS_INTERFACE_PROP_UPDATE_ID, + g_variant_new_uint32(update_id)); break; case GUPNP_CDS_LAST_CHANGE_EVENT_INVALID: default: @@ -317,10 +387,12 @@ static void prv_last_change_decode(GUPnPCDSLastChangeEntry *entry, break; } - g_variant_builder_add(array, "(sv)", key[event - 1], state); + g_variant_builder_add(array, "@a{sv}", g_variant_builder_end(dict)); + on_error: + g_variant_builder_unref(dict); g_free(path); } @@ -354,7 +426,7 @@ static void prv_last_change_cb(GUPnPServiceProxy *proxy, goto on_error; } - g_variant_builder_init(&array, G_VARIANT_TYPE("a(sv)")); + g_variant_builder_init(&array, G_VARIANT_TYPE("aa{sv}")); next = list; while (next) { prv_last_change_decode(next->data, &array, device->path); @@ -362,12 +434,12 @@ static void prv_last_change_cb(GUPnPServiceProxy *proxy, next = g_list_next(next); } - val = g_variant_new("(@a(sv))", g_variant_builder_end(&array)); + val = g_variant_new("(@aa{sv})", g_variant_builder_end(&array)); (void) dls_server_get_connector()->notify(device->connection, device->path, DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE, - DLS_INTERFACE_ESV_LAST_CHANGE, + DLS_INTERFACE_CHANGED_EVENT, val, NULL); @@ -407,6 +479,44 @@ static void prv_build_container_update_array(const gchar *root_path, g_strfreev(str_array); } +static void prv_build_container_update_changed_array(const gchar *root_path, + const gchar *value, + GVariantBuilder *builder) +{ + gchar **str_array; + int pos = 0; + gchar *path; + guint id; + GVariantBuilder dict; + + str_array = g_strsplit(value, ",", 0); + + while (str_array[pos] && str_array[pos + 1]) { + g_variant_builder_init(&dict, G_VARIANT_TYPE("a{sv}")); + + path = dls_path_from_id(root_path, str_array[pos++]); + id = atoi(str_array[pos++]); + + g_variant_builder_add( + &dict, "{sv}", + DLS_INTERFACE_PROP_CHANGE_TYPE, + g_variant_new_uint32(PRV_CHANGED_EVENT_CONTAINER)); + g_variant_builder_add(&dict, "{sv}", + DLS_INTERFACE_PROP_PATH, + g_variant_new_string(path)); + g_variant_builder_add(&dict, "{sv}", + DLS_INTERFACE_PROP_UPDATE_ID, + g_variant_new_uint32(id)); + + g_variant_builder_add(builder, "@a{sv}", + g_variant_builder_end(&dict)); + + g_free(path); + } + + g_strfreev(str_array); +} + static void prv_container_update_cb(GUPnPServiceProxy *proxy, const char *variable, GValue *value, @@ -429,6 +539,25 @@ static void prv_container_update_cb(GUPnPServiceProxy *proxy, g_variant_new("(@a(ou))", g_variant_builder_end(&array)), NULL); + + if (!device->has_last_change) { + g_variant_builder_init(&array, G_VARIANT_TYPE("aa{sv}")); + + prv_build_container_update_changed_array( + device->path, + g_value_get_string(value), + &array); + + (void) dls_server_get_connector()->notify( + device->connection, + device->path, + DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE, + DLS_INTERFACE_CHANGED_EVENT, + g_variant_new("(@aa{sv})", + g_variant_builder_end( + &array)), + NULL); + } } static void prv_system_update_cb(GUPnPServiceProxy *proxy, @@ -870,6 +999,9 @@ static void prv_get_search_capabilities_cb(GUPnPServiceProxy *proxy, prv_get_capabilities_analyze(priv_t->property_map, result, &priv_t->dev->search_caps); + if (g_hash_table_lookup(priv_t->property_map, "upnp:objectUpdateID")) + priv_t->dev->has_last_change = TRUE; + on_error: if (error) diff --git a/libdleyna/server/device.h b/libdleyna/server/device.h index 530f976..6771464 100644 --- a/libdleyna/server/device.h +++ b/libdleyna/server/device.h @@ -63,6 +63,7 @@ struct dls_device_t_ { GVariant *sort_ext_caps; GVariant *feature_list; gboolean shutting_down; + gboolean has_last_change; guint construct_step; dls_device_icon_t icon; }; diff --git a/libdleyna/server/interface.h b/libdleyna/server/interface.h index 57f6dea..f8cb6c6 100644 --- a/libdleyna/server/interface.h +++ b/libdleyna/server/interface.h @@ -123,6 +123,11 @@ enum dls_interface_type_ { /* Evented State Variable Properties */ #define DLS_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID "SystemUpdateID" +/* Changed event properties */ +#define DLS_INTERFACE_PROP_CHANGE_TYPE "ChangeType" +#define DLS_INTERFACE_PROP_UPDATE_ID "UpdateID" +#define DLS_INTERFACE_PROP_SUBTREE_UPDATE "SubTreeUpdate" + #define DLS_INTERFACE_GET_VERSION "GetVersion" #define DLS_INTERFACE_GET_SERVERS "GetServers" #define DLS_INTERFACE_RESCAN "Rescan" @@ -180,8 +185,8 @@ enum dls_interface_type_ { #define DLS_INTERFACE_INVALIDATED_PROPERTIES "InvalidatedProperties" #define DLS_INTERFACE_ESV_CONTAINER_UPDATE_IDS "ContainerUpdateIDs" #define DLS_INTERFACE_CONTAINER_PATHS_ID "ContainerPathsIDs" -#define DLS_INTERFACE_ESV_LAST_CHANGE "LastChange" -#define DLS_INTERFACE_LAST_CHANGE_STATE_EVENT "StateEvent" +#define DLS_INTERFACE_CHANGED_EVENT "Changed" +#define DLS_INTERFACE_CHANGED_OBJECTS "ChangedObjects" #define DLS_INTERFACE_DELETE "Delete" diff --git a/libdleyna/server/server.c b/libdleyna/server/server.c index 10e01c0..20c5704 100644 --- a/libdleyna/server/server.c +++ b/libdleyna/server/server.c @@ -513,9 +513,8 @@ static const gchar g_server_introspection[] = " <signal name='"DLS_INTERFACE_ESV_CONTAINER_UPDATE_IDS"'>" " <arg type='a(ou)' name='"DLS_INTERFACE_CONTAINER_PATHS_ID"'/>" " </signal>" - " <signal name='"DLS_INTERFACE_ESV_LAST_CHANGE"'>" - " <arg type='a(sv)' name='" - DLS_INTERFACE_LAST_CHANGE_STATE_EVENT"'/>" + " <signal name='"DLS_INTERFACE_CHANGED_EVENT"'>" + " <arg type='aa{sv}' name='"DLS_INTERFACE_CHANGED_OBJECTS"'/>" " </signal>" " <signal name='"DLS_INTERFACE_UPLOAD_UPDATE"'>" " <arg type='u' name='"DLS_INTERFACE_UPLOAD_ID"'/>" diff --git a/test/dbus/monitor_last_change.py b/test/dbus/monitor_changed.py index d831ff2..ff32138 100755 --- a/test/dbus/monitor_last_change.py +++ b/test/dbus/monitor_changed.py @@ -29,19 +29,19 @@ import json def print_properties(props): print json.dumps(props, indent=4, sort_keys=True) -def last_change(state_event, path): - print "LastChange signal from [%s]" % path - print "State Event:" - print_properties(state_event) +def changed(objects, path): + print "Changed signal from [%s]" % path + print "Objects:" + print_properties(objects) if __name__ == '__main__': dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) bus = dbus.SessionBus() - bus.add_signal_receiver(last_change, + bus.add_signal_receiver(changed, bus_name="com.intel.dleyna-server", - signal_name = "LastChange", + signal_name = "Changed", path_keyword="path") mainloop = gobject.MainLoop() |