From 146787fa5c966ddcf1b631e2df767177c0146372 Mon Sep 17 00:00:00 2001
From: lemoer <git@irrelefant.net>
Date: Sat, 28 Oct 2017 17:05:53 +0200
Subject: [PATCH] libgluonutil: merge domain and site configs

[Matthias Schiffer: rebase and simplify]
---
 package/libgluonutil/Makefile           |   2 +-
 package/libgluonutil/src/CMakeLists.txt |   2 +-
 package/libgluonutil/src/libgluonutil.c | 104 +++++++++++++++++++++++-
 package/libgluonutil/src/libgluonutil.h |   2 +
 4 files changed, 107 insertions(+), 3 deletions(-)

diff --git a/package/libgluonutil/Makefile b/package/libgluonutil/Makefile
index 489a9ba99..2536727c2 100644
--- a/package/libgluonutil/Makefile
+++ b/package/libgluonutil/Makefile
@@ -16,7 +16,7 @@ define Package/libgluonutil
   SECTION:=libs
   CATEGORY:=Libraries
   TITLE:=Gluon utility library
-  DEPENDS:=+libjson-c
+  DEPENDS:=+libjson-c +libuci
 endef
 
 CMAKE_OPTIONS += \
diff --git a/package/libgluonutil/src/CMakeLists.txt b/package/libgluonutil/src/CMakeLists.txt
index 7df17b1a3..41dd038a4 100644
--- a/package/libgluonutil/src/CMakeLists.txt
+++ b/package/libgluonutil/src/CMakeLists.txt
@@ -6,7 +6,7 @@ set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS _GNU_SOURCE)
 
 add_library(gluonutil SHARED libgluonutil.c)
 set_property(TARGET gluonutil PROPERTY COMPILE_FLAGS "-Wall -std=c99")
-target_link_libraries(gluonutil json-c)
+target_link_libraries(gluonutil json-c uci)
 install(TARGETS gluonutil
   ARCHIVE DESTINATION lib
   LIBRARY DESTINATION lib
diff --git a/package/libgluonutil/src/libgluonutil.c b/package/libgluonutil/src/libgluonutil.c
index db46b9c90..0f4bfe4a0 100644
--- a/package/libgluonutil/src/libgluonutil.c
+++ b/package/libgluonutil/src/libgluonutil.c
@@ -27,11 +27,44 @@
 #include "libgluonutil.h"
 
 #include <json-c/json.h>
+#include <uci.h>
 #include <arpa/inet.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <unistd.h>
+
+/**
+ * Merges two JSON objects
+ *
+ * Both objects are consumed. On conflicts, object b will be preferred.
+ */
+static struct json_object * merge_json(struct json_object *a, struct json_object *b) {
+	if (!json_object_is_type(a, json_type_object) || !json_object_is_type(b, json_type_object)) {
+		json_object_put(a);
+		return b;
+	}
+
+	json_object *m = json_object_new_object();
+
+	json_object_object_foreach(a, key_a, val_a)
+		json_object_object_add(m, key_a, json_object_get(val_a));
+	json_object_put(a);
 
+	json_object_object_foreach(b, key_b, val_b) {
+		struct json_object *val_m;
+
+		if (json_object_object_get_ex(m, key_b, &val_m))
+			val_m = merge_json(json_object_get(val_m), json_object_get(val_b));
+		else
+			val_m = json_object_get(val_b);
+
+		json_object_object_add(m, key_b, val_m);
+	}
+	json_object_put(b);
+
+	return m;
+}
 
 char * gluonutil_read_line(const char *filename) {
 	FILE *f = fopen(filename, "r");
@@ -141,6 +174,75 @@ bool gluonutil_get_node_prefix6(struct in6_addr *prefix) {
 }
 
 
+
+bool gluonutil_has_domains(void) {
+	return (access("/lib/gluon/domains/", F_OK) == 0);
+}
+
+char * gluonutil_get_domain(void) {
+	if (!gluonutil_has_domains())
+		return NULL;
+
+	char *ret = NULL;
+
+	struct uci_context *ctx = uci_alloc_context();
+	if (!ctx)
+		goto uci_fail;
+
+	ctx->flags &= ~UCI_FLAG_STRICT;
+
+	struct uci_package *p;
+	if (uci_load(ctx, "gluon", &p))
+		goto uci_fail;
+
+	struct uci_section *s = uci_lookup_section(ctx, p, "core");
+	if (!s)
+		goto uci_fail;
+
+	const char *domain_code = uci_lookup_option_string(ctx, s, "domain");
+	if (!domain_code)
+		goto uci_fail;
+
+	ret = strdup(domain_code);
+
+uci_fail:
+	if (ctx)
+		uci_free_context(ctx);
+
+	return ret;
+}
+
+
 struct json_object * gluonutil_load_site_config(void) {
-	return json_object_from_file("/lib/gluon/site.json");
+	char *domain_code = NULL;
+	struct json_object *site = NULL, *domain = NULL;
+
+	site = json_object_from_file("/lib/gluon/site.json");
+	if (!site)
+		return NULL;
+
+	if (!gluonutil_has_domains())
+		return site;
+
+	domain_code = gluonutil_get_domain();
+	if (!domain_code)
+		goto err;
+
+	{
+		const char *domain_path_fmt = "/lib/gluon/domains/%s.json";
+		char domain_path[strlen(domain_path_fmt) + strlen(domain_code)];
+		snprintf(domain_path, sizeof(domain_path), domain_path_fmt, domain_code);
+		free(domain_code);
+
+		domain = json_object_from_file(domain_path);
+	}
+	if (!domain)
+		goto err;
+
+	return merge_json(site, domain);
+
+err:
+	json_object_put(site);
+	free(domain_code);
+	return NULL;
 }
diff --git a/package/libgluonutil/src/libgluonutil.h b/package/libgluonutil/src/libgluonutil.h
index b2f90d699..39b253baa 100644
--- a/package/libgluonutil/src/libgluonutil.h
+++ b/package/libgluonutil/src/libgluonutil.h
@@ -40,6 +40,8 @@ bool gluonutil_get_node_prefix6(struct in6_addr *prefix);
 struct json_object * gluonutil_wrap_string(const char *str);
 struct json_object * gluonutil_wrap_and_free_string(char *str);
 
+bool gluonutil_has_domains(void);
+char * gluonutil_get_domain(void);
 struct json_object * gluonutil_load_site_config(void);
 
 #endif /* _LIBGLUON_LIBGLUON_H_ */
-- 
GitLab