From 0b80f1b5ce816696b3f9b2bdaf9f5d8fe9ac0469 Mon Sep 17 00:00:00 2001
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Thu, 18 Jan 2018 16:23:10 +0100
Subject: [PATCH] gluon-core: reimplement gluon.site module in C

By basing the Lua gluon.site module on gluonutil_load_site_config(), the
config load implementation needs to changed only in a single place for
multi-domain support.
---
 package/gluon-core/Makefile                   |   7 +-
 .../luasrc/usr/lib/lua/gluon/site.lua         |  44 -------
 package/gluon-core/src/CMakeLists.txt         |  12 ++
 package/gluon-core/src/site.c                 | 113 ++++++++++++++++++
 4 files changed, 131 insertions(+), 45 deletions(-)
 delete mode 100644 package/gluon-core/luasrc/usr/lib/lua/gluon/site.lua
 create mode 100644 package/gluon-core/src/CMakeLists.txt
 create mode 100644 package/gluon-core/src/site.c

diff --git a/package/gluon-core/Makefile b/package/gluon-core/Makefile
index 3b2b7ca94..4ba21db0c 100644
--- a/package/gluon-core/Makefile
+++ b/package/gluon-core/Makefile
@@ -9,6 +9,7 @@ PKG_VERSION:=$(if $(DUMP),x,$(GLUON_VERSION))
 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 
 include ../gluon.mk
+include $(INCLUDE_DIR)/cmake.mk
 
 
 define Package/gluon-core
@@ -24,16 +25,20 @@ define Package/gluon-core/description
 	Gluon community wifi mesh firmware framework: core
 endef
 
-define Build/Configure
+define Build/Prepare
+	mkdir -p $(PKG_BUILD_DIR)
+	$(CP) ./src/* $(PKG_BUILD_DIR)/
 endef
 
 define Build/Compile
+	$(call Build/Compile/Default,all)
 	$(call GluonSrcDiet,./luasrc,$(PKG_BUILD_DIR)/luadest/)
 endef
 
 define Package/gluon-core/install
 	$(CP) ./files/* $(1)/
 	$(CP) $(PKG_BUILD_DIR)/luadest/* $(1)/
+	$(CP) $(PKG_INSTALL_DIR)/* $(1)/
 
 	$(INSTALL_DIR) $(1)/lib/gluon
 	echo '$(GLUON_VERSION)' > $(1)/lib/gluon/gluon-version
diff --git a/package/gluon-core/luasrc/usr/lib/lua/gluon/site.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/site.lua
deleted file mode 100644
index 65d38cd86..000000000
--- a/package/gluon-core/luasrc/usr/lib/lua/gluon/site.lua
+++ /dev/null
@@ -1,44 +0,0 @@
-local json = require 'jsonc'
-local site = assert(json.load('/lib/gluon/site.json'))
-
-
-local wrap
-
-
-local function index(t, k)
-	local v = getmetatable(t).value
-	if v == nil then return wrap(nil) end
-	return wrap(v[k])
-end
-
-local function newindex()
-	error('attempted to modify site config')
-end
-
-local function call(t, def)
-	local v = getmetatable(t).value
-	if v == nil then return def end
-	return v
-end
-
-local function _wrap(v, t)
-	return setmetatable(t or {}, {
-		__index = index,
-		__newindex = newindex,
-		__call = call,
-		value = v,
-	})
-end
-
-local none = _wrap(nil)
-
-
-function wrap(v, t)
-	if v == nil then return none end
-	return _wrap(v, t)
-end
-
-
-module 'gluon.site'
-
-return wrap(site, _M)
diff --git a/package/gluon-core/src/CMakeLists.txt b/package/gluon-core/src/CMakeLists.txt
new file mode 100644
index 000000000..aee77452e
--- /dev/null
+++ b/package/gluon-core/src/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(gluon-core C)
+
+add_library(site MODULE site.c)
+set_property(TARGET site PROPERTY PREFIX "")
+set_property(TARGET site PROPERTY COMPILE_FLAGS "-Wall -std=c99")
+target_link_libraries(site gluonutil lua lua-jsonc)
+
+install(TARGETS site
+  LIBRARY DESTINATION lib/lua/gluon
+)
diff --git a/package/gluon-core/src/site.c b/package/gluon-core/src/site.c
new file mode 100644
index 000000000..971d44cf8
--- /dev/null
+++ b/package/gluon-core/src/site.c
@@ -0,0 +1,113 @@
+#include "libgluonutil.h"
+#include "lua-jsonc.h"
+
+#include <limits.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+
+#define UDATA "gluon.site"
+
+
+static struct json_object * gluon_site_udata(lua_State *L, int narg) {
+        return *(struct json_object **)luaL_checkudata(L, narg, UDATA);
+}
+
+static void gluon_site_push_none(lua_State *L) {
+        lua_pushlightuserdata(L, gluon_site_push_none);
+        lua_rawget(L, LUA_REGISTRYINDEX);
+}
+
+static void gluon_site_do_wrap(lua_State *L, struct json_object *obj) {
+        struct json_object **objp = lua_newuserdata(L, sizeof(struct json_object *));
+        *objp = json_object_get(obj);
+        luaL_getmetatable(L, UDATA);
+        lua_setmetatable(L, -2);
+}
+
+static void gluon_site_wrap(lua_State *L, struct json_object *obj) {
+        if (obj)
+                gluon_site_do_wrap(L, obj);
+        else
+                gluon_site_push_none(L);
+}
+
+
+static int gluon_site_index(lua_State *L) {
+        struct json_object *obj = gluon_site_udata(L, 1);
+        const char *key;
+        lua_Number lua_index;
+        size_t index;
+        struct json_object *v = NULL;
+
+        switch (json_object_get_type(obj)) {
+	case json_type_object:
+                key = lua_tostring(L, 2);
+                if (key)
+                        json_object_object_get_ex(obj, key, &v);
+                break;
+
+	case json_type_array:
+                index = lua_index = lua_tonumber(L, 2);
+                if (lua_index == (lua_Number)index && index >= 1)
+                        v = json_object_array_get_idx(obj, index-1);
+                break;
+
+	case json_type_string:
+        case json_type_null:
+                break;
+
+	case json_type_boolean:
+	case json_type_int:
+	case json_type_double:
+                luaL_error(L, "attempt to index a number or boolean value");
+                __builtin_unreachable();
+        }
+
+        gluon_site_wrap(L, v);
+        return 1;
+}
+
+static int gluon_site_call(lua_State *L) {
+        struct json_object *obj = gluon_site_udata(L, 1);
+
+        if (obj) {
+                lua_jsonc_push_json(L, obj);
+        } else {
+                if (lua_isnone(L, 2))
+                        lua_pushnil(L);
+                else
+                        lua_pushvalue(L, 2);
+        }
+
+        return 1;
+}
+
+static int gluon_site_gc(lua_State *L) {
+        json_object_put(gluon_site_udata(L, 1));
+        return 0;
+}
+
+static const luaL_reg R[] = {
+        { "__index", gluon_site_index },
+        { "__call", gluon_site_call },
+        { "__gc", gluon_site_gc },
+        {}
+};
+
+int luaopen_gluon_site(lua_State *L) {
+        luaL_newmetatable(L, UDATA);
+        luaL_register(L, NULL, R);
+        lua_pop(L, 1);
+
+        /* Create "none" object */
+        lua_pushlightuserdata(L, gluon_site_push_none);
+        gluon_site_do_wrap(L, NULL);
+        lua_rawset(L, LUA_REGISTRYINDEX);
+
+        struct json_object *site = gluonutil_load_site_config();
+        gluon_site_wrap(L, site);
+        json_object_put(site);
+
+	return 1;
+}
-- 
GitLab