mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-16 00:00:07 +01:00

Really not having any logs makes it difficult to know what is really happening, but if that's you're thing this will align debug and release modes to just have ERR and USER if you give WITH_NO_LOGS
236 lines
5.9 KiB
C
236 lines
5.9 KiB
C
/*
|
|
* lws-api-test-lws_struct-json
|
|
*
|
|
* Written in 2010-2020 by Andy Green <andy@warmcat.com>
|
|
*
|
|
* This file is made available under the Creative Commons CC0 1.0
|
|
* Universal Public Domain Dedication.
|
|
*
|
|
* lws_struct apis are used to serialize and deserialize your C structs and
|
|
* linked-lists in a standardized way that's very modest on memory but
|
|
* convenient and easy to maintain.
|
|
*
|
|
* This second test file shows a worked example for how to express a schema
|
|
* and both consume JSON -> struct and struct -> JSON for it.
|
|
*/
|
|
|
|
#include <libwebsockets.h>
|
|
|
|
static const char * const test2_json =
|
|
"{"
|
|
"\"config\":["
|
|
"{"
|
|
"\"id1\":" "null,"
|
|
"\"creds\":{"
|
|
"\"key1\":" "\"\\\"xxxxxxxxx\\\"\","
|
|
"\"key2\":" "null"
|
|
"},"
|
|
"\"frequency\":" "0,"
|
|
"\"arg1\":" "\"val1\","
|
|
"\"arg2\":" "0,"
|
|
"\"priority\":" "1,"
|
|
"\"ssid\":" "\"\\\"nw2\\\"\""
|
|
"}, {"
|
|
"\"id2\":" "null,"
|
|
"\"creds\": {"
|
|
"\"key1\":" "\"\\\"xxxxxxxxxxxxx\\\"\","
|
|
"\"key2\":" "null"
|
|
"},"
|
|
"\"frequency\":" "11,"
|
|
"\"arg1\":" "\"val2\","
|
|
"\"arg2\":" "1420887242594,"
|
|
"\"priority\":" "3,"
|
|
"\"ssid\":" "\"\\\"nw1\\\"\""
|
|
"}"
|
|
"]"
|
|
"}";
|
|
|
|
static const char * const test2_json_expected =
|
|
"{\"config\":[{\"creds\":{\"key1\":\"\\u0022xxxxxxxxx\\u0022\"},"
|
|
"\"arg1\":\"val1\",\"ssid\":\"\\u0022nw2\\u0022\","
|
|
"\"frequency\":0,\"arg2\":0,\"priority\":1},"
|
|
"{\"creds\":{\"key1\":\"\\u0022xxxxxxxxxxxxx\\u0022\"},"
|
|
"\"arg1\":\"val2\",\"ssid\":\"\\u0022nw1\\u0022\","
|
|
"\"frequency\":11,\"arg2\":1420887242594,\"priority\":3}]}"
|
|
;
|
|
|
|
/*
|
|
* level 3: Credentials object
|
|
*/
|
|
|
|
typedef struct t2_cred {
|
|
const char *key1;
|
|
const char *key2;
|
|
} t2_cred_t;
|
|
|
|
static const lws_struct_map_t lsm_t2_cred[] = {
|
|
LSM_STRING_PTR (t2_cred_t, key1, "key1"),
|
|
LSM_STRING_PTR (t2_cred_t, key2, "key2"),
|
|
};
|
|
|
|
/*
|
|
* level 2: Configuration object, containing a child credentials object
|
|
*/
|
|
|
|
typedef struct t2_config {
|
|
lws_dll2_t list;
|
|
t2_cred_t *creds;
|
|
const char *id1;
|
|
const char *arg1;
|
|
const char *ssid;
|
|
unsigned int frequency;
|
|
unsigned long long arg2;
|
|
unsigned int priority;
|
|
} t2_config_t;
|
|
|
|
static const lws_struct_map_t lsm_t2_config[] = {
|
|
LSM_CHILD_PTR (t2_config_t,
|
|
creds, /* the child pointer member */
|
|
t2_cred_t, /* the child type */
|
|
NULL, lsm_t2_cred, /* map object for item type */
|
|
"creds"), /* outer json object name */
|
|
LSM_STRING_PTR (t2_config_t, id1, "id1"),
|
|
LSM_STRING_PTR (t2_config_t, arg1, "arg1"),
|
|
LSM_STRING_PTR (t2_config_t, ssid, "ssid"),
|
|
|
|
LSM_UNSIGNED (t2_config_t, frequency, "frequency"),
|
|
LSM_UNSIGNED (t2_config_t, arg2, "arg2"),
|
|
LSM_UNSIGNED (t2_config_t, priority, "priority"),
|
|
};
|
|
|
|
/*
|
|
* level 1: list-of-configurations object
|
|
*/
|
|
|
|
typedef struct t2_configs {
|
|
lws_dll2_owner_t configs;
|
|
} t2_configs_t;
|
|
|
|
static const lws_struct_map_t lsm_t2_configs[] = {
|
|
LSM_LIST (t2_configs_t, configs, /* the list owner type/member */
|
|
t2_config_t, list, /* the list item type/member */
|
|
NULL, lsm_t2_config, /* map object for item type */
|
|
"config"), /* outer json object name */
|
|
};
|
|
|
|
/*
|
|
* For parsing, this lists the kind of object we expect to parse so the struct
|
|
* can be allocated polymorphically.
|
|
*
|
|
* Lws uses an explicit "schema" member so the type is known unambiguously. If
|
|
* in the incoming JSON the first member is not "schema", it will scan the
|
|
* maps listed here and instantiate the first object that has a member of that
|
|
* name.
|
|
*/
|
|
|
|
static const lws_struct_map_t lsm_schema[] = {
|
|
LSM_SCHEMA (t2_configs_t, NULL, lsm_t2_configs, "t2"),
|
|
/* other schemata that might need parsing... */
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
t2_config_dump(struct lws_dll2 *d, void *user)
|
|
{
|
|
#if !defined(LWS_WITH_NO_LOGS)
|
|
t2_config_t *c = lws_container_of(d, t2_config_t, list);
|
|
|
|
lwsl_notice("%s: id1 '%s'\n", __func__, c->id1);
|
|
lwsl_notice("%s: arg1 '%s'\n", __func__, c->arg1);
|
|
lwsl_notice("%s: ssid '%s'\n", __func__, c->ssid);
|
|
|
|
lwsl_notice("%s: freq %d\n", __func__, c->frequency);
|
|
lwsl_notice("%s: arg2 %llu\n", __func__, c->arg2);
|
|
lwsl_notice("%s: priority %d\n", __func__, c->priority);
|
|
|
|
lwsl_notice("%s: key1: %s, key2: %s\n", __func__,
|
|
c->creds->key1, c->creds->key2);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
t2_configs_dump(t2_configs_t *t2cs)
|
|
{
|
|
lwsl_notice("%s: number of configs: %d\n", __func__,
|
|
t2cs->configs.count);
|
|
|
|
lws_dll2_foreach_safe(&t2cs->configs, NULL, t2_config_dump);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
test2(void)
|
|
{
|
|
lws_struct_serialize_t *ser;
|
|
struct lejp_ctx ctx;
|
|
lws_struct_args_t a;
|
|
t2_configs_t *top;
|
|
uint8_t buf[4096];
|
|
size_t written;
|
|
int n, bad = 1;
|
|
|
|
lwsl_notice("%s: start \n", __func__);
|
|
|
|
memset(&a, 0, sizeof(a));
|
|
a.map_st[0] = lsm_schema;
|
|
a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema);
|
|
a.ac_block_size = 512;
|
|
lws_struct_json_init_parse(&ctx, NULL, &a);
|
|
|
|
n = lejp_parse(&ctx, (uint8_t *)test2_json, (int)strlen(test2_json));
|
|
lwsl_notice("%s: lejp_parse %d\n", __func__, n);
|
|
if (n < 0) {
|
|
lwsl_err("%s: test2 JSON decode failed '%s'\n",
|
|
__func__, lejp_error_to_string(n));
|
|
goto bail;
|
|
}
|
|
lwsac_info(a.ac);
|
|
|
|
top = (t2_configs_t *)a.dest; /* the top level object */
|
|
|
|
if (!top) {
|
|
lwsl_err("%s: no top level object\n", __func__);
|
|
goto bail;
|
|
}
|
|
t2_configs_dump(top);
|
|
|
|
/* 2. Let's reserialize the top level object and see what comes out */
|
|
|
|
ser = lws_struct_json_serialize_create(&lsm_schema[0], 1,
|
|
LSSERJ_FLAG_OMIT_SCHEMA, top);
|
|
if (!ser) {
|
|
lwsl_err("%s: unable to init serialization\n", __func__);
|
|
goto bail;
|
|
}
|
|
|
|
do {
|
|
n = (int)lws_struct_json_serialize(ser, buf, sizeof(buf), &written);
|
|
switch (n) {
|
|
case LSJS_RESULT_FINISH:
|
|
puts((const char *)buf);
|
|
break;
|
|
case LSJS_RESULT_CONTINUE:
|
|
case LSJS_RESULT_ERROR:
|
|
goto bail;
|
|
}
|
|
} while (n == LSJS_RESULT_CONTINUE);
|
|
|
|
if (strcmp(test2_json_expected, (char *)buf)) {
|
|
lwsl_err("%s: expected %s\n", __func__, test2_json_expected);
|
|
goto bail;
|
|
}
|
|
|
|
lws_struct_json_serialize_destroy(&ser);
|
|
|
|
bad = 0;
|
|
|
|
bail:
|
|
lwsac_free(&a.ac);
|
|
|
|
return bad;
|
|
}
|