From ae4b5a79e5863ee6440b2070361f3229285a9380 Mon Sep 17 00:00:00 2001 From: Jonas Suhr Christensen Date: Tue, 22 May 2012 12:09:08 +0200 Subject: Working cli client. --- TODO | 4 + src/Makefile.am | 1 + src/messageparser.cc | 80 +++++++++++----- src/messageparser.h | 1 + src/muniacli.cc | 257 ++++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 306 insertions(+), 37 deletions(-) diff --git a/TODO b/TODO index fb95122..e818911 100644 --- a/TODO +++ b/TODO @@ -1,2 +1,6 @@ +Client observer lists to set instead of lists. + Add depth to observe and make default client connection "observe 0 2", ie. observe root node with Projects visible. + +Handling of invalid values in incoming messages (default values?) \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 0e59695..c256f54 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,6 +28,7 @@ muniacli_LDADD = $(LIBWEBSOCKETS_LIBS) muniacli_CXXFLAGS = $(LIBWEBSOCKETS_CFLAGS) muniacli_SOURCES = \ + messageparser.cc \ muniacli.cc EXTRA_DIST = \ diff --git a/src/messageparser.cc b/src/messageparser.cc index 62923be..bfaa033 100644 --- a/src/messageparser.cc +++ b/src/messageparser.cc @@ -98,75 +98,95 @@ inline static void parse_into_msg_tokens(std::string& data, } inline static void create_msg_list(MsgTokensList& msgTokensList, - MessageList& msgList) { + MessageList& msgList, + bool clientmode) { + int origin = 0; + if(clientmode) { + origin = 1; + } + MsgTokensList::iterator it_msg; for(it_msg = msgTokensList.begin(); it_msg != msgTokensList.end(); it_msg++) { TokenVector t = *it_msg; //malformed msg - if(t.size() < 1) continue; + if(t.size() < origin+1) continue; message_t m; - if(t[0] == "observe") m.cmd = cmd::observe; - else if(t[0] == "unobserve") m.cmd = cmd::unobserve; - else if(t[0] == "create") m.cmd = cmd::create; - else if(t[0] == "remove") m.cmd = cmd::remove; - else if(t[0] == "move") m.cmd = cmd::move; - else if(t[0] == "update") m.cmd = cmd::update; +// printf("t[%d] : %s, running in clientmode: %d\n", origin, t[origin].c_str(), clientmode); + +// printf("%d\n", t.size()); + + if(t[origin] == "observe") m.cmd = cmd::observe; + else if(t[origin] == "unobserve") m.cmd = cmd::unobserve; + else if(t[origin] == "create") m.cmd = cmd::create; + else if(t[origin] == "remove") m.cmd = cmd::remove; + else if(t[origin] == "move") m.cmd = cmd::move; + else if(t[origin] == "update") m.cmd = cmd::update; else m.cmd = cmd::error; // printf("Number of tokens %d\n", t.size()); switch(m.cmd) { case cmd::observe: { - if(t.size() != 1+1) { - printf("Wrong number of parameters\n"); + if(t.size() != origin+1+1) { + printf("W1: rong number of parameters\n"); continue; } - m.observe.id = atoi(t[1].c_str()); + m.observe.id = atoi(t[origin+1].c_str()); break; } case cmd::unobserve: { - if(t.size() != 1+1) { + if(t.size() != origin+1+1) { printf("Wrong number of parameters\n"); continue; } - m.unobserve.id = atoi(t[1].c_str()); + m.unobserve.id = atoi(t[origin+1].c_str()); break; } case cmd::create: { - if(t.size() != 1+1) { + if(!clientmode && t.size() != origin+1+1) { printf("Wrong number of parameters\n"); continue; } - m.create.parentid = atoi(t[1].c_str()); + if(clientmode && t.size() != origin+1+2) { + printf("Wrong number of parameters\n"); + continue; + } + if(clientmode) { + m.create.id = atoi(t[origin+1].c_str()); + m.create.parentid = atoi(t[origin+2].c_str()); + } + else { + m.create.parentid = atoi(t[origin+1].c_str()); + } break; } case cmd::remove: { - if(t.size() != 1+1) { + if(t.size() != origin+1+1) { printf("Wrong number of parameters\n"); continue; } - m.remove.id = atoi(t[1].c_str()); + m.remove.id = atoi(t[origin+1].c_str()); break; } case cmd::move: { - if(t.size() != 2+1) { + if(t.size() != origin+2+1) { printf("Wrong number of parameters\n"); continue; } - m.move.id = atoi(t[1].c_str()); - m.move.parentid = atoi(t[2].c_str()); + m.move.id = atoi(t[origin+1].c_str()); + m.move.parentid = atoi(t[origin+2].c_str()); break; } case cmd::update: { - if(t.size() != 2+1) { + if(t.size() != origin+2+1) { printf("Wrong number of parameters\n"); continue; } - m.update.id = atoi(t[1].c_str()); - sprintf(m.update.title, "%s", t[2].c_str()); + m.update.id = atoi(t[origin+1].c_str()); + sprintf(m.update.title, "%s", t[origin+2].c_str()); break; } default: @@ -177,13 +197,23 @@ inline static void create_msg_list(MsgTokensList& msgTokensList, } MessageList parse_msg(std::string data) { - printf("Parsing: %s\n", data.c_str()); +// printf("Parsing: %s\n", data.c_str()); + + MsgTokensList msgTokensList; + parse_into_msg_tokens(data, msgTokensList); + + MessageList msgList; + create_msg_list(msgTokensList, msgList, false); + + return msgList; +} +MessageList parse_msg_client(std::string data) { MsgTokensList msgTokensList; parse_into_msg_tokens(data, msgTokensList); MessageList msgList; - create_msg_list(msgTokensList, msgList); + create_msg_list(msgTokensList, msgList, true); return msgList; } diff --git a/src/messageparser.h b/src/messageparser.h index 11b11cb..95208f2 100644 --- a/src/messageparser.h +++ b/src/messageparser.h @@ -31,6 +31,7 @@ #include "message.h" MessageList parse_msg(std::string msg); +MessageList parse_msg_client(std::string msg); //message_t create_msg(cmd::cmd_t type, task_t task); std::string msg_tostring(message_t msg); diff --git a/src/muniacli.cc b/src/muniacli.cc index a84de65..30e0ecf 100644 --- a/src/muniacli.cc +++ b/src/muniacli.cc @@ -30,13 +30,94 @@ #include #include #include +#include +#include +#include + +#include "message.h" +#include "messageparser.h" #include + enum demo_protocols { PROTOCOL_TASK }; +enum cmd_t { + DEFAULT, + CREATE, + LIST, + REMOVE, + UPDATE +}; + +static bool run; +static bool interactive; +static std::string msgs; +static int taskid; + +static std::map > structuremap; +static std::map titlemap; + +static std::string indent; + + +static void rec_pretty_print(int node) { + // printf("pretty printing %d\n", node); + // for(std::map>::iterator it = structuremap.begin(); + // it != structuremap.end(); it++) { + // std::list childlist = *it; + + printf("%s%d - %s\n", indent.c_str(), node, titlemap[node].c_str()); + std::list childlist = structuremap[node]; + if(!childlist.empty()) { + for(std::list::iterator it = childlist.begin(); + it != childlist.end(); it++) { + int child = *it; + indent += " "; + rec_pretty_print(child); + } + } + + indent = indent.substr(0, indent.length()-2); +} + +static void pretty_print(std::string msgs) { + // printf("%s\n", msgs.c_str()); + MessageList list = parse_msg_client(msgs); + + std::string indent; + int prevtask = -1; + + std::list childlist; + + for(MessageList::iterator it = list.begin(); + it != list.end(); it++) { + message_t msg = *it; + + switch(msg.cmd) { + case cmd::create: + // printf("Parent %d, id %d\n", msg.create.parentid, msg.create.id); + childlist = structuremap[msg.create.parentid]; + childlist.push_back(msg.create.id); + structuremap[msg.create.parentid] = childlist; + // printf("Childlist size of %d = %d\n", msg.create.parentid, childlist.size()); + break; + case cmd::update: + // char buf[256]; + // sprintf(buf, "%s", msg.update.title); + titlemap[msg.update.id] = msg.update.title; + // printf("%s\n", buf); + break; + default: + break; + } + } + + rec_pretty_print(taskid); +} + static int callback_task(struct libwebsocket_context *me, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, @@ -46,6 +127,7 @@ static int callback_task(struct libwebsocket_context *me, LWS_SEND_BUFFER_POST_PADDING]; int l; char msg[4096]; + std::string r; switch (reason) { @@ -59,21 +141,34 @@ static int callback_task(struct libwebsocket_context *me, break; case LWS_CALLBACK_CLIENT_RECEIVE: - fprintf(stderr, "rx %d '", (int)len); - fwrite(in, len, 1, stderr); - fprintf(stderr, "'\n"); + // fprintf(stderr, "rx %d '", (int)len); + // fwrite(in, len, 1, stderr); + // fprintf(stderr, "\n"); + pretty_print((char*)in); libwebsocket_callback_on_writable(me, wsi); + + if(!interactive) run = false; break; case LWS_CALLBACK_CLIENT_WRITEABLE: - fgets(msg, sizeof(msg), stdin); - printf("send...\n"); - l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING], "%s", msg); + + if(interactive) { + fgets(msg, sizeof(msg), stdin); + msgs += msg; + printf("send...\n"); + } - libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], - l, LWS_WRITE_TEXT); + if(!msgs.empty()) { + // printf("Sending %s\n", msgs.c_str()); + l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING], "%s", msgs.c_str()); + + libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], + l, LWS_WRITE_TEXT); + + msgs.clear(); + } break; - + default: break; } @@ -92,6 +187,7 @@ int client(const char *address, int port) struct libwebsocket *wsi_task = NULL; int ietf_version = -1; // latest + context = libwebsocket_create_context(CONTEXT_PORT_NO_LISTEN, NULL, protocols, libwebsocket_internal_extensions, @@ -108,6 +204,7 @@ int client(const char *address, int port) */ int n = 1; while(n >= 0) { + n = libwebsocket_service(context, 1000); if (wsi_task == NULL) { @@ -129,17 +226,153 @@ int client(const char *address, int port) wsi_mirror, LWS_CLOSE_STATUS_GOINGAWAY); */ } + + if(!run) break; } - fprintf(stderr, "Exiting\n"); + // fprintf(stderr, "Exiting\n"); libwebsocket_context_destroy(context); return 0; } -int main() +static struct option options[] = { + { "create", no_argument, NULL, 'C'}, + { "help", no_argument, NULL, 'h' }, + { "host", required_argument, NULL, 'H'}, + { "interactive", no_argument, NULL, 'i'}, + { "id", required_argument, NULL, 'I'}, + { "list", no_argument, NULL, 'L'}, + { "name", required_argument, NULL, 'n'}, + { "port", required_argument, NULL, 'p' }, + { "remove", no_argument, NULL, 'R'}, + { "update", required_argument, NULL, 'U'}, + { NULL, 0, 0, 0 } +}; + +static char* USAGE= + "Usage: muniacli [OPTION]... TASK COMMAND\n" + "Commandline client to munia." + "Options:\n" + " -p, --port Port on host\n" + " -H, --host Host\n" + " -i, --interactive Run in interactive/shell mode\n" + "Task:\n" + " -N, --name Select task by name\n" + " -I, --id Select task by id\n" + "Commands:\n" + " -C, --create Create new subtask in TASK\n" + " -L, --list List subtasks in TASK\n" + " -R, --remove Remove subtask from TASK\n" + " -U, --update Update data in TASK"; + + +int main(int argc, char** argv) { - client("localhost", 10001); + int port = 7681; + struct libwebsocket_context *context; + int opts = 0; + std::string host = "localhost"; + int optionscount = 0; + std::string taskbyid; + std::string taskbyname; + cmd_t cmd = DEFAULT; + std::string cmd_opts; + + interactive = false; + run = true; + + int n = 0; + while(n >= 0) { + n = getopt_long(argc, argv, "p:iN:I:CLR:U:hH:", options, NULL); + if(n < 0) continue; + switch(n) { + case 'i': + interactive = true; + break; + case 'p': + port = atoi(optarg); + break; + case 'H': + host = optarg; + break; + case 'h': + fprintf(stderr, "%s\n", USAGE); + exit(1); + case 'N': + taskbyname = optarg; + break; + case 'I': + taskbyid = optarg; + break; + case 'C': + cmd = CREATE; + break; + case 'L': + cmd = LIST; + break; + case 'R': + cmd = REMOVE; + break; + case 'U': + cmd = UPDATE; + cmd_opts = optarg; + break; + } + } + + if(cmd == DEFAULT) { + fprintf(stderr, "%s\n", USAGE); + exit(1); + } + + if(!taskbyname.empty()) { + taskbyid = -1; + fprintf(stderr, "Option '-N, --name' is not yet supported\n"); + fprintf(stderr, "%s\n", USAGE); + exit(1); + } + + if(taskbyid.empty()) { + fprintf(stderr, "%s\n", USAGE); + exit(1); + } + + taskid = atoi(taskbyid.c_str()); + + switch(cmd) { + case CREATE: + msgs = "create " + taskbyid + ";"; + break; + case LIST: + msgs = "observe " + taskbyid; //+ + // "; unobserve " + task + ";"; + break; + case REMOVE: + msgs = "remove " + taskbyid + ";"; + break; + case UPDATE: + msgs = "update " + taskbyid + " " + cmd_opts; + break; + } + + /* + if(!interactive && argc - optionscount < 3) { + fprintf(stderr, "%s", USAGE); + exit(1); + } + else if (interactive && argc - optionscount < 2){ + fprintf(stderr, "%s", USAGE); + exit(1); + } + + if(!interactive) { + // printf("cmd: %s\n", argv[3]); + msgs = argv[3]; + } + */ + + client("localhost", port); return 0; } -- cgit v1.2.3