1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-api-test-lws_struct-json 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2020 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci * 9d4afb5ceSopenharmony_ci * lws_struct apis are used to serialize and deserialize your C structs and 10d4afb5ceSopenharmony_ci * linked-lists in a standardized way that's very modest on memory but 11d4afb5ceSopenharmony_ci * convenient and easy to maintain. 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * This second test file shows a worked example for how to express a schema 14d4afb5ceSopenharmony_ci * and both consume JSON -> struct and struct -> JSON for it. 15d4afb5ceSopenharmony_ci */ 16d4afb5ceSopenharmony_ci 17d4afb5ceSopenharmony_ci#include <libwebsockets.h> 18d4afb5ceSopenharmony_ci 19d4afb5ceSopenharmony_cistatic const char * const test2_json = 20d4afb5ceSopenharmony_ci"{" 21d4afb5ceSopenharmony_ci "\"config\":[" 22d4afb5ceSopenharmony_ci "{" 23d4afb5ceSopenharmony_ci "\"id1\":" "null," 24d4afb5ceSopenharmony_ci "\"creds\":{" 25d4afb5ceSopenharmony_ci "\"key1\":" "\"\\\"xxxxxxxxx\\\"\"," 26d4afb5ceSopenharmony_ci "\"key2\":" "null" 27d4afb5ceSopenharmony_ci "}," 28d4afb5ceSopenharmony_ci "\"frequency\":" "0," 29d4afb5ceSopenharmony_ci "\"arg1\":" "\"val1\"," 30d4afb5ceSopenharmony_ci "\"arg2\":" "0," 31d4afb5ceSopenharmony_ci "\"priority\":" "1," 32d4afb5ceSopenharmony_ci "\"ssid\":" "\"\\\"nw2\\\"\"" 33d4afb5ceSopenharmony_ci "}, {" 34d4afb5ceSopenharmony_ci "\"id2\":" "null," 35d4afb5ceSopenharmony_ci "\"creds\": {" 36d4afb5ceSopenharmony_ci "\"key1\":" "\"\\\"xxxxxxxxxxxxx\\\"\"," 37d4afb5ceSopenharmony_ci "\"key2\":" "null" 38d4afb5ceSopenharmony_ci "}," 39d4afb5ceSopenharmony_ci "\"frequency\":" "11," 40d4afb5ceSopenharmony_ci "\"arg1\":" "\"val2\"," 41d4afb5ceSopenharmony_ci "\"arg2\":" "1420887242594," 42d4afb5ceSopenharmony_ci "\"priority\":" "3," 43d4afb5ceSopenharmony_ci "\"ssid\":" "\"\\\"nw1\\\"\"" 44d4afb5ceSopenharmony_ci "}" 45d4afb5ceSopenharmony_ci "]" 46d4afb5ceSopenharmony_ci"}"; 47d4afb5ceSopenharmony_ci 48d4afb5ceSopenharmony_cistatic const char * const test2_json_expected = 49d4afb5ceSopenharmony_ci "{\"config\":[{\"creds\":{\"key1\":\"\\u0022xxxxxxxxx\\u0022\"}," 50d4afb5ceSopenharmony_ci "\"arg1\":\"val1\",\"ssid\":\"\\u0022nw2\\u0022\"," 51d4afb5ceSopenharmony_ci "\"frequency\":0,\"arg2\":0,\"priority\":1}," 52d4afb5ceSopenharmony_ci "{\"creds\":{\"key1\":\"\\u0022xxxxxxxxxxxxx\\u0022\"}," 53d4afb5ceSopenharmony_ci "\"arg1\":\"val2\",\"ssid\":\"\\u0022nw1\\u0022\"," 54d4afb5ceSopenharmony_ci "\"frequency\":11,\"arg2\":1420887242594,\"priority\":3}]}" 55d4afb5ceSopenharmony_ci; 56d4afb5ceSopenharmony_ci 57d4afb5ceSopenharmony_ci/* 58d4afb5ceSopenharmony_ci * level 3: Credentials object 59d4afb5ceSopenharmony_ci */ 60d4afb5ceSopenharmony_ci 61d4afb5ceSopenharmony_citypedef struct t2_cred { 62d4afb5ceSopenharmony_ci const char *key1; 63d4afb5ceSopenharmony_ci const char *key2; 64d4afb5ceSopenharmony_ci} t2_cred_t; 65d4afb5ceSopenharmony_ci 66d4afb5ceSopenharmony_cistatic const lws_struct_map_t lsm_t2_cred[] = { 67d4afb5ceSopenharmony_ci LSM_STRING_PTR (t2_cred_t, key1, "key1"), 68d4afb5ceSopenharmony_ci LSM_STRING_PTR (t2_cred_t, key2, "key2"), 69d4afb5ceSopenharmony_ci}; 70d4afb5ceSopenharmony_ci 71d4afb5ceSopenharmony_ci/* 72d4afb5ceSopenharmony_ci * level 2: Configuration object, containing a child credentials object 73d4afb5ceSopenharmony_ci */ 74d4afb5ceSopenharmony_ci 75d4afb5ceSopenharmony_citypedef struct t2_config { 76d4afb5ceSopenharmony_ci lws_dll2_t list; 77d4afb5ceSopenharmony_ci t2_cred_t *creds; 78d4afb5ceSopenharmony_ci const char *id1; 79d4afb5ceSopenharmony_ci const char *arg1; 80d4afb5ceSopenharmony_ci const char *ssid; 81d4afb5ceSopenharmony_ci unsigned int frequency; 82d4afb5ceSopenharmony_ci unsigned long long arg2; 83d4afb5ceSopenharmony_ci unsigned int priority; 84d4afb5ceSopenharmony_ci} t2_config_t; 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_cistatic const lws_struct_map_t lsm_t2_config[] = { 87d4afb5ceSopenharmony_ci LSM_CHILD_PTR (t2_config_t, 88d4afb5ceSopenharmony_ci creds, /* the child pointer member */ 89d4afb5ceSopenharmony_ci t2_cred_t, /* the child type */ 90d4afb5ceSopenharmony_ci NULL, lsm_t2_cred, /* map object for item type */ 91d4afb5ceSopenharmony_ci "creds"), /* outer json object name */ 92d4afb5ceSopenharmony_ci LSM_STRING_PTR (t2_config_t, id1, "id1"), 93d4afb5ceSopenharmony_ci LSM_STRING_PTR (t2_config_t, arg1, "arg1"), 94d4afb5ceSopenharmony_ci LSM_STRING_PTR (t2_config_t, ssid, "ssid"), 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_ci LSM_UNSIGNED (t2_config_t, frequency, "frequency"), 97d4afb5ceSopenharmony_ci LSM_UNSIGNED (t2_config_t, arg2, "arg2"), 98d4afb5ceSopenharmony_ci LSM_UNSIGNED (t2_config_t, priority, "priority"), 99d4afb5ceSopenharmony_ci}; 100d4afb5ceSopenharmony_ci 101d4afb5ceSopenharmony_ci/* 102d4afb5ceSopenharmony_ci * level 1: list-of-configurations object 103d4afb5ceSopenharmony_ci */ 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_citypedef struct t2_configs { 106d4afb5ceSopenharmony_ci lws_dll2_owner_t configs; 107d4afb5ceSopenharmony_ci} t2_configs_t; 108d4afb5ceSopenharmony_ci 109d4afb5ceSopenharmony_cistatic const lws_struct_map_t lsm_t2_configs[] = { 110d4afb5ceSopenharmony_ci LSM_LIST (t2_configs_t, configs, /* the list owner type/member */ 111d4afb5ceSopenharmony_ci t2_config_t, list, /* the list item type/member */ 112d4afb5ceSopenharmony_ci NULL, lsm_t2_config, /* map object for item type */ 113d4afb5ceSopenharmony_ci "config"), /* outer json object name */ 114d4afb5ceSopenharmony_ci}; 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci/* 117d4afb5ceSopenharmony_ci * For parsing, this lists the kind of object we expect to parse so the struct 118d4afb5ceSopenharmony_ci * can be allocated polymorphically. 119d4afb5ceSopenharmony_ci * 120d4afb5ceSopenharmony_ci * Lws uses an explicit "schema" member so the type is known unambiguously. If 121d4afb5ceSopenharmony_ci * in the incoming JSON the first member is not "schema", it will scan the 122d4afb5ceSopenharmony_ci * maps listed here and instantiate the first object that has a member of that 123d4afb5ceSopenharmony_ci * name. 124d4afb5ceSopenharmony_ci */ 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_cistatic const lws_struct_map_t lsm_schema[] = { 127d4afb5ceSopenharmony_ci LSM_SCHEMA (t2_configs_t, NULL, lsm_t2_configs, "t2"), 128d4afb5ceSopenharmony_ci /* other schemata that might need parsing... */ 129d4afb5ceSopenharmony_ci}; 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_ci 132d4afb5ceSopenharmony_ci 133d4afb5ceSopenharmony_cistatic int 134d4afb5ceSopenharmony_cit2_config_dump(struct lws_dll2 *d, void *user) 135d4afb5ceSopenharmony_ci{ 136d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_NO_LOGS) 137d4afb5ceSopenharmony_ci t2_config_t *c = lws_container_of(d, t2_config_t, list); 138d4afb5ceSopenharmony_ci 139d4afb5ceSopenharmony_ci lwsl_notice("%s: id1 '%s'\n", __func__, c->id1); 140d4afb5ceSopenharmony_ci lwsl_notice("%s: arg1 '%s'\n", __func__, c->arg1); 141d4afb5ceSopenharmony_ci lwsl_notice("%s: ssid '%s'\n", __func__, c->ssid); 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_ci lwsl_notice("%s: freq %d\n", __func__, c->frequency); 144d4afb5ceSopenharmony_ci lwsl_notice("%s: arg2 %llu\n", __func__, c->arg2); 145d4afb5ceSopenharmony_ci lwsl_notice("%s: priority %d\n", __func__, c->priority); 146d4afb5ceSopenharmony_ci 147d4afb5ceSopenharmony_ci lwsl_notice("%s: key1: %s, key2: %s\n", __func__, 148d4afb5ceSopenharmony_ci c->creds->key1, c->creds->key2); 149d4afb5ceSopenharmony_ci#endif 150d4afb5ceSopenharmony_ci 151d4afb5ceSopenharmony_ci return 0; 152d4afb5ceSopenharmony_ci} 153d4afb5ceSopenharmony_ci 154d4afb5ceSopenharmony_cistatic int 155d4afb5ceSopenharmony_cit2_configs_dump(t2_configs_t *t2cs) 156d4afb5ceSopenharmony_ci{ 157d4afb5ceSopenharmony_ci lwsl_notice("%s: number of configs: %d\n", __func__, 158d4afb5ceSopenharmony_ci t2cs->configs.count); 159d4afb5ceSopenharmony_ci 160d4afb5ceSopenharmony_ci lws_dll2_foreach_safe(&t2cs->configs, NULL, t2_config_dump); 161d4afb5ceSopenharmony_ci 162d4afb5ceSopenharmony_ci return 0; 163d4afb5ceSopenharmony_ci} 164d4afb5ceSopenharmony_ci 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_ciint 167d4afb5ceSopenharmony_citest2(void) 168d4afb5ceSopenharmony_ci{ 169d4afb5ceSopenharmony_ci lws_struct_serialize_t *ser; 170d4afb5ceSopenharmony_ci struct lejp_ctx ctx; 171d4afb5ceSopenharmony_ci lws_struct_args_t a; 172d4afb5ceSopenharmony_ci t2_configs_t *top; 173d4afb5ceSopenharmony_ci uint8_t buf[4096]; 174d4afb5ceSopenharmony_ci size_t written; 175d4afb5ceSopenharmony_ci int n, bad = 1; 176d4afb5ceSopenharmony_ci 177d4afb5ceSopenharmony_ci lwsl_notice("%s: start \n", __func__); 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci memset(&a, 0, sizeof(a)); 180d4afb5ceSopenharmony_ci a.map_st[0] = lsm_schema; 181d4afb5ceSopenharmony_ci a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema); 182d4afb5ceSopenharmony_ci a.ac_block_size = 512; 183d4afb5ceSopenharmony_ci lws_struct_json_init_parse(&ctx, NULL, &a); 184d4afb5ceSopenharmony_ci 185d4afb5ceSopenharmony_ci n = lejp_parse(&ctx, (uint8_t *)test2_json, (int)strlen(test2_json)); 186d4afb5ceSopenharmony_ci lwsl_notice("%s: lejp_parse %d\n", __func__, n); 187d4afb5ceSopenharmony_ci if (n < 0) { 188d4afb5ceSopenharmony_ci lwsl_err("%s: test2 JSON decode failed '%s'\n", 189d4afb5ceSopenharmony_ci __func__, lejp_error_to_string(n)); 190d4afb5ceSopenharmony_ci goto bail; 191d4afb5ceSopenharmony_ci } 192d4afb5ceSopenharmony_ci lwsac_info(a.ac); 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci top = (t2_configs_t *)a.dest; /* the top level object */ 195d4afb5ceSopenharmony_ci 196d4afb5ceSopenharmony_ci if (!top) { 197d4afb5ceSopenharmony_ci lwsl_err("%s: no top level object\n", __func__); 198d4afb5ceSopenharmony_ci goto bail; 199d4afb5ceSopenharmony_ci } 200d4afb5ceSopenharmony_ci t2_configs_dump(top); 201d4afb5ceSopenharmony_ci 202d4afb5ceSopenharmony_ci /* 2. Let's reserialize the top level object and see what comes out */ 203d4afb5ceSopenharmony_ci 204d4afb5ceSopenharmony_ci ser = lws_struct_json_serialize_create(&lsm_schema[0], 1, 205d4afb5ceSopenharmony_ci LSSERJ_FLAG_OMIT_SCHEMA, top); 206d4afb5ceSopenharmony_ci if (!ser) { 207d4afb5ceSopenharmony_ci lwsl_err("%s: unable to init serialization\n", __func__); 208d4afb5ceSopenharmony_ci goto bail; 209d4afb5ceSopenharmony_ci } 210d4afb5ceSopenharmony_ci 211d4afb5ceSopenharmony_ci do { 212d4afb5ceSopenharmony_ci n = (int)lws_struct_json_serialize(ser, buf, sizeof(buf), &written); 213d4afb5ceSopenharmony_ci switch (n) { 214d4afb5ceSopenharmony_ci case LSJS_RESULT_FINISH: 215d4afb5ceSopenharmony_ci puts((const char *)buf); 216d4afb5ceSopenharmony_ci break; 217d4afb5ceSopenharmony_ci case LSJS_RESULT_CONTINUE: 218d4afb5ceSopenharmony_ci case LSJS_RESULT_ERROR: 219d4afb5ceSopenharmony_ci goto bail; 220d4afb5ceSopenharmony_ci } 221d4afb5ceSopenharmony_ci } while (n == LSJS_RESULT_CONTINUE); 222d4afb5ceSopenharmony_ci 223d4afb5ceSopenharmony_ci if (strcmp(test2_json_expected, (char *)buf)) { 224d4afb5ceSopenharmony_ci lwsl_err("%s: expected %s\n", __func__, test2_json_expected); 225d4afb5ceSopenharmony_ci goto bail; 226d4afb5ceSopenharmony_ci } 227d4afb5ceSopenharmony_ci 228d4afb5ceSopenharmony_ci lws_struct_json_serialize_destroy(&ser); 229d4afb5ceSopenharmony_ci 230d4afb5ceSopenharmony_ci bad = 0; 231d4afb5ceSopenharmony_ci 232d4afb5ceSopenharmony_cibail: 233d4afb5ceSopenharmony_ci lwsac_free(&a.ac); 234d4afb5ceSopenharmony_ci 235d4afb5ceSopenharmony_ci return bad; 236d4afb5ceSopenharmony_ci} 237