mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-03 18:57:06 +01:00
lighting-cli: do incremental parsing.
Far less hacky, and a little faster: real 0m0.168s user 0m0.135s sys 0m0.033s Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
2ff9e42b33
commit
aa34ad30d9
1 changed files with 33 additions and 35 deletions
|
@ -52,16 +52,16 @@ int main(int argc, char *argv[])
|
||||||
int fd, i, off;
|
int fd, i, off;
|
||||||
const char *method;
|
const char *method;
|
||||||
char *cmd, *resp, *idstr, *rpc_filename;
|
char *cmd, *resp, *idstr, *rpc_filename;
|
||||||
char *result_end;
|
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
jsmntok_t *toks;
|
jsmntok_t *toks;
|
||||||
const jsmntok_t *result, *error, *id;
|
const jsmntok_t *result, *error, *id;
|
||||||
char *lightning_dir;
|
char *lightning_dir;
|
||||||
const tal_t *ctx = tal(NULL, char);
|
const tal_t *ctx = tal(NULL, char);
|
||||||
size_t num_opens, num_closes;
|
jsmn_parser parser;
|
||||||
bool valid;
|
jsmnerr_t parserr;
|
||||||
|
|
||||||
err_set_progname(argv[0]);
|
err_set_progname(argv[0]);
|
||||||
|
jsmn_init(&parser);
|
||||||
|
|
||||||
opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn);
|
opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn);
|
||||||
configdir_register_opts(ctx, &lightning_dir, &rpc_filename);
|
configdir_register_opts(ctx, &lightning_dir, &rpc_filename);
|
||||||
|
@ -117,43 +117,41 @@ int main(int argc, char *argv[])
|
||||||
if (!write_all(fd, cmd, strlen(cmd)))
|
if (!write_all(fd, cmd, strlen(cmd)))
|
||||||
err(ERROR_TALKING_TO_LIGHTNINGD, "Writing command");
|
err(ERROR_TALKING_TO_LIGHTNINGD, "Writing command");
|
||||||
|
|
||||||
resp = tal_arr(cmd, char, 100);
|
/* Start with 1000 characters, 100 tokens. */
|
||||||
|
resp = tal_arr(ctx, char, 1000);
|
||||||
|
toks = tal_arr(ctx, jsmntok_t, 100);
|
||||||
off = 0;
|
off = 0;
|
||||||
num_opens = num_closes = 0;
|
parserr = 0;
|
||||||
while ((i = read(fd, resp + off, tal_count(resp) - 1 - off)) > 0) {
|
while (parserr <= 0) {
|
||||||
resp[off + i] = '\0';
|
/* Read more if parser says, or we have 0 tokens. */
|
||||||
num_opens += strcount(resp + off, "{");
|
if (parserr == 0 || parserr == JSMN_ERROR_PART) {
|
||||||
num_closes += strcount(resp + off, "}");
|
i = read(fd, resp + off, tal_count(resp) - 1 - off);
|
||||||
|
if (i <= 0)
|
||||||
|
err(ERROR_TALKING_TO_LIGHTNINGD,
|
||||||
|
"reading response");
|
||||||
|
off += i;
|
||||||
|
/* NUL terminate */
|
||||||
|
resp[off] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
off += i;
|
/* (Continue) parsing */
|
||||||
if (off == tal_count(resp) - 1)
|
parserr = jsmn_parse(&parser, resp, off, toks, tal_count(toks));
|
||||||
tal_resize(&resp, tal_count(resp) * 2);
|
|
||||||
|
|
||||||
/* parsing huge outputs is slow: do quick check first. */
|
switch (parserr) {
|
||||||
if (num_opens == num_closes)
|
case JSMN_ERROR_INVAL:
|
||||||
|
errx(ERROR_TALKING_TO_LIGHTNINGD,
|
||||||
|
"Malformed response '%s'", resp);
|
||||||
|
case JSMN_ERROR_NOMEM:
|
||||||
|
/* Need more tokens, double it */
|
||||||
|
tal_resize(&toks, tal_count(toks) * 2);
|
||||||
break;
|
break;
|
||||||
|
case JSMN_ERROR_PART:
|
||||||
|
/* Need more data: make room if necessary */
|
||||||
|
if (off == tal_count(resp) - 1)
|
||||||
|
tal_resize(&resp, tal_count(resp) * 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (i < 0)
|
|
||||||
err(ERROR_TALKING_TO_LIGHTNINGD, "reading response");
|
|
||||||
|
|
||||||
resp[off] = '\0';
|
|
||||||
|
|
||||||
/* Parsing huge results is too slow, so hack fastpath common case */
|
|
||||||
result_end = tal_fmt(ctx, ", \"error\" : null, \"id\" : \"%s\" }\n",
|
|
||||||
idstr);
|
|
||||||
|
|
||||||
if (strstarts(resp, "{ \"result\" : ") && strends(resp, result_end)) {
|
|
||||||
/* Result is OK, so dump it */
|
|
||||||
resp += strlen("{ \"result\" : ");
|
|
||||||
printf("%.*s\n", (int)(strlen(resp) - strlen(result_end)), resp);
|
|
||||||
tal_free(ctx);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
toks = json_parse_input(resp, off, &valid);
|
|
||||||
if (!toks || !valid)
|
|
||||||
errx(ERROR_TALKING_TO_LIGHTNINGD,
|
|
||||||
"Malformed response '%s'", resp);
|
|
||||||
|
|
||||||
if (toks->type != JSMN_OBJECT)
|
if (toks->type != JSMN_OBJECT)
|
||||||
errx(ERROR_TALKING_TO_LIGHTNINGD,
|
errx(ERROR_TALKING_TO_LIGHTNINGD,
|
||||||
|
|
Loading…
Add table
Reference in a new issue