Browse Source

libgluonutil: merge domain and site configs

[Matthias Schiffer: rebase and simplify]
lemoer 6 years ago
parent
commit
146787fa5c

+ 1 - 1
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 += \

+ 1 - 1
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

+ 103 - 1
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;
 }

+ 2 - 0
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_ */