[grilo-plugins] lua-factory: Grilo operations to Lua sources



commit f5f335ca0f593e855d057f772c358c3c1e82cdc9
Author: Victor Toso <me victortoso com>
Date:   Thu Oct 31 22:18:48 2013 -0200

    lua-factory: Grilo operations to Lua sources
    
    This is the glue code between Grilo and the Lua sources. The Lua stack
    (lua_State) is used to pass the variables to the lua code.
    
    Besides the Grilo operations, the lua source can use the grl_source_init
    function to check if it can be successfully loaded or not.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=711243

 src/lua-factory/grl-lua-common.h  |    3 +
 src/lua-factory/grl-lua-factory.c |  272 ++++++++++++++++++++++++++++++++++++-
 src/lua-factory/grl-lua-library.c |   42 ++++++
 src/lua-factory/grl-lua-library.h |    4 +
 4 files changed, 319 insertions(+), 2 deletions(-)
---
diff --git a/src/lua-factory/grl-lua-common.h b/src/lua-factory/grl-lua-common.h
index f5f472c..47345d2 100644
--- a/src/lua-factory/grl-lua-common.h
+++ b/src/lua-factory/grl-lua-common.h
@@ -66,4 +66,7 @@ typedef struct _OperationSpec {
   guint error_code;
 } OperationSpec;
 
+void grl_lua_library_save_operation_data (lua_State *L, OperationSpec *os);
+OperationSpec *grl_lua_library_load_operation_data (lua_State *L);
+
 #endif /* _GRL_LUA_LIBRARY_COMMON_H_ */
diff --git a/src/lua-factory/grl-lua-factory.c b/src/lua-factory/grl-lua-factory.c
index 4baad1b..be392d1 100644
--- a/src/lua-factory/grl-lua-factory.c
+++ b/src/lua-factory/grl-lua-factory.c
@@ -102,6 +102,23 @@ static void grl_lua_factory_source_finalize (GObject *object);
 
 static const GList *grl_lua_factory_source_supported_keys (GrlSource *source);
 
+static void grl_lua_factory_source_search (GrlSource *source,
+                                           GrlSourceSearchSpec *ss);
+
+static void grl_lua_factory_source_browse (GrlSource *source,
+                                           GrlSourceBrowseSpec *bs);
+
+static void grl_lua_factory_source_query (GrlSource *source,
+                                          GrlSourceQuerySpec *qs);
+
+static void grl_lua_factory_source_resolve (GrlSource *source,
+                                            GrlSourceResolveSpec *rs);
+
+static gboolean grl_lua_factory_source_may_resolve (GrlSource *source,
+                                                    GrlMedia *media,
+                                                    GrlKeyID key_id,
+                                                    GList **missing_keys);
+
 static GrlSupportedOps
 grl_lua_factory_source_supported_operations (GrlSource *source);
 
@@ -112,6 +129,8 @@ static GrlConfig *merge_all_configs (const gchar *source_id,
 static gboolean all_mandatory_options_has_value (GHashTable *source_configs,
                                                  GrlConfig *merged_configs);
 
+static gboolean lua_plugin_source_init (GrlLuaFactorySource *lua_source);
+
 /* ================== Lua-Factory Plugin  ================================== */
 
 static gboolean
@@ -245,6 +264,12 @@ grl_lua_factory_source_new (gchar *lua_plugin_path,
   g_free (source_id);
   source->priv->config_keys = config_keys;
   source->priv->l_st = L;
+
+  if (lua_plugin_source_init (source) == FALSE) {
+    g_object_unref (G_OBJECT (source));
+    source = NULL;
+  }
+
   return source;
 
 bail:
@@ -275,6 +300,11 @@ grl_lua_factory_source_class_init (GrlLuaFactorySourceClass *klass)
 
   source_class->supported_keys = grl_lua_factory_source_supported_keys;
   source_class->supported_operations = grl_lua_factory_source_supported_operations;
+  source_class->search = grl_lua_factory_source_search;
+  source_class->browse = grl_lua_factory_source_browse;
+  source_class->query = grl_lua_factory_source_query;
+  source_class->resolve = grl_lua_factory_source_resolve;
+  source_class->may_resolve = grl_lua_factory_source_may_resolve;
 
   g_type_class_add_private (klass, sizeof (GrlLuaFactorySourcePrivate));
 }
@@ -306,6 +336,62 @@ grl_lua_factory_source_finalize (GObject *object)
   G_OBJECT_CLASS (grl_lua_factory_source_parent_class)->finalize (object);
 }
 
+/* lua_plugin_source_init
+ *
+ * Calls a init function with current config_keys to check if the source is
+ * ready to operate.
+ */
+static gboolean
+lua_plugin_source_init (GrlLuaFactorySource *lua_source)
+{
+  lua_State *L = lua_source->priv->l_st;
+  GList *it_keys = NULL;
+  GList *list_keys = NULL;
+  const gchar *key = NULL;
+  const gchar *value = NULL;
+  gboolean ret = FALSE;
+
+  /* Source does not have grl_source_init() */
+  if (lua_source->priv->fn[LUA_SOURCE_INIT] == FALSE) {
+    GRL_DEBUG ("grl_source_init not implemented");
+    return TRUE;
+  }
+
+  lua_getglobal (L, LUA_SOURCE_OPERATION[LUA_SOURCE_INIT]);
+
+  if (lua_source->priv->config_keys != NULL) {
+    /* configs */
+    lua_newtable (L);
+
+    list_keys = g_hash_table_get_keys (lua_source->priv->config_keys);
+    for (it_keys = list_keys; it_keys; it_keys = g_list_next (it_keys)) {
+      key = it_keys->data;
+      value = grl_config_get_string (lua_source->priv->configs, key);
+
+      if (value) {
+        lua_pushstring (L, key);
+        lua_pushstring (L, value);
+        lua_settable (L, -3);
+      }
+    }
+    g_list_free (list_keys);
+
+  } else {
+    lua_pushnil (L);
+  }
+
+  if (lua_pcall (L, 1, 1, 0)) {
+    GRL_WARNING ("calling grl_source_init function failed: %s",
+                 lua_tolstring (L, -1, NULL));
+    lua_pop (L, 1);
+    return FALSE;
+  }
+
+  ret = (lua_isboolean (L, -1) && lua_toboolean (L, -1)) ? TRUE : FALSE;
+  lua_pop (L, 1);
+  return ret;
+}
+
 /* ======================= Utilities ======================================= */
 
 static GList *
@@ -813,6 +899,188 @@ grl_lua_factory_source_supported_keys (GrlSource *source)
 static GrlSupportedOps
 grl_lua_factory_source_supported_operations (GrlSource *source)
 {
-  /* No operation is implemented right now */
-  return 0;
+  GrlSupportedOps caps = 0;
+  GrlLuaFactorySource *lua_source = GRL_LUA_FACTORY_SOURCE (source);
+
+  caps |= (lua_source->priv->fn[LUA_SEARCH]) ? GRL_OP_SEARCH : caps;
+  caps |= (lua_source->priv->fn[LUA_BROWSE]) ? GRL_OP_BROWSE : caps;
+  caps |= (lua_source->priv->fn[LUA_QUERY]) ? GRL_OP_QUERY : caps;
+  caps |= (lua_source->priv->fn[LUA_RESOLVE]) ? GRL_OP_RESOLVE : caps;
+
+  return caps;
+}
+
+static void
+grl_lua_factory_source_search (GrlSource *source,
+                               GrlSourceSearchSpec *ss)
+{
+  GrlLuaFactorySource *lua_source = GRL_LUA_FACTORY_SOURCE (source);
+  lua_State *L = lua_source->priv->l_st;
+  OperationSpec *os = NULL;
+  const gchar *text = NULL;
+
+  GRL_DEBUG ("grl_lua_factory_source_search");
+
+  os = g_slice_new0 (OperationSpec);
+  os->source = ss->source;
+  os->operation_id = ss->operation_id;
+  os->cb.result = ss->callback;
+  os->user_data = ss->user_data;
+  os->error_code = GRL_CORE_ERROR_SEARCH_FAILED;
+  os->keys = g_list_copy (ss->keys);
+  os->options = grl_operation_options_copy (ss->options);
+  os->op_type = LUA_SEARCH;
+
+  grl_lua_library_save_operation_data (L, os);
+  lua_getglobal (L, LUA_SOURCE_OPERATION[LUA_SEARCH]);
+
+  text = (ss->text == NULL) ? "" : ss->text;
+  lua_pushstring (L, text);
+  if (lua_pcall (L, 1, 0, 0)) {
+    GRL_WARNING ("%s '%s'", "calling search function fail:",
+                 lua_tolstring (L, -1, NULL));
+    lua_pop (L, 1);
+  }
+}
+
+static void
+grl_lua_factory_source_browse (GrlSource *source,
+                               GrlSourceBrowseSpec *bs)
+{
+  GrlLuaFactorySource *lua_source = GRL_LUA_FACTORY_SOURCE (source);
+  lua_State *L = lua_source->priv->l_st;
+  OperationSpec *os = NULL;
+  const gchar *media_id = NULL;
+
+  GRL_DEBUG ("grl_lua_factory_source_browse");
+
+  os = g_slice_new0 (OperationSpec);
+  os->source = bs->source;
+  os->operation_id = bs->operation_id;
+  os->media = bs->container;
+  os->cb.result = bs->callback;
+  os->user_data = bs->user_data;
+  os->error_code = GRL_CORE_ERROR_BROWSE_FAILED;
+  os->keys = g_list_copy (bs->keys);
+  os->options = grl_operation_options_copy (bs->options);
+  os->op_type = LUA_BROWSE;
+
+  grl_lua_library_save_operation_data (L, os);
+  lua_getglobal (L, LUA_SOURCE_OPERATION[LUA_BROWSE]);
+
+  media_id = grl_media_get_id (os->media);
+  lua_pushstring (L, media_id);
+  if (lua_pcall (L, 1, 0, 0)) {
+    GRL_WARNING ("%s '%s'", "calling browse function fail:",
+                 lua_tolstring (L, -1, NULL));
+    lua_pop (L, 1);
+  }
+}
+
+static void
+grl_lua_factory_source_query (GrlSource *source,
+                              GrlSourceQuerySpec *qs)
+{
+  GrlLuaFactorySource *lua_source = GRL_LUA_FACTORY_SOURCE (source);
+  lua_State *L = lua_source->priv->l_st;
+  OperationSpec *os = NULL;
+  const gchar *query = NULL;
+
+  GRL_DEBUG ("grl_lua_factory_source_query");
+
+  os = g_slice_new0 (OperationSpec);
+  os->source = qs->source;
+  os->operation_id = qs->operation_id;
+  os->cb.result = qs->callback;
+  os->user_data = qs->user_data;
+  os->error_code = GRL_CORE_ERROR_QUERY_FAILED;
+  os->keys = g_list_copy (qs->keys);
+  os->options = grl_operation_options_copy (qs->options);
+  os->op_type = LUA_QUERY;
+
+  grl_lua_library_save_operation_data (L, os);
+  lua_getglobal (L, LUA_SOURCE_OPERATION[LUA_QUERY]);
+
+  query = (qs->query == NULL) ? "" : qs->query;
+  lua_pushstring (L, query);
+  if (lua_pcall (L, 1, 0, 0)) {
+    GRL_WARNING ("%s '%s'", "calling query function fail:",
+                 lua_tolstring (L, -1, NULL));
+    lua_pop (L, 1);
+  }
+}
+
+static void
+grl_lua_factory_source_resolve (GrlSource *source,
+                                GrlSourceResolveSpec *rs)
+{
+  GrlLuaFactorySource *lua_source = GRL_LUA_FACTORY_SOURCE (source);
+  lua_State *L = lua_source->priv->l_st;
+  OperationSpec *os = NULL;
+
+  GRL_DEBUG ("grl_lua_factory_source_resolve");
+
+  os = g_slice_new0 (OperationSpec);
+  os->source = rs->source;
+  os->operation_id = rs->operation_id;
+  os->cb.resolve = rs->callback;
+  os->media = rs->media;
+  os->user_data = rs->user_data;
+  os->error_code = GRL_CORE_ERROR_RESOLVE_FAILED;
+  os->keys = g_list_copy (rs->keys);
+  os->options = grl_operation_options_copy (rs->options);
+  os->op_type = LUA_RESOLVE;
+
+  grl_lua_library_save_operation_data (L, os);
+  lua_getglobal (L, LUA_SOURCE_OPERATION[LUA_RESOLVE]);
+
+  if (lua_pcall (L, 0, 0, 0)) {
+    GRL_WARNING ("%s '%s'", "calling resolve function fail:",
+                 lua_tolstring (L, -1, NULL));
+    lua_pop (L, 1);
+  }
+}
+
+static gboolean
+grl_lua_factory_source_may_resolve (GrlSource *source,
+                                    GrlMedia *media,
+                                    GrlKeyID key_id,
+                                    GList **missing_keys)
+{
+  GrlLuaFactorySource *lua_source = GRL_LUA_FACTORY_SOURCE (source);
+  GList *it_keys = NULL;
+  GList *missing = NULL;
+  GrlMediaType res_type = GRL_MEDIA_TYPE_NONE;
+  GrlKeyID it_key_id = GRL_METADATA_KEY_INVALID;
+
+  GRL_DEBUG ("grl_lua_factory_source_may_resolve");
+
+  if (lua_source->priv->resolve_keys == NULL
+      || !g_list_find (lua_source->priv->supported_keys,
+                       GRLKEYID_TO_POINTER (key_id))) {
+    return FALSE;
+  }
+
+  /* Verify if the source resolve type and media type match */
+  res_type = lua_source->priv->resolve_type;
+  if ((GRL_IS_MEDIA_AUDIO (media) && !(res_type & GRL_MEDIA_TYPE_AUDIO))
+      || (GRL_IS_MEDIA_IMAGE (media) && !(res_type & GRL_MEDIA_TYPE_IMAGE))
+      || (GRL_IS_MEDIA_VIDEO (media) && !(res_type & GRL_MEDIA_TYPE_VIDEO))) {
+    return FALSE;
+  }
+
+  /* Verify if all keys needed are present */
+  for (it_keys = lua_source->priv->resolve_keys;
+       it_keys;
+       it_keys = g_list_next (it_keys)) {
+
+    it_key_id = GRLPOINTER_TO_KEYID (it_keys->data);
+    if (it_key_id != GRL_METADATA_KEY_INVALID
+        && grl_data_has_key (GRL_DATA (media), it_key_id) == FALSE) {
+      missing = g_list_prepend (missing, GRLKEYID_TO_POINTER (it_key_id));
+    }
+  }
+
+  *missing_keys = missing;
+  return (missing == NULL) ? TRUE : FALSE;
 }
diff --git a/src/lua-factory/grl-lua-library.c b/src/lua-factory/grl-lua-library.c
index 7fde7ec..4b6c3ed 100644
--- a/src/lua-factory/grl-lua-library.c
+++ b/src/lua-factory/grl-lua-library.c
@@ -24,6 +24,7 @@
 #include <string.h>
 
 #include "grl-lua-common.h"
+#include "grl-lua-library.h"
 
 #define GRL_LOG_DOMAIN_DEFAULT lua_library_log_domain
 GRL_LOG_DOMAIN_STATIC (lua_library_log_domain);
@@ -44,3 +45,44 @@ luaopen_grilo (lua_State *L)
 
   return 1;
 }
+
+/* ======= Lua-Library and Lua-Factory utilities ============= */
+
+/**
+ * grl_lua_library_save_operation_data
+ *
+ * @L : LuaState where the data will be stored.
+ * @os: The Operation Data to store.
+ * @return: Nothing.
+ *
+ * Stores the OperationSpec from Lua-Factory in the global environment of
+ * lua_State.
+ **/
+void
+grl_lua_library_save_operation_data (lua_State *L, OperationSpec *os)
+{
+  lua_getglobal (L, LUA_ENV_TABLE);
+  lua_pushstring (L, GRILO_LUA_OPERATION_INDEX);
+  lua_pushlightuserdata (L, os);
+  lua_settable (L, -3);
+  lua_pop (L, 1);
+}
+
+/**
+ * grl_lua_library_load_operation_data
+ *
+ * @L : LuaState where the data is stored.
+ * @return: The Operation Data.
+ **/
+OperationSpec *
+grl_lua_library_load_operation_data (lua_State *L)
+{
+  OperationSpec *os = NULL;
+
+  lua_getglobal (L, LUA_ENV_TABLE);
+  lua_pushstring (L, GRILO_LUA_OPERATION_INDEX);
+  lua_gettable (L, -2);
+  os = (lua_islightuserdata(L, -1)) ? lua_touserdata(L, -1) : NULL;
+  lua_pop(L, 1);
+  return os;
+}
diff --git a/src/lua-factory/grl-lua-library.h b/src/lua-factory/grl-lua-library.h
index 9fa33df..13e3ab1 100644
--- a/src/lua-factory/grl-lua-library.h
+++ b/src/lua-factory/grl-lua-library.h
@@ -31,6 +31,10 @@
 
 #define GRILO_LUA_LIBRARY_NAME "grl"
 
+#define LUA_ENV_TABLE "_G"
+
+#define GRILO_LUA_OPERATION_INDEX "grl-lua-operation-spec"
+
 gint luaopen_grilo (lua_State *L);
 
 #endif /* _GRL_LUA_LIBRARY_H_ */


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