[vlc-devel] [PATCH] Add addons management API

Francois Cartegnie fcvlcdev at free.fr
Fri Feb 7 23:41:19 CET 2014


Hi,

This is a separate commit regarding the upcoming addons management.

Basically, addons management is done using new modules types:
* addons finder : lists addons from a repository and provide way to retrieve
content that will be passed to storage.
* addons storage : provide addons listing (maintains a catalog) installing and
removing functions.

This allows using alternate repositories and switching to a smarter
lua scripts listing method / storage.

Not on this patch:
Current implementation has an "addons storage" matching our current filesystem
layout and providing a "finder" submodule for querying installed addons.
There's also a repository "addons finder" module for a rewritten addons.v.o, 
which will use a new .vlp package + manifest.
>From early work, an open desktop (current addons.vo) based "finder", 
which is likely not to be commited at all.


François

---
 include/vlc_addons.h | 221 +++++++++++++++++++++++
 include/vlc_common.h |   1 +
 include/vlc_events.h |  13 +-
 src/Makefile.am      |   1 +
 src/libvlccore.sym   |   9 +
 src/misc/addons.c    | 485 +++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 729 insertions(+), 1 deletion(-)
 create mode 100644 include/vlc_addons.h
 create mode 100644 src/misc/addons.c

diff --git a/include/vlc_addons.h b/include/vlc_addons.h
new file mode 100644
index 0000000..8d16b35
--- /dev/null
+++ b/include/vlc_addons.h
@@ -0,0 +1,221 @@
+/*****************************************************************************
+ * vlc_addons.h : addons handling and describing
+ *****************************************************************************
+ * Copyright (C) 2013 VideoLAN and authors
+ *
+ * This program 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.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *****************************************************************************/
+
+#ifndef VLC_ADDONS_H
+#define VLC_ADDONS_H 1
+
+#include <vlc_arrays.h>
+#include <vlc_events.h>
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+typedef enum addon_type_t
+{
+    ADDON_UNKNOWN = 0,
+    ADDON_EXTENSION,
+    ADDON_PLAYLIST_PARSER,
+    ADDON_SERVICE_DISCOVERY,
+    ADDON_SKIN2,
+    ADDON_PLUGIN,
+    ADDON_OTHER
+} addon_type_t;
+
+typedef enum addon_state_t
+{
+    ADDON_NOTINSTALLED = 0,
+    ADDON_INSTALLING,
+    ADDON_INSTALLED,
+    ADDON_UNINSTALLING
+} addon_state_t;
+
+typedef enum addon_flags_t
+{
+    ADDON_BROKEN     = 1, /* Have install inconsistency */
+    ADDON_MANAGEABLE = 1 << 1, /* Have manifest, can install or uninstall files */
+    ADDON_UPDATABLE  = 1 << 2,
+} addon_flags_t;
+
+#define ADDON_UUID_SIZE 16
+#define ADDON_UUID_PSZ_SIZE (ADDON_UUID_SIZE * 2 + 4)
+typedef uint8_t addon_uuid_t[ADDON_UUID_SIZE];
+
+typedef struct addon_file_t
+{
+    addon_type_t e_filetype;
+    char *psz_download_uri;
+    char *psz_filename;
+} addon_file_t;
+
+struct addon_entry_t
+{
+    vlc_mutex_t lock;
+
+    addon_type_t e_type;
+    addon_state_t e_state;
+    addon_flags_t e_flags;
+
+    /* data describing addon */
+    addon_uuid_t uuid;
+    char *psz_name;
+    char *psz_summary;
+    char *psz_description;
+    char *psz_source_uri; /* webpage, ... */
+    char *psz_image_uri;
+    char *psz_image_data; /* base64, png */
+    char *psz_version;
+
+    /* stats */
+    long int i_downloads;
+    long int i_score;
+
+    /* Lister */
+    char *psz_source_module;
+
+    /* files list */
+    char *psz_archive_uri; /* Archive */
+    DECL_ARRAY(addon_file_t *) files;
+
+    /* custom data storage (if needed by module/source) */
+    void * p_custom;
+};
+typedef struct addon_entry_t addon_entry_t;
+
+typedef struct addons_finder_t addons_finder_t;
+typedef struct addons_finder_sys_t addons_finder_sys_t;
+struct addons_finder_t
+{
+    VLC_COMMON_MEMBERS
+
+    int ( * pf_find )( addons_finder_t * );
+    int ( * pf_retrieve )( addons_finder_t *, addon_entry_t * );
+    DECL_ARRAY( addon_entry_t * ) entries;
+    char *psz_uri;
+
+    addons_finder_sys_t *p_sys;
+};
+
+typedef struct addons_storage_t addons_storage_t;
+typedef struct addons_storage_sys_t addons_storage_sys_t;
+struct addons_storage_t
+{
+    VLC_COMMON_MEMBERS
+
+    int ( * pf_install )( addons_storage_t *, addon_entry_t * );
+    int ( * pf_remove )( addons_storage_t *, addon_entry_t * );
+    int ( * pf_catalog ) ( addons_storage_t *, addon_entry_t **, int );
+
+    addons_storage_sys_t *p_sys;
+};
+
+typedef struct addons_manager_private_t addons_manager_private_t;
+/**
+ *
+ */
+/*FIXME*/
+typedef struct vlc_event_manager_t vlc_event_manager_t;
+
+struct addons_manager_t
+{
+    vlc_event_manager_t * p_event_manager;
+
+    addons_manager_private_t *p_priv;
+};
+typedef struct addons_manager_t addons_manager_t;
+
+/**
+ *  addon entry lifecycle
+ */
+VLC_API addon_entry_t *addon_entry_New( void );
+VLC_API addon_entry_t *addon_entry_Hold(addon_entry_t *);
+VLC_API void addon_entry_Release(addon_entry_t *);
+
+/**
+ * addons manager lifecycle
+ */
+VLC_API addons_manager_t *addons_manager_New( vlc_object_t * );
+VLC_API void addons_manager_Delete( addons_manager_t * );
+
+/**
+ * Charge currently installed, usable and manageable addons
+ * (default "addons storage" module)
+ */
+VLC_API int addons_manager_LoadCatalog( addons_manager_t * );
+
+/**
+ * Gather addons info from repository (default "addons finder" module)
+ * If psz_uri is not NULL, only gather info from the pointed package.
+ */
+VLC_API void addons_manager_Gather( addons_manager_t *, const char *psz_uri );
+
+/**
+ * Install or Remove the addon identified by its uuid
+ */
+VLC_API int addons_manager_Install( addons_manager_t *p_manager, const addon_uuid_t uuid );
+VLC_API int addons_manager_Remove( addons_manager_t *p_manager, const addon_uuid_t uuid );
+
+/**
+ * String uuid to binary uuid helpers
+ */
+static inline bool addons_uuid_read( const char *psz_uuid, addon_uuid_t *p_uuid )
+{
+    if ( !psz_uuid ) return false;
+    if ( strlen( psz_uuid ) < ADDON_UUID_PSZ_SIZE ) return false;
+
+    int i = 0, j = 0;
+    while ( i<ADDON_UUID_PSZ_SIZE )
+    {
+        if ( *( psz_uuid + i ) == '-' )
+            i++;
+        int v;
+        sscanf( psz_uuid + i, "%02"PRIx8, &v );
+        (*p_uuid)[j++] = v & 0xFF;
+        i+=2;
+    }
+
+    return true;
+}
+
+static inline char * addons_uuid_to_psz( const addon_uuid_t * p_uuid )
+{
+    char *psz = (char*) calloc( ADDON_UUID_PSZ_SIZE + 1 , sizeof(char) );
+    if ( psz )
+    {
+        int i=0;
+        char *p = psz;
+        while ( i < ADDON_UUID_SIZE )
+        {
+            if ( i == 4 || i== 7 || i== 9 || i== 11 )
+                *p++ = '-';
+            int v = 0xFF & (*p_uuid)[i];
+            sprintf( p, "%02"PRIx8, v );
+            p += 2;
+            i++;
+        }
+    }
+    return psz;
+}
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
diff --git a/include/vlc_common.h b/include/vlc_common.h
index 62b1260..7e84f16 100644
--- a/include/vlc_common.h
+++ b/include/vlc_common.h
@@ -335,6 +335,7 @@ typedef struct vlm_message_t vlm_message_t;
 /* misc */
 typedef struct vlc_meta_t    vlc_meta_t;
 typedef struct input_stats_t input_stats_t;
+typedef struct addon_entry_t addon_entry_t;
 
 /* Update */
 typedef struct update_t update_t;
diff --git a/include/vlc_events.h b/include/vlc_events.h
index 9e37f7f..9a6166a 100644
--- a/include/vlc_events.h
+++ b/include/vlc_events.h
@@ -27,6 +27,7 @@
 
 #include <vlc_arrays.h>
 #include <vlc_meta.h>
+#include <vlc_addons.h>
 
 /**
  * \file
@@ -129,7 +130,12 @@ typedef enum vlc_event_type_t {
     vlc_ServicesDiscoveryItemRemoved,
     vlc_ServicesDiscoveryItemRemoveAll,
     vlc_ServicesDiscoveryStarted,
-    vlc_ServicesDiscoveryEnded
+    vlc_ServicesDiscoveryEnded,
+
+    /* Addons Manager events */
+    vlc_AddonFound,
+    vlc_AddonsDiscoveryEnded,
+    vlc_AddonChanged
 } vlc_event_type_t;
 
 /* Event definition */
@@ -202,6 +208,11 @@ typedef struct vlc_event_t
             void * unused;
         } services_discovery_ended;
 
+        /* Addons */
+        struct vlc_addon_generic_event
+        {
+            addon_entry_t * p_entry;
+        } addon_generic_event;
     } u;
 } vlc_event_t;
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 474da25..ab4b744 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -475,6 +475,7 @@ SOURCES_libvlc_common = \
 	misc/xml.c \
 	extras/libc.c \
 	extras/tdestroy.c \
+	misc/addons.c \
 	misc/filter.c \
 	misc/filter_chain.c \
 	misc/http_auth.c \
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 3fc39d7..1ed906a 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -641,3 +641,12 @@ vlc_keycode2str
 vlc_str2keycode
 fingerprinter_Create
 fingerprinter_Destroy
+addons_manager_New
+addons_manager_Delete
+addons_manager_Gather
+addons_manager_LoadCatalog
+addons_manager_Install
+addons_manager_Remove
+addon_entry_New
+addon_entry_Hold
+addon_entry_Release
diff --git a/src/misc/addons.c b/src/misc/addons.c
new file mode 100644
index 0000000..8e8659c
--- /dev/null
+++ b/src/misc/addons.c
@@ -0,0 +1,485 @@
+/*****************************************************************************
+ * addons.c: VLC addons manager
+ *****************************************************************************
+ * Copyright (C) 2014 VLC authors and VideoLAN
+ *
+ * This program 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.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_atomic.h>
+#include <vlc_modules.h>
+#include <vlc_arrays.h>
+#include <vlc_events.h>
+#include "libvlc.h"
+
+#include <vlc_addons.h>
+
+/*****************************************************************************
+ * Structures/definitions
+ *****************************************************************************/
+
+typedef struct addon_entry_owner
+{
+    addon_entry_t entry;
+    atomic_uint refs;
+} addon_entry_owner_t;
+
+struct addons_manager_private_t
+{
+    vlc_object_t *p_parent;
+
+    struct
+    {
+        vlc_thread_t *p_thread;
+        bool b_live;
+        vlc_mutex_t lock;
+        char *psz_uri_hint; /* uri hint for non repo based install */
+        DECL_ARRAY(addon_entry_t*) entries;
+    } finder;
+
+    struct
+    {
+        vlc_thread_t *p_thread;
+        bool b_live;
+        vlc_mutex_t lock;
+        DECL_ARRAY(addon_entry_t*) entries;
+    } installer;
+};
+
+static void *FinderThread( void * );
+static void LoadLocalStorage( addons_manager_t *p_manager );
+
+/*****************************************************************************
+ * Public functions
+ *****************************************************************************/
+
+addon_entry_t * addon_entry_New()
+{
+    addon_entry_owner_t *owner = calloc( 1, sizeof(addon_entry_owner_t) );
+    if( unlikely(owner == NULL) )
+        return NULL;
+
+    atomic_init( &owner->refs, 1 );
+
+    addon_entry_t *p_entry = &owner->entry;
+    vlc_mutex_init( &p_entry->lock );
+    ARRAY_INIT( p_entry->files );
+    return p_entry;
+}
+
+addon_entry_t * addon_entry_Hold( addon_entry_t * p_entry )
+{
+    addon_entry_owner_t *owner = (addon_entry_owner_t *) p_entry;
+
+    atomic_fetch_add( &owner->refs, 1 );
+    return p_entry;
+}
+
+void addon_entry_Release( addon_entry_t * p_entry )
+{
+    addon_entry_owner_t *owner = (addon_entry_owner_t *) p_entry;
+
+    if( atomic_fetch_sub(&owner->refs, 1) != 1 )
+        return;
+
+    free( p_entry->psz_name );
+    free( p_entry->psz_summary );
+    free( p_entry->psz_description );
+    free( p_entry->psz_archive_uri );
+    free( p_entry->psz_image_uri );
+    free( p_entry->psz_image_data );
+    free( p_entry->psz_source_module );
+    free( p_entry->psz_version );
+    free( p_entry->p_custom );
+
+    addon_file_t *p_file;
+    FOREACH_ARRAY( p_file, p_entry->files )
+    free( p_file->psz_filename );
+    free( p_file->psz_download_uri );
+    FOREACH_END()
+    ARRAY_RESET( p_entry->files );
+
+    vlc_mutex_destroy( &p_entry->lock );
+    free( owner );
+}
+
+addons_manager_t *addons_manager_New( vlc_object_t *p_this )
+{
+    addons_manager_t *p_manager = malloc( sizeof(addons_manager_t) );
+    if ( !p_manager ) return NULL;
+
+    p_manager->p_priv = malloc( sizeof(addons_manager_private_t) );
+    if ( !p_manager->p_priv )
+    {
+        free( p_manager );
+        return NULL;
+    }
+
+    p_manager->p_event_manager = malloc( sizeof(vlc_event_manager_t) );
+    if ( !p_manager->p_event_manager )
+    {
+        free( p_manager->p_priv );
+        free( p_manager );
+        return NULL;
+    }
+
+    p_manager->p_priv->p_parent = p_this;
+
+#define INIT_QUEUE( name ) \
+    p_manager->p_priv->name.b_live = false;\
+    p_manager->p_priv->name.p_thread = NULL;\
+    vlc_mutex_init( &p_manager->p_priv->name.lock );\
+    ARRAY_INIT( p_manager->p_priv->name.entries );
+
+    INIT_QUEUE( finder )
+    INIT_QUEUE( installer )
+    p_manager->p_priv->finder.psz_uri_hint = NULL;
+
+    vlc_event_manager_t *em = p_manager->p_event_manager;
+    vlc_event_manager_init( em, p_manager );
+    vlc_event_manager_register_event_type(em, vlc_AddonFound);
+    vlc_event_manager_register_event_type(em, vlc_AddonsDiscoveryEnded);
+    vlc_event_manager_register_event_type(em, vlc_AddonChanged);
+
+    return p_manager;
+}
+
+void addons_manager_Delete( addons_manager_t *p_manager )
+{
+    if ( p_manager->p_priv->finder.b_live )
+        vlc_cancel( *p_manager->p_priv->finder.p_thread );
+    if ( p_manager->p_priv->installer.b_live )
+        vlc_cancel( *p_manager->p_priv->installer.p_thread );
+
+    vlc_event_manager_fini( p_manager->p_event_manager );
+
+#define FREE_QUEUE( name ) \
+    vlc_mutex_lock( &p_manager->p_priv->name.lock );\
+    FOREACH_ARRAY( addon_entry_t *p_entry, p_manager->p_priv->name.entries )\
+        addon_entry_Release( p_entry );\
+    FOREACH_END();\
+    ARRAY_RESET( p_manager->p_priv->name.entries );\
+    vlc_mutex_unlock( &p_manager->p_priv->name.lock );\
+    vlc_mutex_destroy( &p_manager->p_priv->name.lock );
+
+    FREE_QUEUE( finder )
+    FREE_QUEUE( installer )
+    free( p_manager->p_priv->finder.psz_uri_hint );
+
+    free( p_manager->p_priv );
+    free( p_manager->p_event_manager );
+    free( p_manager );
+}
+
+void addons_manager_Gather( addons_manager_t *p_manager, const char *psz_uri )
+{
+    vlc_mutex_lock( &p_manager->p_priv->finder.lock );
+    if ( psz_uri )
+    {
+        p_manager->p_priv->finder.psz_uri_hint = strdup( psz_uri );
+    }
+    if( !p_manager->p_priv->finder.b_live )
+    {
+        if( vlc_clone_detach( p_manager->p_priv->finder.p_thread, FinderThread, p_manager,
+                              VLC_THREAD_PRIORITY_LOW ) )
+            msg_Err( p_manager->p_priv->p_parent,
+                     "cannot spawn entries provider thread" );
+        else
+            p_manager->p_priv->finder.b_live = true;
+    }
+    vlc_mutex_unlock( &p_manager->p_priv->finder.lock );
+}
+
+/*****************************************************************************
+ * Private functions
+ *****************************************************************************/
+
+static addon_entry_t * getHeldEntryByUUID( addons_manager_t *p_manager,
+                                           const addon_uuid_t uuid )
+{
+    addon_entry_t *p_return = NULL;
+    vlc_mutex_lock( &p_manager->p_priv->finder.lock );
+    FOREACH_ARRAY( addon_entry_t *p_entry, p_manager->p_priv->finder.entries )
+    if ( !memcmp( p_entry->uuid, uuid, sizeof( addon_uuid_t ) ) )
+    {
+        p_return = p_entry;
+        addon_entry_Hold( p_return );
+        break;
+    }
+    FOREACH_END()
+    vlc_mutex_unlock( &p_manager->p_priv->finder.lock );
+    return p_return;
+}
+
+static void MergeSources( addons_manager_t *p_manager,
+                          addon_entry_t **pp_addons, int i_count )
+{
+    addon_entry_t *p_entry, *p_manager_entry;
+    addon_uuid_t zerouuid;
+    memset( zerouuid, 0, sizeof( addon_uuid_t ) );
+    for ( int i=0; i < i_count; i++ )
+    {
+        p_entry = pp_addons[i];
+        if ( memcmp( p_entry->uuid, zerouuid, sizeof( addon_uuid_t ) ) )
+            p_manager_entry = getHeldEntryByUUID( p_manager, p_entry->uuid );
+        else
+            p_manager_entry = NULL;
+        if ( !p_manager_entry )
+        {
+            ARRAY_APPEND( p_manager->p_priv->finder.entries, p_entry );
+            vlc_event_t event;
+            event.type = vlc_AddonFound;
+            event.u.addon_generic_event.p_entry = p_entry;
+            vlc_event_send( p_manager->p_event_manager, &event );
+        }
+        else
+        {
+            addon_entry_Release( p_manager_entry );
+        }
+    }
+}
+
+static void LoadLocalStorage( addons_manager_t *p_manager )
+{
+    addons_finder_t *p_finder =
+        vlc_custom_create( p_manager->p_priv->p_parent, sizeof( *p_finder ), "entries finder" );
+
+    module_t *p_module = module_need( p_finder, "addons finder",
+                                      "addons.store.list", true );
+    if( p_module )
+    {
+        ARRAY_INIT( p_finder->entries );
+        p_finder->pf_find( p_finder );
+        module_unneed( p_finder, p_module );
+
+        MergeSources( p_manager, p_finder->entries.p_elems, p_finder->entries.i_size );
+
+        ARRAY_RESET( p_finder->entries );
+    }
+    vlc_object_release( p_finder );
+}
+
+static void *FinderThread( void *p_data )
+{
+    addons_manager_t *p_manager = p_data;
+    int i_cancel;
+    p_manager->p_priv->finder.b_live = true;
+
+    addons_finder_t *p_finder =
+            vlc_custom_create( p_manager->p_priv->p_parent, sizeof( *p_finder ), "entries finder" );
+
+    if( p_finder != NULL )
+    {
+        module_t *p_module;
+        ARRAY_INIT( p_finder->entries );
+        p_finder->psz_uri = p_manager->p_priv->finder.psz_uri_hint;
+        p_manager->p_priv->finder.psz_uri_hint = NULL;
+
+        p_module = module_need( p_finder, "addons finder", NULL, false );
+        if( p_module )
+        {
+            i_cancel = vlc_savecancel();
+            p_finder->pf_find( p_finder );
+            vlc_restorecancel( i_cancel );
+            module_unneed( p_finder, p_module );
+
+            MergeSources( p_manager, p_finder->entries.p_elems, p_finder->entries.i_size );
+        }
+
+        ARRAY_RESET( p_finder->entries );
+        free( p_finder->psz_uri );
+        vlc_object_release( p_finder );
+    }
+
+    p_manager->p_priv->finder.b_live = false;
+
+    vlc_event_t event;
+    event.type = vlc_AddonsDiscoveryEnded;
+    event.u.addon_generic_event.p_entry = NULL;
+    vlc_event_send( p_manager->p_event_manager, &event );
+
+    return NULL;
+}
+
+static int addons_manager_WriteCatalog( addons_manager_t *p_manager )
+{
+    int i_return = VLC_EGENERIC;
+
+    addons_storage_t *p_storage =
+        vlc_custom_create( p_manager->p_priv->p_parent, sizeof( *p_storage ), "entries storage" );
+
+    module_t *p_module = module_need( p_storage, "addons storage",
+                                      "addons.store.install", true );
+    if( p_module )
+    {
+        vlc_mutex_lock( &p_manager->p_priv->finder.lock );
+        i_return = p_storage->pf_catalog( p_storage, p_manager->p_priv->finder.entries.p_elems,
+                                          p_manager->p_priv->finder.entries.i_size );
+        vlc_mutex_unlock( &p_manager->p_priv->finder.lock );
+        module_unneed( p_storage, p_module );
+    }
+    vlc_object_release( p_storage );
+
+    return i_return;
+}
+
+int addons_manager_LoadCatalog( addons_manager_t *p_manager )
+{
+    LoadLocalStorage( p_manager );
+    return VLC_SUCCESS;
+}
+
+static int installOrRemoveAddon( addons_manager_t *p_manager, addon_entry_t *p_entry, bool b_install )
+{
+    int i_return = VLC_EGENERIC;
+
+    addons_storage_t *p_storage =
+        vlc_custom_create( p_manager->p_priv->p_parent, sizeof( *p_storage ), "entries storage" );
+
+    module_t *p_module = module_need( p_storage, "addons storage",
+                                      "addons.store.install", true );
+    if( p_module )
+    {
+        if ( b_install )
+            i_return = p_storage->pf_install( p_storage, p_entry );
+        else
+            i_return = p_storage->pf_remove( p_storage, p_entry );
+        module_unneed( p_storage, p_module );
+        msg_Dbg( p_manager->p_priv->p_parent, "InstallAddon returns %d", i_return );
+    }
+    vlc_object_release( p_storage );
+
+    return i_return;
+}
+
+static void *InstallerThread( void *p_data )
+{
+    addons_manager_t *p_manager = p_data;
+    int i_ret, i_cancel;
+    vlc_event_t event;
+    event.type = vlc_AddonChanged;
+
+    for( ;; )
+    {
+        vlc_testcancel();
+        vlc_mutex_lock( &p_manager->p_priv->installer.lock );
+        if ( !p_manager->p_priv->installer.entries.i_size )
+        {
+            /* No queued addons */
+            vlc_mutex_unlock( &p_manager->p_priv->installer.lock );
+            p_manager->p_priv->installer.b_live = false;
+            break;
+        }
+
+        addon_entry_t *p_entry = p_manager->p_priv->installer.entries.p_elems[0];
+        ARRAY_REMOVE( p_manager->p_priv->installer.entries, 0 );
+        addon_entry_Hold( p_entry );
+        vlc_mutex_unlock( &p_manager->p_priv->installer.lock );
+
+        vlc_mutex_lock( &p_entry->lock );
+        /* DO WORK */
+        if ( p_entry->e_state == ADDON_INSTALLED )
+        {
+            p_entry->e_state = ADDON_UNINSTALLING;
+            vlc_mutex_unlock( &p_entry->lock );
+
+            /* notify */
+            event.u.addon_generic_event.p_entry = p_entry;
+            vlc_event_send( p_manager->p_event_manager, &event );
+
+            i_cancel = vlc_savecancel();
+            i_ret = installOrRemoveAddon( p_manager, p_entry, false );
+            vlc_restorecancel( i_cancel );
+
+            vlc_mutex_lock( &p_entry->lock );
+            p_entry->e_state = ( i_ret == VLC_SUCCESS ) ? ADDON_NOTINSTALLED
+                                                        : ADDON_INSTALLED;
+            vlc_mutex_unlock( &p_entry->lock );
+        }
+        else if ( p_entry->e_state == ADDON_NOTINSTALLED )
+        {
+            p_entry->e_state = ADDON_INSTALLING;
+            vlc_mutex_unlock( &p_entry->lock );
+
+            /* notify */
+            event.u.addon_generic_event.p_entry = p_entry;
+            vlc_event_send( p_manager->p_event_manager, &event );
+
+            i_cancel = vlc_savecancel();
+            i_ret = installOrRemoveAddon( p_manager, p_entry, true );
+            vlc_restorecancel( i_cancel );
+
+            vlc_mutex_lock( &p_entry->lock );
+            p_entry->e_state = ( i_ret == VLC_SUCCESS ) ? ADDON_INSTALLED
+                                                        : ADDON_NOTINSTALLED;
+            vlc_mutex_unlock( &p_entry->lock );
+        }
+        else
+            vlc_mutex_unlock( &p_entry->lock );
+        /* !DO WORK */
+
+        event.u.addon_generic_event.p_entry = p_entry;
+        vlc_event_send( p_manager->p_event_manager, &event );
+
+        addon_entry_Release( p_entry );
+    }
+
+    i_cancel = vlc_savecancel();
+    addons_manager_WriteCatalog( p_manager );
+    vlc_restorecancel( i_cancel );
+
+    return NULL;
+}
+
+static int InstallEntry( addons_manager_t *p_manager, addon_entry_t *p_entry )
+{
+    if ( p_entry->e_type == ADDON_UNKNOWN ||
+         p_entry->e_type == ADDON_PLUGIN ||
+         p_entry->e_type == ADDON_OTHER )
+        return VLC_EBADVAR;
+
+    vlc_mutex_lock( &p_manager->p_priv->installer.lock );
+    ARRAY_APPEND( p_manager->p_priv->installer.entries, p_entry );
+    if( !p_manager->p_priv->installer.b_live )
+    {
+        if( vlc_clone_detach( p_manager->p_priv->installer.p_thread, InstallerThread, p_manager,
+                              VLC_THREAD_PRIORITY_LOW ) )
+            msg_Err( p_manager->p_priv->p_parent,
+                     "cannot spawn addons installer thread" );
+        else
+            p_manager->p_priv->installer.b_live = true;
+    }
+    vlc_mutex_unlock( &p_manager->p_priv->installer.lock );
+    return VLC_SUCCESS;
+}
+
+int addons_manager_Install( addons_manager_t *p_manager, const addon_uuid_t uuid )
+{
+    addon_entry_t *p_install_entry = getHeldEntryByUUID( p_manager, uuid );
+    if ( ! p_install_entry ) return VLC_EGENERIC;
+    int i_ret = InstallEntry( p_manager, p_install_entry );
+    addon_entry_Release( p_install_entry );
+    return i_ret;
+}
+
+int addons_manager_Remove( addons_manager_t *p_manager, const addon_uuid_t uuid )
+{
+    return addons_manager_Install( p_manager, uuid );
+}
-- 
1.8.5.3




More information about the vlc-devel mailing list