lnvis

nanovg lightning network visualizer
git clone git://jb55.com/lnvis
Log | Files | Refs | README | LICENSE

commit 2c8b700a9aa63cdb35c0ec3e2c8d6d5de8500532
parent fcc6c15637cb7807516ebd8fa2830ef6fadbebf9
Author: William Casarin <jb55@jb55.com>
Date:   Sat, 11 Aug 2018 15:09:35 -0700

node parsing working

Diffstat:
MMakefile | 2+-
Mjson.c | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mjson.h | 11+++++++----
Mln.c | 2+-
Mln.h | 3++-
Mmain.c | 38++++++++++++++++++++++++++++++++------
6 files changed, 191 insertions(+), 28 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ BIN = lnvis PREFIX ?= /usr/local -CFLAGS = -Ideps -ggdb -O2 -Wall -Wextra -Werror -std=c99 -DJSMN_PARENT_LINKS +CFLAGS = -Ideps -ggdb -O2 -Wall -Wextra -std=c99 -DJSMN_PARENT_LINKS LDFLAGS = -lglfw -lGL diff --git a/json.c b/json.c @@ -4,17 +4,29 @@ #include <stdio.h> #include <assert.h> #include <stdio.h> +#include <ctype.h> #include <stdlib.h> #include <string.h> #define ERROR_READING_CHANNELS -2 #define ERROR_ALLOCATING_CHANNELS -3 -struct parser { +#define min(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +struct channel_parser { const char *field; enum channel_parsing_state state; }; + +struct node_parser { + const char *field; + enum node_parsing_state state; +}; + /* "source": "02fc7ef232bd958209a2180fb18844388babc48a81d31434e343ecc4d7dd1a9186", */ /* "destination": "03b7ca940bc33b882dc1f1bee353a6cf205b1a7472d8ae24d45370a8f510c27d23", */ /* "short_channel_id": "505273:1478:0", */ @@ -26,7 +38,7 @@ struct parser { /* "base_fee_millisatoshi": 1, */ /* "fee_per_millionth": 1, */ /* "delay": 14 */ -static const struct parser channel_parsers[] = { +static const struct channel_parser channel_parsers[] = { { "short_channel_id", PARSING_CHAN_SHORTID }, { "public", PARSING_CHAN_PUBLIC }, { "satoshis", PARSING_CHAN_SATOSHIS }, @@ -38,6 +50,22 @@ static const struct parser channel_parsers[] = { { "delay", PARSING_CHAN_DELAY }, }; +/* "nodeid": "03a8334aba5660e241468e2f0deb2526bfd50d0e3fe808d882913e39094dc1a028", */ +/* "alias": "cosmicApotheosis", */ +/* "color": "33cccc", */ +/* "last_timestamp": 1533693585, */ +/* "global_features": "", */ +/* "addresses": [ */ +/* { "type": "ipv4", */ +/* "address": "138.229.205.237", */ +/* "port": 9735 */ +/* }] */ +static const struct node_parser node_parsers[] = { + { "alias", PARSING_NODE_ALIAS }, + { "color", PARSING_NODE_COLOR }, + { "addresses", PARSING_NODE_ADDRESSES }, +}; + #define MKTMPBUF \ char buf[toklen + 1]; \ buf[toklen] = '\0'; \ @@ -141,36 +169,141 @@ int parse_json(FILE *fd, jsmntok_t **ptoks, int *ntoks, char **pbuffer) { } +static inline u8 hexdigit(char hex) { + return (hex <= '9') ? hex - '0' : toupper(hex) - 'A' + 10 ; +} + + +static void parse_color(int toklen, const char *tokstr, union color *color) { + color->a = 1.0f; + + if (toklen != 6) + goto colorerr; + + for (int i = 0; i < 3; i++) { + u8 c1 = tokstr[i]; + u8 c2 = tokstr[i+1]; + + if (!isxdigit(c1) || !isxdigit(c2)) + goto colorerr; + + u8 val = hexdigit(c1) << 4 | hexdigit(c2); + color->rgba[i] = val / 255.0f; + } + + return; +colorerr: + color->r = 0.0f; + color->g = 0.0f; + color->b = 0.0f; + return; +} + int parse_clightning_nodes(FILE *fd, int *node_count, struct node **pnodes) { - (void)fd; - (void)node_count; - (void)pnodes; + struct node *node = NULL, *nodes; + char *buffer, *tokstr; + void *res; + jsmntok_t *toks; + jsmntok_t *tok; + int i, ntoks = 0, toklen = 0, objs = 0; + int nodecap = 4096; + enum node_parsing_state state = PARSING_NODE_TOKEN; + + *node_count = 0; + + nodes = calloc(nodecap, sizeof(struct node)); + + int rez = parse_json(fd, &toks, &ntoks, &buffer); + if (rez < 0) + return rez; + + for (i = 0; i < ntoks; i++) { + tok = &toks[i]; + + if (tok->type == JSMN_ARRAY) + continue; + + if (tok->type == JSMN_OBJECT) { + if (state == PARSING_NODE_ADDRESSES) + continue; + + if (++objs > 2) + (*node_count)++; + + continue; + } + + toklen = tok->end - tok->start; + tokstr = &buffer[tok->start]; + + node = &nodes[*node_count]; + + // allocate more channels if needed + if (*node_count > nodecap) { + nodecap *= 2; + res = realloc(nodes, nodecap * sizeof(struct channel)); + if (res == NULL) { + free(nodes); + return ERROR_ALLOCATING_CHANNELS; + } + nodes = res; + } + + switch (state) { + case PARSING_NODE_ALIAS: + strncpy(node->alias, tokstr, min(toklen, MAX_ALIAS_SIZE)); + state = PARSING_NODE_TOKEN; + break; + + case PARSING_NODE_COLOR: + parse_color(toklen, tokstr, &node->color); + state = PARSING_NODE_TOKEN; + break; + + case PARSING_NODE_ADDRESSES: + // TODO: parse addresses + state = PARSING_NODE_TOKEN; + break; + + case PARSING_NODE_TOKEN: + for (size_t i = 0; i < ARRAY_SIZE(node_parsers); i++) { + if (tokeq(toklen, tokstr, + node_parsers[i].field)) { + state = node_parsers[i].state; + continue; + } + } + break; + } + + } + + *pnodes = nodes; + *node_count = *node_count + 1; + return 0; } -int parse_clightning_channels(FILE *fd, int *nchannels, struct channel **pchannels) +int parse_clightning_channels(FILE *fd, int *nchans, struct channel **pchannels) { char *buffer; void *res; struct channel *chan = NULL, *channels; - int nchans = 0; int chancap = 4096; jsmntok_t *toks; jsmntok_t *tok; char *tokstr; - int ntoks; - int toklen; + int ntoks = 0, toklen = 0, objs = 0; enum channel_parsing_state state = PARSING_CHAN_TOKEN; + int rez = parse_json(fd, &toks, &ntoks, &buffer); if (rez < 0) return rez; channels = calloc(chancap, sizeof(struct channel)); - int objs = 0; - // parse tokens for (int i = 0; i < ntoks; ++i) { tok = &toks[i]; @@ -180,7 +313,7 @@ int parse_clightning_channels(FILE *fd, int *nchannels, struct channel **pchanne if (tok->type == JSMN_OBJECT) { if (++objs > 2) - nchans++; + (*nchans)++; continue; } @@ -189,7 +322,7 @@ int parse_clightning_channels(FILE *fd, int *nchannels, struct channel **pchanne tokstr = &buffer[tok->start]; // allocate more channels if needed - if (nchans > chancap) { + if (*nchans > chancap) { chancap *= 2; res = realloc(channels, chancap * sizeof(struct channel)); if (res == NULL) { @@ -199,7 +332,7 @@ int parse_clightning_channels(FILE *fd, int *nchannels, struct channel **pchanne channels = res; } - chan = &channels[nchans]; + chan = &channels[*nchans]; // TODO: lookup node id, assign nodes switch (state) { @@ -263,7 +396,7 @@ int parse_clightning_channels(FILE *fd, int *nchannels, struct channel **pchanne } *pchannels = channels; - *nchannels = nchans + 1; + *nchans = *nchans + 1; free(buffer); free(toks); diff --git a/json.h b/json.h @@ -6,8 +6,11 @@ #include <stdio.h> #include "ln.h" -enum nodes_parsing_state { - PARSING_NODE_TOKEN +enum node_parsing_state { + PARSING_NODE_TOKEN, + PARSING_NODE_ALIAS, + PARSING_NODE_COLOR, + PARSING_NODE_ADDRESSES, }; enum channel_parsing_state { @@ -23,7 +26,7 @@ enum channel_parsing_state { PARSING_CHAN_DELAY, }; -int parse_clightning_channels(FILE *fd, int *nchannels, - struct channel **channels); +int parse_clightning_nodes(FILE *fd, int *node_count, struct node **nodes); +int parse_clightning_channels(FILE *fd, int *nchannels, struct channel **channels); #endif /* LNVIS_JSON_H */ diff --git a/ln.c b/ln.c @@ -37,7 +37,7 @@ void random_network(int ww, int wh, int max_per_node, int num_nodes, struct ln * for (i = 0; i < num_nodes; ++i) { n = &ln->nodes[i]; - n->alias = "test"; + strcpy(n->alias, "test"); n->color.r = rand_0to1(); n->color.g = rand_0to1(); n->color.b = rand_0to1(); diff --git a/ln.h b/ln.h @@ -6,6 +6,7 @@ #include "defs.h" #define CELL_MAX_ELEMS 32 +#define MAX_ALIAS_SIZE 32 union color { float rgba[4]; @@ -16,7 +17,7 @@ union color { }; struct node { - const char *alias; + char alias[MAX_ALIAS_SIZE]; const char *id; // pubkey union color color; diff --git a/main.c b/main.c @@ -101,6 +101,14 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod } } +static void print_node(struct node *node) +{ + printf("node %s #%02X%02X%02X\n", node->alias, + (int)node->color.r * 255, + (int)node->color.g * 255, + (int)node->color.b * 255); +} + static void print_channel(struct channel *chan) { printf("chan shortid=%u:%u:%hu public=%d sats=%"PRIu64" active=%d " @@ -121,22 +129,40 @@ static void print_channel(struct channel *chan) void test_read_json() { - FILE *f = fopen("clightning-channels.json", "r"); + FILE *channels_fd = fopen("clightning-channels.json", "r"); + FILE *nodes_fd = fopen("clightning-nodes.json", "r"); + int nchans = 0; + int node_count = 0; + int i; struct channel *channels; - int res = parse_clightning_channels(f, &nchans, &channels); + struct node *nodes; + + int res = parse_clightning_nodes(nodes_fd, &node_count, &nodes); + fclose(nodes_fd); + + if (res != 0) { + printf("parse_clightning_nodes res %d\n", res); + exit(1); + } + + res = parse_clightning_channels(channels_fd, &nchans, &channels); + fclose(channels_fd); if (res != 0) { - printf("test_read_json res %d\n", res); + printf("parse_clightning_channels res %d\n", res); exit(1); } - for (int i = 0; i < nchans; i++) + for (i = 0; i < nchans; i++) print_channel(&channels[i]); - printf("%d channels\n", nchans); + for (i = 0; i < node_count; i++) + print_node(&nodes[i]); + + printf("%d nodes, %d channels\n", node_count, nchans); + - fclose(f); exit(0); }