aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/json.c
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2023-07-17 23:03:59 +0200
committerEgor Tensin <Egor.Tensin@gmail.com>2023-07-18 00:38:50 +0200
commite05f02acd583797ceb449fc501d371d45a4293c1 (patch)
tree491322cf633b67918f0361c1ce986f6b690844bc /src/json.c
parentdocker: sanitize package dependencies (diff)
downloadcimple-e05f02acd583797ceb449fc501d371d45a4293c1.tar.gz
cimple-e05f02acd583797ceb449fc501d371d45a4293c1.zip
switch to JSON-RPC as message format
Instead of the weird `struct msg` I had, I switched to the JSON-RPC format. It's basically the same, but has a well-defined semantics in case of errors.
Diffstat (limited to 'src/json.c')
-rw-r--r--src/json.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/src/json.c b/src/json.c
new file mode 100644
index 0000000..a01aae6
--- /dev/null
+++ b/src/json.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2023 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "cimple" project.
+ * For details, see https://github.com/egor-tensin/cimple.
+ * Distributed under the MIT License.
+ */
+
+#include "json.h"
+#include "log.h"
+#include "net.h"
+
+#include <json-c/json_object.h>
+#include <json-c/json_tokener.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *json_to_string(struct json_object *obj)
+{
+ const char *result = json_object_to_json_string(obj);
+ if (!result) {
+ json_errno("json_object_to_json_string");
+ return NULL;
+ }
+
+ char *_result = strdup(result);
+ if (!_result) {
+ log_errno("strdup");
+ return NULL;
+ }
+
+ return _result;
+}
+
+struct json_object *json_from_string(const char *src)
+{
+ enum json_tokener_error error;
+
+ struct json_object *result = json_tokener_parse_verbose(src, &error);
+ if (!result) {
+ json_errno("json_tokener_parse_verbose");
+ log_err("JSON: parsing failed: %s\n", json_tokener_error_desc(error));
+ return NULL;
+ }
+
+ return result;
+}
+
+int json_clone(const struct json_object *obj, const char *key, struct json_object **_value)
+{
+ int ret = 0;
+
+ struct json_object *old_value = NULL;
+ ret = json_get(obj, key, &old_value);
+ if (ret < 0)
+ return ret;
+
+ struct json_object *new_value = NULL;
+ ret = json_object_deep_copy(old_value, &new_value, NULL);
+ if (ret < 0)
+ return ret;
+
+ *_value = new_value;
+ return ret;
+}
+
+int json_send(struct json_object *obj, int fd)
+{
+ int ret = 0;
+
+ const char *str = json_to_string(obj);
+ if (!str)
+ return -1;
+
+ struct buf *buf = NULL;
+ ret = buf_pack_strings(&buf, 1, &str);
+ free((char *)str);
+ if (ret < 0)
+ return ret;
+
+ ret = net_send_buf(fd, buf);
+ buf_destroy(buf);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+struct json_object *json_recv(int fd)
+{
+ struct json_object *result = NULL;
+ int ret = 0;
+
+ struct buf *buf = NULL;
+ ret = net_recv_buf(fd, &buf);
+ if (ret < 0)
+ return NULL;
+
+ result = json_from_string((const char *)buf_get_data(buf));
+ if (!result)
+ goto destroy_buf;
+
+destroy_buf:
+ buf_destroy(buf);
+
+ return result;
+}
+
+int json_has(const struct json_object *obj, const char *key)
+{
+ return json_object_object_get_ex(obj, key, NULL);
+}
+
+int json_get(const struct json_object *obj, const char *key, struct json_object **value)
+{
+ if (!json_has(obj, key)) {
+ log_err("JSON: key is missing: %s\n", key);
+ return -1;
+ }
+
+ return json_object_object_get_ex(obj, key, value);
+}
+
+int json_get_string(const struct json_object *obj, const char *key, const char **_value)
+{
+ struct json_object *value = NULL;
+
+ int ret = json_get(obj, key, &value);
+ if (ret < 0)
+ return ret;
+
+ if (!json_object_is_type(value, json_type_string)) {
+ log_err("JSON: key is not a string: %s\n", key);
+ return -1;
+ }
+
+ *_value = json_object_get_string(value);
+ return 0;
+}
+
+int json_get_int(const struct json_object *obj, const char *key, int64_t *_value)
+{
+ struct json_object *value = NULL;
+
+ int ret = json_get(obj, key, &value);
+ if (ret < 0)
+ return ret;
+
+ if (!json_object_is_type(value, json_type_int)) {
+ log_err("JSON: key is not an integer: %s\n", key);
+ return -1;
+ }
+
+ errno = 0;
+ int64_t tmp = json_object_get_int64(value);
+ if (errno) {
+ log_err("JSON: failed to parse integer from key: %s\n", key);
+ return -1;
+ }
+
+ *_value = tmp;
+ return 0;
+}
+
+static int json_set_internal(struct json_object *obj, const char *key, struct json_object *value,
+ unsigned flags)
+{
+ int ret = 0;
+
+ ret = json_object_object_add_ex(obj, key, value, flags);
+ if (ret < 0) {
+ json_errno("json_object_object_add_ex");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int json_set_string_internal(struct json_object *obj, const char *key, const char *_value,
+ unsigned flags)
+{
+ struct json_object *value = json_object_new_string(_value);
+ if (!value) {
+ json_errno("json_object_new_string");
+ return -1;
+ }
+
+ int ret = json_set_internal(obj, key, value, flags);
+ if (ret < 0)
+ goto free_value;
+
+ return ret;
+
+free_value:
+ json_object_put(value);
+
+ return ret;
+}
+
+static int json_set_int_internal(struct json_object *obj, const char *key, int64_t _value,
+ unsigned flags)
+{
+ struct json_object *value = json_object_new_int64(_value);
+ if (!value) {
+ json_errno("json_object_new_int");
+ return -1;
+ }
+
+ int ret = json_set_internal(obj, key, value, flags);
+ if (ret < 0)
+ goto free_value;
+
+ return ret;
+
+free_value:
+ json_object_put(value);
+
+ return ret;
+}
+
+int json_set(struct json_object *obj, const char *key, struct json_object *value)
+{
+ return json_set_internal(obj, key, value, 0);
+}
+
+int json_set_string(struct json_object *obj, const char *key, const char *value)
+{
+ return json_set_string_internal(obj, key, value, 0);
+}
+
+int json_set_int(struct json_object *obj, const char *key, int64_t value)
+{
+ return json_set_int_internal(obj, key, value, 0);
+}
+
+#ifndef JSON_C_OBJECT_ADD_CONSTANT_KEY
+#define JSON_C_OBJECT_ADD_CONSTANT_KEY JSON_C_OBJECT_KEY_IS_CONSTANT
+#endif
+static const unsigned json_const_key_flags = JSON_C_OBJECT_ADD_CONSTANT_KEY;
+
+int json_set_const_key(struct json_object *obj, const char *key, struct json_object *value)
+{
+ return json_set_internal(obj, key, value, json_const_key_flags);
+}
+
+int json_set_string_const_key(struct json_object *obj, const char *key, const char *value)
+{
+ return json_set_string_internal(obj, key, value, json_const_key_flags);
+}
+
+int json_set_int_const_key(struct json_object *obj, const char *key, int64_t value)
+{
+ return json_set_int_internal(obj, key, value, json_const_key_flags);
+}