#include "platform.h" #include "gnunet_jsonapi_lib.h" #include "jsonapi_objects.h" /** * String serialze jsonapi resources * * @param data the JSON API resource * @param result where to store the result * @return GNUNET_SYSERR on error else GNUNET_OK */ int GNUNET_JSONAPI_resource_to_json (const struct GNUNET_JSONAPI_Resource *res, json_t **result) { struct GNUNET_JSONAPI_Resource *rel_res; json_t *relationship; json_t *res_json_tmp; *result = json_object (); if (0 != json_object_set_new (*result, GNUNET_JSONAPI_KEY_ID, json_string (res->id))) return GNUNET_SYSERR; if (0 != json_object_set_new (*result, GNUNET_JSONAPI_KEY_TYPE, json_string (res->type))) return GNUNET_SYSERR; if ((NULL != res->attr_obj) && (0 != json_object_set (*result, GNUNET_JSONAPI_KEY_ATTRIBUTES, res->attr_obj))) return GNUNET_SYSERR; //Relationships if (NULL != res->relationship) { relationship = json_object (); if (0 != res->relationship->res_count) { json_t *res_json; switch (res->relationship->res_count) { case 0: res_json = json_null(); break; case 1: GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_resource_to_json (res->relationship->res_list_head, &res_json)); break; default: res_json = json_array (); rel_res = NULL; for (rel_res = res->relationship->res_list_head; rel_res != NULL; rel_res = rel_res->next) { GNUNET_assert (GNUNET_OK == GNUNET_JSONAPI_resource_to_json (rel_res, &res_json_tmp)); json_array_append_new (res_json, res_json_tmp); } break; } json_object_set_new (relationship, GNUNET_JSONAPI_KEY_DATA, res_json); } if ((NULL != res->relationship->meta) && (0 != json_object_set_new (relationship, GNUNET_JSONAPI_KEY_META, res->relationship->meta))) return GNUNET_SYSERR; //TODO link } return GNUNET_OK; } /** * Create a JSON API resource * * @param type the JSON API resource type * @param id the JSON API resource id * @return a new JSON API resource or NULL on error. */ struct GNUNET_JSONAPI_Resource* GNUNET_JSONAPI_resource_new (const char *type, const char *id) { struct GNUNET_JSONAPI_Resource *res; if (NULL == type) return NULL; if (NULL == id) return NULL; res = GNUNET_new (struct GNUNET_JSONAPI_Resource); res->prev = NULL; res->next = NULL; res->attr_obj = NULL; res->relationship = NULL; res->id = GNUNET_strdup (id); res->type = GNUNET_strdup (type); return res; } /** * Add a jsonapi relationship * @param res the resource to add to * @param rel the relationship to add * @return #GNUNETOK if added successfully */ int GNUNET_JSONAPI_resource_set_relationship (struct GNUNET_JSONAPI_Resource *res, struct GNUNET_JSONAPI_Relationship *rel) { GNUNET_assert (NULL != res); GNUNET_assert (NULL != rel); if (NULL != res->relationship) return GNUNET_SYSERR; res->relationship = rel; return GNUNET_OK; } /** * Add a JSON API attribute * * @param res the JSON resource * @param key the key for the attribute * @param json the json_t attribute to add * @return #GNUNET_OK if added successfully * #GNUNET_SYSERR if not */ int GNUNET_JSONAPI_resource_add_attr (struct GNUNET_JSONAPI_Resource *resource, const char* key, json_t *json) { if ( (NULL == resource) || (NULL == key) || (NULL == json) ) return GNUNET_SYSERR; if (NULL == resource->attr_obj) resource->attr_obj = json_object (); json_object_set (resource->attr_obj, key, json); return GNUNET_OK; } /** * Read a JSON API attribute * * @param res the JSON resource * @param key the key for the attribute * @return the json_t object */ json_t* GNUNET_JSONAPI_resource_read_attr (const struct GNUNET_JSONAPI_Resource *resource, const char* key) { if ( (NULL == resource) || (NULL == key) || (NULL == resource->attr_obj)) return NULL; return json_object_get (resource->attr_obj, key); } int check_resource_attr_str (const struct GNUNET_JSONAPI_Resource *resource, const char* key, const char* attr) { json_t *value; if ( (NULL == resource) || (NULL == key) || (NULL == attr) || (NULL == resource->attr_obj)) return GNUNET_NO; value = json_object_get (resource->attr_obj, key); if (NULL == value) return GNUNET_NO; if (!json_is_string (value) || (0 != strcmp (attr, json_string_value(value)))) { return GNUNET_NO; } return GNUNET_YES; } /** * Check a JSON API resource type * * @param res the JSON resource * @param type the expected type * @return GNUNET_YES if id matches */ int GNUNET_JSONAPI_resource_check_type (const struct GNUNET_JSONAPI_Resource *resource, const char* type) { return (0 == memcmp (type, resource->type, strlen (resource->type))) ? GNUNET_YES : GNUNET_NO; } /** * Delete a JSON API resource * * @param res the JSON resource * @param result Pointer where the resource should be stored */ void GNUNET_JSONAPI_resource_delete (struct GNUNET_JSONAPI_Resource *resource) { GNUNET_free (resource->id); GNUNET_free (resource->type); if (NULL != resource->attr_obj) json_decref (resource->attr_obj); if (NULL != resource->relationship) GNUNET_JSONAPI_relationship_delete (resource->relationship); GNUNET_free (resource); resource = NULL; } /** * Check a JSON API resource id * * @param res the JSON resource * @param id the expected id * @return GNUNET_YES if id matches */ int GNUNET_JSONAPI_resource_check_id (const struct GNUNET_JSONAPI_Resource *resource, const char* id) { return (0 == memcmp (resource->id, id, strlen (id))) ? GNUNET_YES : GNUNET_NO; } /** * Check a JSON API resource id * * @param res the JSON resource * @return the resource id */ const char* GNUNET_JSONAPI_resource_get_id (const struct GNUNET_JSONAPI_Resource *resource) { return resource->id; } /** * Parse json to resource object * * @param res_json JSON object * @param[out] res resource object * @return GNUNET_OK on success */ int GNUNET_JSONAPI_json_to_resource (json_t *res_json, struct GNUNET_JSONAPI_Resource **res) { struct GNUNET_JSON_Specification jsonapispecresource[] = { GNUNET_JSON_spec_jsonapi_resource (res), GNUNET_JSON_spec_end() }; return GNUNET_JSON_parse (res_json, jsonapispecresource, NULL, NULL); } /** * Parse given JSON object to jsonapi document. * * @param cls closure, NULL * @param root the json object representing data * @param[out] spec where to write the data * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error */ static int parse_jsonapiresource (void *cls, json_t *root, struct GNUNET_JSON_Specification *spec) { struct GNUNET_JSONAPI_Resource *res; const char *type; const char *id; json_t *attrs; struct GNUNET_JSON_Specification dspec[] = { GNUNET_JSON_spec_string (GNUNET_JSONAPI_KEY_TYPE, &type), GNUNET_JSON_spec_string (GNUNET_JSONAPI_KEY_ID, &id), GNUNET_JSON_spec_end() }; if (GNUNET_OK != GNUNET_JSON_parse (root, dspec, NULL, NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unable to parse resource\n"); return GNUNET_SYSERR; } res = GNUNET_JSONAPI_resource_new (type, id); GNUNET_JSON_parse_free (dspec); struct GNUNET_JSON_Specification attrspec[] = { GNUNET_JSON_spec_json (GNUNET_JSONAPI_KEY_ATTRIBUTES, &attrs), GNUNET_JSON_spec_end() }; if (GNUNET_OK != GNUNET_JSON_parse (root, attrspec, NULL, NULL)) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Resource does not contain attributes\n"); if (NULL != attrs) res->attr_obj = json_deep_copy (attrs); //TODO relationship GNUNET_JSON_parse_free (attrspec); *(struct GNUNET_JSONAPI_Resource **) spec->ptr = res; return GNUNET_OK; } /** * Cleanup data left from parsing resource. * * @param cls closure, NULL * @param[out] spec where to free the data */ static void clean_jsonapiresource (void *cls, struct GNUNET_JSON_Specification *spec) { struct GNUNET_JSONAPI_Resource **jsonapi_obj; jsonapi_obj = (struct GNUNET_JSONAPI_Resource **) spec->ptr; if (NULL != *jsonapi_obj) { GNUNET_JSONAPI_resource_delete (*jsonapi_obj); *jsonapi_obj = NULL; } } /** * JSON object. * * @param name name of the JSON field * @param[out] jsonp where to store the JSON found under @a name */ struct GNUNET_JSON_Specification GNUNET_JSON_spec_jsonapi_resource (struct GNUNET_JSONAPI_Resource **jsonapi_object) { struct GNUNET_JSON_Specification ret = { .parser = &parse_jsonapiresource, .cleaner = &clean_jsonapiresource, .cls = NULL, .field = NULL, .ptr = jsonapi_object, .ptr_size = 0, .size_ptr = NULL }; *jsonapi_object = NULL; return ret; }