[grilo-plugins] lua-factory: Create a proxy for grl and grl.lua



commit 7c9315e7bb7bf7c572663e002c321d53d76d25cf
Author: Victor Toso <me victortoso com>
Date:   Fri Mar 4 16:30:50 2016 +0100

    lua-factory: Create a proxy for grl and grl.lua
    
    By creating a proxy table with custom metatable in order to have more
    control into changes make in grl and grl.lua by Lua sources.
    
    At the moment, the proxy redirects read access (__index metamethod)
    and write access (__newindex metamethod) to the original table but later
    on we can remove write access from Lua sources to our library.
    
    Internally we are should be using the __call metamethod in order to
    retrieve the original table.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=763046

 src/lua-factory/grl-lua-common.h             |    1 +
 src/lua-factory/grl-lua-library-operations.c |  100 ++++++++++++++++++++++++++
 src/lua-factory/grl-lua-library.c            |    5 ++
 3 files changed, 106 insertions(+), 0 deletions(-)
---
diff --git a/src/lua-factory/grl-lua-common.h b/src/lua-factory/grl-lua-common.h
index fa5c12e..405e41e 100644
--- a/src/lua-factory/grl-lua-common.h
+++ b/src/lua-factory/grl-lua-common.h
@@ -87,6 +87,7 @@ void grl_lua_library_push_grl_options (lua_State *L, guint operation_id, GrlOper
 void grl_lua_library_push_grl_callback (lua_State *L, OperationSpec *os);
 
 /* grl-lua-library-operations */
+void grl_lua_operations_set_proxy_table (lua_State *L, gint index);
 gboolean grl_lua_operations_pcall (lua_State *L, gint nargs, OperationSpec *os, GError **err);
 
 #endif /* _GRL_LUA_LIBRARY_COMMON_H_ */
diff --git a/src/lua-factory/grl-lua-library-operations.c b/src/lua-factory/grl-lua-library-operations.c
index 031b624..0074990 100644
--- a/src/lua-factory/grl-lua-library-operations.c
+++ b/src/lua-factory/grl-lua-library-operations.c
@@ -24,10 +24,110 @@
 #include "grl-lua-common.h"
 
 /* =========================================================================
+ * Internal functions ======================================================
+ * ========================================================================= */
+
+/* ============== Proxy related ============================================ */
+
+/*
+ * Get the original table from proxy which is still able to rw operations
+ *
+ * @index: position to the proxy table in the stack
+ * return: the original table in top of the stack
+ *
+ */
+static void
+proxy_table_get_rw (lua_State *L,
+                    guint index)
+{
+  gint *table_ref;
+
+  /* using table as function */
+  lua_pushvalue (L, index);
+  table_ref = lua_newuserdata (L, sizeof (gint));
+  *table_ref = 0;
+  if (lua_pcall (L, 1, 0, 0)) {
+    GRL_WARNING ("Failed to get rw table due: %s",
+                 lua_tolstring (L, -1, NULL));
+    lua_pop (L, 1);
+  }
+  lua_rawgeti (L, LUA_REGISTRYINDEX, *table_ref);
+  luaL_unref (L, LUA_REGISTRYINDEX, *table_ref);
+}
+
+/*
+ * proxy handler for __call metamethod; This metamethod is called when using
+ * the table as a function (e.g {}()). The proxy uses this metamethod in order
+ * to retrieve a reference to original table which is still capabable of
+ * read-write operations.
+ *
+ * @userdata: Expects pointer to integer which will hold the reference to the
+ * requested table.
+ */
+static int
+proxy_metatable_handle_call (lua_State *L)
+{
+  luaL_argcheck (L, lua_istable (L, 1), 1, "First argument is always itself");
+  luaL_argcheck (L, lua_isuserdata (L, 2), 2,
+                 "expecting userdata as reference holder (gint *)");
+  gint *table_ref = lua_touserdata (L, 2);
+  lua_pushvalue (L, lua_upvalueindex (1));
+  *table_ref = luaL_ref (L, LUA_REGISTRYINDEX);
+  return 0;
+}
+
+/* =========================================================================
  * Exported functions ======================================================
  * ========================================================================= */
 
 /*
+ * Create a read-only proxy table which will only be allowed to access the
+ * original table.
+ *
+ * @index: position to the table in the stack
+ * return: switch the table at @index with a read-only proxy
+ */
+void
+grl_lua_operations_set_proxy_table (lua_State *L,
+                                    gint index)
+{
+  g_assert_true (lua_istable (L, index));
+
+  /* Proxy table that will be switched with the one at index */
+  lua_newtable (L);
+
+  /* Metatable */
+  lua_createtable (L, 0, 3);
+
+  /* __index: triggered when acessing a value of given table */
+  lua_pushstring (L, "__index");
+  lua_pushvalue (L, index - 3);
+  lua_settable (L, -3);
+
+  /* __len: triggered when counting the length of given table */
+  lua_pushstring (L, "__len");
+  lua_pushvalue (L, index - 3);
+  lua_settable (L, -3);
+
+  /* __newindex: triggered when inserting new key/value to given table */
+  lua_pushstring (L, "__newindex");
+  lua_pushvalue (L, index - 3);
+  lua_settable (L, -3);
+
+  /* __call: triggered when using the table as a function */
+  lua_pushstring (L, "__call");
+  lua_pushvalue (L, index - 3);
+  lua_pushcclosure (L, proxy_metatable_handle_call, 1);
+  lua_settable (L, -3);
+
+  /* Set metatable to our proxy */
+  lua_setmetatable (L, -2);
+
+  /* Replace original table with our proxy */
+  lua_replace (L, index - 1);
+}
+
+/*
  * This is a wrapper to do execute the lua_pcall and all internals that might
  * be necessary to Lua-Library before calling the Lua function. The stack
  * requirements are the same of lua_pcall, function and arguments in expected
diff --git a/src/lua-factory/grl-lua-library.c b/src/lua-factory/grl-lua-library.c
index 9b66da8..7b4fe9a 100644
--- a/src/lua-factory/grl-lua-library.c
+++ b/src/lua-factory/grl-lua-library.c
@@ -1438,8 +1438,13 @@ luaopen_grilo (lua_State *L)
   }
   lua_pop (L, 1);
 
+  grl_lua_operations_set_proxy_table (L, -1);
+
   /* Those modules are called in 'lua' table, inside 'grl' */
   lua_settable (L, -3);
+
+  grl_lua_operations_set_proxy_table (L, -1);
+
   return 1;
 }
 


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