mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
lws_struct: store which toplevel schema matched
We can give the lws_struct parser a table of toplevel schemas, record which one we chose so the caller can know how to interpret the result
This commit is contained in:
parent
30fc8e9caf
commit
55ea791a77
3 changed files with 158 additions and 22 deletions
|
@ -70,6 +70,8 @@ typedef struct lws_struct_args {
|
|||
size_t ac_block_size;
|
||||
int subtype;
|
||||
|
||||
int top_schema_index;
|
||||
|
||||
/*
|
||||
* temp ac used to collate unknown possibly huge strings before final
|
||||
* allocation and copy
|
||||
|
@ -230,7 +232,8 @@ lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason);
|
|||
|
||||
LWS_VISIBLE LWS_EXTERN lws_struct_serialize_t *
|
||||
lws_struct_json_serialize_create(const lws_struct_map_t *map,
|
||||
size_t map_entries, int flags, void *ptoplevel);
|
||||
size_t map_entries, int flags,
|
||||
const void *ptoplevel);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_struct_json_serialize_destroy(lws_struct_serialize_t **pjs);
|
||||
|
|
|
@ -51,6 +51,8 @@ lws_struct_schema_only_lejp_cb(struct lejp_ctx *ctx, char reason)
|
|||
return 1;
|
||||
}
|
||||
a->dest_len = map->aux;
|
||||
if (!ctx->pst_sp)
|
||||
a->top_schema_index = (int)(map - a->map_st[ctx->pst_sp]);
|
||||
|
||||
if (!cb)
|
||||
cb = lws_struct_default_lejp_cb;
|
||||
|
@ -365,6 +367,7 @@ chunk_copy:
|
|||
if (b > lim)
|
||||
b = lim;
|
||||
memcpy(s, ctx->buf, b);
|
||||
s[b] = '\0';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -404,7 +407,7 @@ lws_struct_json_init_parse(struct lejp_ctx *ctx, lejp_callback cb, void *user)
|
|||
lws_struct_serialize_t *
|
||||
lws_struct_json_serialize_create(const lws_struct_map_t *map,
|
||||
size_t map_entries, int flags,
|
||||
void *ptoplevel)
|
||||
const void *ptoplevel)
|
||||
{
|
||||
lws_struct_serialize_t *js = lws_zalloc(sizeof(*js), __func__);
|
||||
lws_struct_serialize_st_t *j;
|
||||
|
@ -601,7 +604,7 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
|
|||
if (js->sp + 1 == LEJP_MAX_PARSING_STACK_DEPTH)
|
||||
return LSJS_RESULT_ERROR;
|
||||
|
||||
/* add a stack level tto handle parsing child members */
|
||||
/* add a stack level to handle parsing child members */
|
||||
|
||||
n = j->idt;
|
||||
j = &js->st[++js->sp];
|
||||
|
@ -615,6 +618,7 @@ lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
|
|||
len--;
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
j->obj = q;
|
||||
|
||||
continue;
|
||||
|
||||
case LSMT_SCHEMA:
|
||||
|
|
|
@ -119,6 +119,10 @@ static const char * const json_tests[] = {
|
|||
"yJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx"
|
||||
"+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\"}]}"
|
||||
"}",
|
||||
"{" /* test 8 the "other" schema */
|
||||
"\"schema\":\"com-warmcat-sai-other\","
|
||||
"\"name\":\"somename\""
|
||||
"}",
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -170,7 +174,8 @@ static const char * const json_expected[] = {
|
|||
"V+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yuyJln+v4R"
|
||||
"IWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5v"
|
||||
"METteZlx+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\""
|
||||
",\"someflag\":false}]}"
|
||||
",\"someflag\":false}]}",
|
||||
"{\"schema\":\"com-warmcat-sai-other\",\"name\":\"somename\"}"
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -210,6 +215,8 @@ static const lws_struct_map_t lsm_target[] = {
|
|||
NULL, lsm_child, "child"),
|
||||
};
|
||||
|
||||
/* the first kind of struct / schema we can receive */
|
||||
|
||||
/* builder object */
|
||||
|
||||
typedef struct sai_builder {
|
||||
|
@ -227,20 +234,66 @@ static const lws_struct_map_t lsm_builder[] = {
|
|||
NULL, lsm_target, "targets"),
|
||||
};
|
||||
|
||||
/* Schema table
|
||||
/*
|
||||
* the second kind of struct / schema we can receive
|
||||
*/
|
||||
|
||||
typedef struct sai_other {
|
||||
char name[32];
|
||||
} sai_other_t;
|
||||
|
||||
static const lws_struct_map_t lsm_other[] = {
|
||||
LSM_CARRAY (sai_other_t, name, "name"),
|
||||
};
|
||||
|
||||
/*
|
||||
* meta composed pointers test
|
||||
*
|
||||
* We serialize a struct that consists of members that point to other objects,
|
||||
* we expect this kind of thing
|
||||
*
|
||||
* {
|
||||
* "schema": "meta",
|
||||
* "t": { ... },
|
||||
* "e": { ...}
|
||||
* }
|
||||
*/
|
||||
|
||||
typedef struct meta {
|
||||
sai_target_t *t;
|
||||
sai_builder_t *b;
|
||||
} meta_t;
|
||||
|
||||
static const lws_struct_map_t lsm_meta[] = {
|
||||
LSM_CHILD_PTR (meta_t, t, sai_target_t, NULL, lsm_target, "t"),
|
||||
LSM_CHILD_PTR (meta_t, b, sai_child_t, NULL, lsm_builder, "e"),
|
||||
};
|
||||
|
||||
static const lws_struct_map_t lsm_schema_meta[] = {
|
||||
LSM_SCHEMA (meta_t, NULL, lsm_meta, "meta.schema"),
|
||||
};
|
||||
|
||||
/*
|
||||
* Schema table
|
||||
*
|
||||
* Before we can understand the serialization top level format, we must read
|
||||
* the schema, use the table below to create the right toplevel object for the
|
||||
* schema name, and select the correct map tables to interpret the rest of the
|
||||
* serialization.
|
||||
*
|
||||
* Therefore the schema tables below are the starting point for the
|
||||
* JSON deserialization.
|
||||
* In this example there are two completely separate structs / schemas possible
|
||||
* to receive, and we disambiguate and create the correct one using the schema
|
||||
* JSON node.
|
||||
*
|
||||
* Therefore the schema table below is the starting point for the JSON
|
||||
* deserialization.
|
||||
*/
|
||||
|
||||
static const lws_struct_map_t lsm_schema_map[] = {
|
||||
LSM_SCHEMA (sai_builder_t, NULL,
|
||||
lsm_builder, "com-warmcat-sai-builder"),
|
||||
LSM_SCHEMA (sai_other_t, NULL,
|
||||
lsm_other, "com-warmcat-sai-other"),
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -268,8 +321,11 @@ int main(int argc, const char **argv)
|
|||
#endif
|
||||
struct lejp_ctx ctx;
|
||||
lws_struct_args_t a;
|
||||
sai_builder_t *b;
|
||||
sai_builder_t *b, mb;
|
||||
sai_target_t mt;
|
||||
sai_other_t *o;
|
||||
const char *p;
|
||||
meta_t meta;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
@ -299,27 +355,58 @@ int main(int argc, const char **argv)
|
|||
}
|
||||
lwsac_info(a.ac);
|
||||
|
||||
b = a.dest;
|
||||
if (!b) {
|
||||
lwsl_err("%s: didn't produce any output\n", __func__);
|
||||
e++;
|
||||
goto done;
|
||||
if (m + 1 != 8) {
|
||||
b = a.dest;
|
||||
if (!b) {
|
||||
lwsl_err("%s: didn't produce any output\n", __func__);
|
||||
e++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (a.top_schema_index) {
|
||||
lwsl_err("%s: wrong top_schema_index\n", __func__);
|
||||
e++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
lwsl_notice("builder.hostname = '%s', timeout = %d, targets (%d)\n",
|
||||
b->hostname, b->nspawn_timeout,
|
||||
b->targets.count);
|
||||
|
||||
lws_dll2_foreach_safe(&b->targets, NULL, show_target);
|
||||
} else {
|
||||
o = a.dest;
|
||||
if (!o) {
|
||||
lwsl_err("%s: didn't produce any output\n", __func__);
|
||||
e++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (a.top_schema_index != 1) {
|
||||
lwsl_err("%s: wrong top_schema_index\n", __func__);
|
||||
e++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
lwsl_notice("other.name = '%s'\n", o->name);
|
||||
}
|
||||
|
||||
lwsl_notice("builder.hostname = '%s', timeout = %d, targets (%d)\n",
|
||||
b->hostname, b->nspawn_timeout,
|
||||
b->targets.count);
|
||||
|
||||
lws_dll2_foreach_safe(&b->targets, NULL, show_target);
|
||||
|
||||
/* 2. serialize the structs into JSON and confirm */
|
||||
|
||||
lwsl_notice("%s: .... strarting serialization of test %d\n",
|
||||
__func__, m + 1);
|
||||
ser = lws_struct_json_serialize_create(lsm_schema_map,
|
||||
|
||||
if (m + 1 != 8) {
|
||||
ser = lws_struct_json_serialize_create(lsm_schema_map,
|
||||
LWS_ARRAY_SIZE(lsm_schema_map),
|
||||
0//LSSERJ_FLAG_PRETTY
|
||||
, b);
|
||||
} else {
|
||||
ser = lws_struct_json_serialize_create(&lsm_schema_map[1],
|
||||
1,
|
||||
0//LSSERJ_FLAG_PRETTY
|
||||
, o);
|
||||
}
|
||||
if (!ser) {
|
||||
lwsl_err("%s: unable to init serialization\n", __func__);
|
||||
goto bail;
|
||||
|
@ -328,12 +415,11 @@ int main(int argc, const char **argv)
|
|||
do {
|
||||
n = lws_struct_json_serialize(ser, buf, sizeof(buf),
|
||||
&written);
|
||||
lwsl_notice("ser says %d\n", n);
|
||||
switch (n) {
|
||||
case LSJS_RESULT_CONTINUE:
|
||||
case LSJS_RESULT_FINISH:
|
||||
puts((const char *)buf);
|
||||
break;
|
||||
case LSJS_RESULT_CONTINUE:
|
||||
case LSJS_RESULT_ERROR:
|
||||
goto bail;
|
||||
}
|
||||
|
@ -343,6 +429,7 @@ int main(int argc, const char **argv)
|
|||
lwsl_err("%s: test %d: expected %s\n", __func__, m + 1,
|
||||
json_expected[m]);
|
||||
e++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
lws_struct_json_serialize_destroy(&ser);
|
||||
|
@ -354,6 +441,48 @@ done:
|
|||
if (e)
|
||||
goto bail;
|
||||
|
||||
/* ad-hoc tests */
|
||||
|
||||
memset(&meta, 0, sizeof(meta));
|
||||
memset(&mb, 0, sizeof(mb));
|
||||
memset(&mt, 0, sizeof(mt));
|
||||
|
||||
meta.t = &mt;
|
||||
meta.b = &mb;
|
||||
|
||||
meta.t->name = "mytargetname";
|
||||
lws_strncpy(meta.b->hostname, "myhostname", sizeof(meta.b->hostname));
|
||||
ser = lws_struct_json_serialize_create(lsm_schema_meta, 1, 0,
|
||||
&meta);
|
||||
if (!ser) {
|
||||
lwsl_err("%s: failed to create json\n", __func__);
|
||||
|
||||
|
||||
}
|
||||
do {
|
||||
n = lws_struct_json_serialize(ser, buf, sizeof(buf), &written);
|
||||
switch (n) {
|
||||
case LSJS_RESULT_CONTINUE:
|
||||
case LSJS_RESULT_FINISH:
|
||||
puts((const char *)buf);
|
||||
if (strcmp((const char *)buf,
|
||||
"{\"schema\":\"meta.schema\","
|
||||
"\"t\":{\"name\":\"mytargetname\","
|
||||
"\"someflag\":false},"
|
||||
"\"e\":{\"hostname\":\"myhostname\","
|
||||
"\"nspawn_timeout\":0}}")) {
|
||||
lwsl_err("%s: meta test fail\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
break;
|
||||
case LSJS_RESULT_ERROR:
|
||||
goto bail;
|
||||
}
|
||||
} while(n == LSJS_RESULT_CONTINUE);
|
||||
|
||||
lws_struct_json_serialize_destroy(&ser);
|
||||
|
||||
|
||||
lwsl_user("Completed: PASS\n");
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue