From: Guus Sliepen Date: Tue, 9 Oct 2018 14:06:50 +0000 (+0200) Subject: Add an example using curses to monitor the state of MeshLink. X-Git-Url: http://git.meshlink.io/?p=meshlink;a=commitdiff_plain;h=6136f2677f8c4967b9b30ebb372dd8c3656c2cf9 Add an example using curses to monitor the state of MeshLink. --- diff --git a/examples/Makefile.am b/examples/Makefile.am index 4d363657..9ce812d2 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = meshlinkapp chat chatpp manynodes channels +noinst_PROGRAMS = meshlinkapp chat chatpp manynodes channels monitor AM_CPPFLAGS = $(PTHREAD_CFLAGS) -I${top_srcdir}/src -iquote. -Wall AM_LDFLAGS = $(PTHREAD_LIBS) @@ -17,3 +17,6 @@ manynodes_LDADD = ${top_builddir}/src/libmeshlink.la channels_SOURCES = channels.c channels_LDADD = ${top_builddir}/src/libmeshlink.la + +monitor_SOURCES = monitor.c +monitor_LDADD = ${top_builddir}/src/libmeshlink.la -lcurses -lm diff --git a/examples/monitor.c b/examples/monitor.c new file mode 100644 index 00000000..ef010af6 --- /dev/null +++ b/examples/monitor.c @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../src/meshlink.h" +#include "../src/devtools.h" + +static WINDOW *topwin; +static WINDOW *nodewin; +static WINDOW *splitwin; +static WINDOW *logwin; +static WINDOW *statuswin; +static float splitpoint = 0.5; + +static meshlink_handle_t *mesh; +static meshlink_node_t **nodes; +static size_t nnodes; + +static void log_message(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text) { + (void)mesh; + + wattron(logwin, COLOR_PAIR(level)); + wprintw(logwin, "%s\n", text); + wattroff(logwin, COLOR_PAIR(level)); + wrefresh(logwin); +} + +static void do_resize() { + const int nodelines = lrintf((LINES - 3) * splitpoint); + const int loglines = (LINES - 3) - nodelines; + assert(nodelines > 1); + assert(loglines > 1); + assert(COLS > 1); + + mvwin(topwin, 0, 0); + wresize(topwin, 1, COLS); + + mvwin(nodewin, 1, 0); + wresize(nodewin, nodelines, COLS); + + mvwin(splitwin, 1 + nodelines, 0); + wresize(splitwin, 1, COLS); + + mvwin(logwin, 2 + nodelines, 0); + wresize(logwin, loglines, COLS); + + mvwin(statuswin, LINES - 1, 0); + wresize(statuswin, 1, COLS); +} + + +static void do_redraw_nodes() { + werase(nodewin); + nodes = meshlink_get_all_nodes(mesh, nodes, &nnodes); + + for(size_t i = 0; i < nnodes; i++) { + devtool_node_status_t status; + devtool_get_node_status(mesh, nodes[i], &status); + char host[NI_MAXHOST] = ""; + char serv[NI_MAXSERV] = ""; + getnameinfo(&status.address, sizeof status.address, host, sizeof host, serv, sizeof serv, NI_NUMERICHOST | NI_NUMERICSERV); + const char *desc; + + switch(status.udp_status) { + case DEVTOOL_UDP_FAILED: + desc = "UDP failed"; + break; + + case DEVTOOL_UDP_IMPOSSIBLE: + desc = "unreachable"; + break; + + case DEVTOOL_UDP_TRYING: + desc = "probing"; + break; + + case DEVTOOL_UDP_WORKING: + desc = "UDP working"; + break; + + case DEVTOOL_UDP_UNKNOWN: + default: + desc = "unknown"; + break; + }; + + if(!strcmp(nodes[i]->name, mesh->name)) { + desc = "myself"; + } + + char mtustate = ' '; + + if(status.minmtu) { + if(status.minmtu != status.maxmtu) { + mtustate = '~'; + } + }; + + mvwprintw(nodewin, i, 0, "%-16s %-12s %-32s %5s %c%5d", nodes[i]->name, desc, host, serv, mtustate, status.maxmtu); + } + + wnoutrefresh(nodewin); +} + +static void do_redraw() { + // Draw top line + werase(topwin); + mvwprintw(topwin, 0, 0, "%-16s %-12s %-32s %5s %6s", "Node:", "Status:", "UDP address:", "Port:", "MTU:"); + wnoutrefresh(topwin); + + // Draw middle line + werase(splitwin); + mvwprintw(splitwin, 0, 0, "Log output:"); + wnoutrefresh(splitwin); + + // Draw bottom line + werase(statuswin); + mvwprintw(statuswin, 0, 0, "Status bar"); + wnoutrefresh(statuswin); + + wnoutrefresh(logwin); + + do_redraw_nodes(); +} + +static void node_status(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable) { + (void)mesh; + (void)node; + (void)reachable; + do_redraw_nodes(); + doupdate(); +} + +int main(int argc, char *argv[]) { + const char *confbase = ".monitor"; + const char *id = NULL; + char buf[1024]; + + if(argc > 1) { + confbase = argv[1]; + } + + if(argc > 2) { + id = argv[2]; + } + + initscr(); + start_color(); + curs_set(false); + noecho(); + + topwin = newwin(1, COLS, 0, 0); + nodewin = newwin(1, COLS, 1, 0); + splitwin = newwin(1, COLS, 2, 0); + logwin = newwin(1, COLS, 3, 0); + statuswin = newwin(1, COLS, 4, 0); + + leaveok(topwin, true); + leaveok(nodewin, true); + leaveok(splitwin, true); + leaveok(logwin, true); + leaveok(statuswin, true); + + wattrset(topwin, A_REVERSE); + wattrset(splitwin, A_REVERSE); + wattrset(statuswin, A_REVERSE); + + wbkgdset(topwin, ' ' | A_REVERSE); + wbkgdset(splitwin, ' ' | A_REVERSE); + wbkgdset(statuswin, ' ' | A_REVERSE); + + init_pair(1, COLOR_GREEN, -1); + init_pair(2, COLOR_YELLOW, -1); + init_pair(3, COLOR_RED, -1); + init_pair(4, COLOR_RED, -1); + + scrollok(logwin, true); + + do_resize(); + do_redraw(); + doupdate(); + + meshlink_set_log_cb(NULL, MESHLINK_DEBUG, log_message); + + mesh = meshlink_open(confbase, id, "monitor", DEV_CLASS_STATIONARY); + + if(!mesh) { + endwin(); + fprintf(stderr, "Could not open MeshLink: %s\n", meshlink_strerror(meshlink_errno)); + return 1; + } + + meshlink_set_log_cb(mesh, MESHLINK_DEBUG, log_message); + meshlink_set_node_status_cb(mesh, node_status); + + if(!meshlink_start(mesh)) { + endwin(); + fprintf(stderr, "Could not start MeshLink: %s\n", meshlink_strerror(meshlink_errno)); + return 1; + } + + bool running = true; + timeout(500); + wtimeout(topwin, 500); + + do_redraw(); + doupdate(); + + while(running) { + int key = wgetch(topwin); + + switch(key) { + case 'q': + case 27: + case KEY_BREAK: + running = false; + break; + + case KEY_RESIZE: + do_resize(); + break; + + case 'r': + case KEY_REFRESH: + clearok(topwin, true); + clearok(nodewin, true); + clearok(splitwin, true); + clearok(logwin, true); + clearok(statuswin, true); + break; + } + + do_redraw(); + doupdate(); + } + + meshlink_stop(mesh); + meshlink_close(mesh); + + endwin(); + + return 0; +}