[vlc-devel] [PATCH 07/10][RFC][WIP] cloudstorage: sd: add services discovery module

Diogo Silva dbtdsilva at gmail.com
Thu Aug 17 03:08:15 CEST 2017


---
 modules/access/Makefile.am                         |   2 +
 modules/access/cloudstorage.cpp                    |  15 +
 modules/access/cloudstorage/services_discovery.cpp | 315 +++++++++++++++++++++
 modules/access/cloudstorage/services_discovery.h   |  55 ++++
 po/POTFILES.in                                     |   2 +
 5 files changed, 389 insertions(+)
 create mode 100644 modules/access/cloudstorage/services_discovery.cpp
 create mode 100644 modules/access/cloudstorage/services_discovery.h

diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
index 75e4afa885..d1737d5e56 100644
--- a/modules/access/Makefile.am
+++ b/modules/access/Makefile.am
@@ -316,6 +316,8 @@ endif
 libcloudstorage_plugin_la_SOURCES = \
 	access/cloudstorage.cpp \
 	access/cloudstorage/access.h access/cloudstorage/access.cpp \
+	access/cloudstorage/services_discovery.h \
+	access/cloudstorage/services_discovery.cpp \
 	access/cloudstorage/provider_callback.h
 libcloudstorage_plugin_la_CXXFLAGS = $(CXXFLAGS_cloudstorage) $(AM_CXXFLAGS)
 libcloudstorage_plugin_la_LIBADD = $(LIBS_cloudstorage)
diff --git a/modules/access/cloudstorage.cpp b/modules/access/cloudstorage.cpp
index 152f2067c7..9b5fe2ad1f 100644
--- a/modules/access/cloudstorage.cpp
+++ b/modules/access/cloudstorage.cpp
@@ -28,6 +28,10 @@
 #include <vlc_plugin.h>

 #include "cloudstorage/access.h"
+#include "cloudstorage/services_discovery.h"
+
+static int vlc_sd_probe_Open( vlc_object_t * );
+VLC_SD_PROBE_HELPER( "cloudstorage", N_("Cloud Storage"), SD_CAT_INTERNET )

 vlc_module_begin()
     set_shortname(N_("cloudstorage"))
@@ -38,4 +42,15 @@ vlc_module_begin()
     set_subcategory(SUBCAT_INPUT_ACCESS)
     // callbacks are defined under cloudstorage/access.h
     set_callbacks(Open, Close)
+
+    add_submodule()
+        set_description( N_("Cloud storage services (such as Drive, Dropbox)"
+        " services discovery module using libcloudstorage") )
+        set_category( CAT_PLAYLIST )
+        set_subcategory( SUBCAT_PLAYLIST_SD )
+        set_capability( "services_discovery", 0 )
+        // callbacks are defined under cloudstorage/services_discovery.h
+        set_callbacks( SDOpen, SDClose )
+
+        VLC_SD_PROBE_SUBMODULE
 vlc_module_end()
diff --git a/modules/access/cloudstorage/services_discovery.cpp b/modules/access/cloudstorage/services_discovery.cpp
new file mode 100644
index 0000000000..1f8c9bf969
--- /dev/null
+++ b/modules/access/cloudstorage/services_discovery.cpp
@@ -0,0 +1,315 @@
+/*****************************************************************************
+ * services_discovery.cpp: cloud storage services discovery module
+ *****************************************************************************
+ * Copyright (C) 2017 VideoLabs and VideoLAN
+ *
+ * Authors: William Ung <williamung at msn.com>
+ *          Diogo Silva <dbtdsilva at gmail.com>
+ *
+ * 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 /* HAVE_CONFIG_H */
+
+#include <vlc_keystore.h>
+#include <vlc_url.h>
+
+#include <ICloudStorage.h>
+#include <sstream>
+#include <algorithm>
+
+#include "services_discovery.h"
+
+static int GetProvidersList( services_discovery_t * );
+static int RepresentUsers( services_discovery_t * );
+static input_item_t * GetNewUserInput( services_discovery_t *, const char *,
+                     const char * );
+static int InsertNewUserInput( services_discovery_t *, input_item_t * );
+static char * GenerateUserIdentifier( services_discovery_t *, const char * );
+static int CallbackNewAuthentication( vlc_object_t *, char const *,
+                     vlc_value_t, vlc_value_t, void * );
+static int CallbackRequestedFromUI( vlc_object_t *, char const *,
+                     vlc_value_t, vlc_value_t, void * );
+
+using cloudstorage::ICloudStorage;
+
+int SDOpen( vlc_object_t *p_this )
+{
+    services_discovery_t *p_sd = (services_discovery_t *) p_this;
+    services_discovery_sys_t *p_sys;
+
+    p_sd->p_sys = p_sys = new services_discovery_sys_t();
+    if ( p_sys == nullptr)
+        return VLC_ENOMEM;
+    p_sd->description = _( "Cloud Storage" );
+
+    if ( GetProvidersList( p_sd ) != VLC_SUCCESS )
+        goto error;
+    if ( RepresentUsers( p_sd ) != VLC_SUCCESS )
+        goto error;
+
+    // Associate callbacks to detect when a user is authenticated with success!
+    if ( var_Create( p_sd->obj.libvlc, "cloudstorage-new-auth",
+            VLC_VAR_STRING) != VLC_SUCCESS )
+        goto error;
+    var_AddCallback( p_sd->obj.libvlc, "cloudstorage-new-auth",
+            CallbackNewAuthentication, p_sd );
+
+    if ( var_Create( p_sd->obj.parent, "cloudstorage-request",
+            VLC_VAR_STRING ) != VLC_SUCCESS )
+        goto error;
+    var_AddCallback( p_sd->obj.parent, "cloudstorage-request",
+            CallbackRequestedFromUI, p_sd );
+    return VLC_SUCCESS;
+
+error:
+    SDClose( p_this );
+    return VLC_EGENERIC;
+}
+
+void SDClose( vlc_object_t *p_this )
+{
+    services_discovery_t *p_sd = (services_discovery_t *) p_this;
+    services_discovery_sys_t *p_sys = (services_discovery_sys_t *) p_sd->p_sys;
+
+    for ( auto& p_item_root : p_sys->providers_items )
+        delete p_item_root.second;
+    if (p_sys->auth_item != nullptr)
+        delete p_sys->auth_item;
+
+    var_DelCallback( p_sd->obj.libvlc, "cloudstorage-new-auth",
+            CallbackNewAuthentication, p_sd );
+    var_DelCallback( p_sd->obj.parent, "cloudstorage-request",
+            CallbackRequestedFromUI, p_sd);
+    delete p_sys;
+}
+
+static int GetProvidersList( services_discovery_t * p_sd )
+{
+    services_discovery_sys_t *p_sys = (services_discovery_sys_t *) p_sd->p_sys;
+    for ( const auto& provider_ptr : ICloudStorage::create()->providers() )
+        p_sys->providers_list.push_back( provider_ptr->name() );
+
+    if ( p_sys->providers_list.empty() )
+    {
+        msg_Err( p_sd, "Failed to load providers from libcloudstorage" );
+        return VLC_EGENERIC;
+    }
+    return VLC_SUCCESS;
+}
+
+static int RepresentUsers( services_discovery_t * p_sd )
+{
+    services_discovery_sys_t *p_sys = (services_discovery_sys_t *) p_sd->p_sys;
+
+    p_sys->auth_progress = false;
+    for ( auto& provider : p_sys->providers_list )
+    {
+        std::string mrl_base = "cloudstorage://" + provider;
+        vlc_url_t dummy_url;
+        vlc_UrlParse( &dummy_url, mrl_base.c_str() );
+        vlc_credential cred;
+        vlc_credential_init( &cred, &dummy_url );
+        vlc_credential_get( &cred, p_sd, NULL, NULL, NULL, NULL );
+        for (unsigned int i = 0; i < cred.i_entries_count; i++)
+        {
+            input_item_t * item = GetNewUserInput( p_sd,
+                    cred.p_entries[i].ppsz_values[KEY_USER],
+                    cred.p_entries[i].ppsz_values[KEY_SERVER] );
+            InsertNewUserInput( p_sd, item );
+        }
+        vlc_credential_clean( &cred );
+        vlc_UrlClean( &dummy_url );
+    }
+    return VLC_SUCCESS;
+}
+
+static input_item_t * GetNewUserInput( services_discovery_t * p_sd,
+        const char * user, const char * provider )
+{
+    services_discovery_sys_t *p_sys = (services_discovery_sys_t *) p_sd->p_sys;
+
+    if ( std::find( p_sys->providers_list.begin(),
+                    p_sys->providers_list.end(),
+                    provider ) ==
+            p_sys->providers_list.end() )
+        return nullptr;
+
+    char *user_with_provider;
+    if ( asprintf( &user_with_provider, "%s@%s", user, provider ) < 0 )
+        return nullptr;
+    char *uri;
+    if ( asprintf(&uri, "cloudstorage://%s/", user_with_provider ) < 0 )
+    {
+        free( user_with_provider );
+        return nullptr;
+    }
+
+    input_item_t *p_item_user = input_item_NewDirectory( uri,
+                user_with_provider, ITEM_NET );
+    free( user_with_provider );
+    free( uri );
+
+    return p_item_user;
+}
+
+static int InsertNewUserInput( services_discovery_t * p_sd, input_item_t* item )
+{
+    if ( item == NULL )
+        return VLC_EGENERIC;
+
+    services_discovery_sys_t *p_sys = (services_discovery_sys_t *) p_sd->p_sys;
+    services_discovery_AddItem( p_sd, item );
+
+    provider_item_t * prov = new provider_item_t( item, nullptr );
+    p_sys->providers_items.insert( std::make_pair( item->psz_name, prov ) );
+
+    return VLC_SUCCESS;
+}
+
+static char * GenerateUserIdentifier( services_discovery_t * p_sd,
+        const char * provider)
+{
+    // Find the last generated identifier for the Association MRL
+    // MRL in the item will contain a predefined user
+    std::string mrl_base = "cloudstorage://";
+    mrl_base += provider;
+    vlc_url_t dummy_url;
+    vlc_UrlParse( &dummy_url, mrl_base.c_str() );
+    vlc_credential cred;
+    vlc_credential_init( &cred, &dummy_url );
+    vlc_credential_get( &cred, p_sd, NULL, NULL, NULL, NULL );
+
+    unsigned int id = 1;
+    bool name_exists;
+    char * gen_user;
+    do
+    {
+        if ( asprintf( &gen_user, "user%d", id ) < 0 )
+            return nullptr;
+        name_exists = false;
+        for ( unsigned int i = 0; i < cred.i_entries_count; i++ )
+        {
+            if ( strcmp( cred.p_entries[i].ppsz_values[KEY_USER],
+                         gen_user ) == 0)
+            {
+                id += 1;
+                name_exists = true;
+                free( gen_user );
+                break;
+            }
+        }
+    } while ( name_exists );
+
+    vlc_credential_clean( &cred );
+    vlc_UrlClean( &dummy_url );
+
+    return gen_user;
+}
+
+static int CallbackNewAuthentication( vlc_object_t *p_this, char const *psz_var,
+                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    (void) oldval; (void) p_this; (void) psz_var; (void) newval;
+
+    services_discovery_t *p_sd = (services_discovery_t *) p_data;
+    services_discovery_sys_t *p_sys = (services_discovery_sys_t *) p_sd->p_sys;
+
+    services_discovery_AddItem( p_sd, p_sys->auth_item->item  );
+    p_sys->providers_items.insert( std::make_pair(
+        p_sys->auth_item->item->psz_name, p_sys->auth_item ) );
+
+    p_sys->auth_item = nullptr;
+    p_sys->auth_progress = false;
+    return VLC_SUCCESS;
+}
+
+static int CallbackRequestedFromUI( vlc_object_t *p_this, char const *psz_var,
+                     vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    (void) oldval; (void) p_this; (void) psz_var;
+    services_discovery_t *p_sd = (services_discovery_t *) p_data;
+    services_discovery_sys_t *p_sys = (services_discovery_sys_t *) p_sd->p_sys;
+
+    std::string raw( newval.psz_string );
+
+    std::string operation = raw.substr( 0, raw.find_first_of(":") );
+    std::string request = raw.substr( raw.find_first_of(":") + 1 );
+    if ( operation == "ADD" )
+    {
+        // Only one add operation is allowed at the same time
+        if ( p_sys->auth_progress )
+        {
+            msg_Err( p_sd, "There is already a running authentication in "
+                     "progress that must be finished before!");
+            return VLC_EGENERIC;
+        }
+
+        // Generate the user and spawn the authorization
+        char* gen_user = GenerateUserIdentifier( p_sd, request.c_str() );
+        input_item_t *item = GetNewUserInput( p_sd, gen_user,
+                request.c_str() );
+        input_thread_t *thread = input_CreateAndStart( p_sd, item, NULL);
+        p_sys->auth_item = new provider_item_t(item, thread);
+        p_sys->auth_progress = true;
+    }
+    else if ( operation == "RM" )
+    {
+        std::string mrl_base = "cloudstorage://" + request;
+        vlc_url_t dummy_url;
+        vlc_UrlParse( &dummy_url, mrl_base.c_str() );
+        vlc_credential cred;
+        vlc_credential_init( &cred, &dummy_url );
+        vlc_credential_get( &cred, p_sd, NULL, NULL, NULL, NULL );
+        if ( vlc_credential_delete( &cred, p_sd ) )
+        {
+            auto it = p_sys->providers_items.find( request );
+            services_discovery_RemoveItem( p_sd, it->second->item );
+            delete it->second;
+            p_sys->providers_items.erase( it );
+        }
+        vlc_credential_clean( &cred );
+        vlc_UrlClean( &dummy_url );
+    }
+    else if ( operation == "ACT")
+    {
+        auto it = p_sys->providers_items.find( request );
+        if ( it->second->thread == nullptr )
+        {
+            it->second->thread = input_CreateAndStart(
+                    p_sd, it->second->item, NULL);
+        }
+    }
+
+    return VLC_SUCCESS;
+}
+
+provider_item_t::provider_item_t(input_item_t *item, input_thread_t *thread) :
+    item(item), thread(thread)
+{
+}
+
+provider_item_t::~provider_item_t()
+{
+    if ( item != nullptr )
+        input_item_Release( item );
+    if ( thread != nullptr )
+    {
+        input_Stop( thread );
+        input_Close( thread );
+    }
+}
\ No newline at end of file
diff --git a/modules/access/cloudstorage/services_discovery.h b/modules/access/cloudstorage/services_discovery.h
new file mode 100644
index 0000000000..f6a679b0a6
--- /dev/null
+++ b/modules/access/cloudstorage/services_discovery.h
@@ -0,0 +1,55 @@
+/*****************************************************************************
+ * services_discovery.h: cloud storage services discovery module
+ *****************************************************************************
+ * Copyright (C) 2017 VideoLabs and VideoLAN
+ *
+ * Authors: William Ung <williamung at msn.com>
+ *          Diogo Silva <dbtdsilva at gmail.com>
+ *
+ * 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_CLOUDSTORAGE_SERVICES_DISCOVERY_H
+#define VLC_CLOUDSTORAGE_SERVICES_DISCOVERY_H
+
+#include <vector>
+#include <map>
+#include <string>
+
+#include <vlc_common.h>
+#include <vlc_keystore.h>
+#include <vlc_services_discovery.h>
+
+int SDOpen( vlc_object_t * );
+void SDClose( vlc_object_t * );
+
+struct provider_item_t
+{
+    provider_item_t(input_item_t *, input_thread_t *);
+    ~provider_item_t();
+
+    input_item_t * item;
+    input_thread_t * thread;
+};
+
+struct services_discovery_sys_t
+{
+    bool auth_progress;
+    std::map< std::string, provider_item_t * > providers_items;
+    std::vector< std::string > providers_list;
+    provider_item_t * auth_item;
+};
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d47d046f41..8bfa9577f0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -181,6 +181,8 @@ modules/access/cloudstorage.cpp
 modules/access/cloudstorage/access.cpp
 modules/access/cloudstorage/access.h
 modules/access/cloudstorage/provider_callback.h
+modules/access/cloudstorage/services_discovery.cpp
+modules/access/cloudstorage/services_discovery.h
 modules/access/concat.c
 modules/access/dc1394.c
 modules/access/dcp/dcp.cpp
--
2.14.1


More information about the vlc-devel mailing list