/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * muniacli.cc * * Fri May 4 15:39:06 CEST 2012 * Copyright 2012 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of Munia. * * Munia is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Munia is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Munia; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #include #include //#include "message.h" //#include "messageparser.h" #include static bool run; static std::string msgs; struct per_session_data__lws_node { struct lws *wsi; }; static int callback_lws_node(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 + LWS_SEND_BUFFER_POST_PADDING]; int l; std::string r; switch (reason) { case LWS_CALLBACK_CLOSED: //fprintf(stderr, "mirror: LWS_CALLBACK_CLOSED\n"); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: lws_callback_on_writable(wsi); break; case LWS_CALLBACK_CLIENT_RECEIVE: //pretty_print((char*)in); printf("%s\n", (char*)in); lws_callback_on_writable(wsi); //if(!interactive) run = false; run = false; break; case LWS_CALLBACK_CLIENT_WRITEABLE: //if(interactive) //{ // fgets(msg, sizeof(msg), stdin); // msgs += msg; // printf("send...\n"); //} l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING], "%s", msgs.c_str()); lws_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], l, LWS_WRITE_TEXT); break; default: break; } return 0; } static struct lws_protocols protocols[] = { { "lws-node-protocol", callback_lws_node, sizeof(struct per_session_data__lws_node) }, { nullptr, nullptr, 0 } // End of list }; int client(const char *address, int port) { // printf("Connection to %s on port %d\n", address, port); struct lws_context *context; struct lws *wsi_node = nullptr; int ietf_version = -1; // latest lws_set_log_level(0, nullptr); struct lws_context_creation_info info{}; info.port = CONTEXT_PORT_NO_LISTEN; info.iface = nullptr; // What is this? info.protocols = protocols; //info.extensions = lws_get_internal_extensions(); context = lws_create_context(&info); if(context == nullptr) { fprintf(stderr, "Creating lws context failed\n"); return 1; } // sit there servicing the websocket context to handle incoming // packets, and drawing random circles on the mirror protocol websocket int n = 1; while(n >= 0) { n = lws_service(context, 10); if(wsi_node == nullptr) { lws_client_connect_info info; memset(&info, 0, sizeof(info)); info.context = context; info.address = address; info.port = port; info.ssl_connection = 0; info.path = "/"; info.host = address; info.origin = address; info.protocol = "lws-node-protocol"; info.ietf_version_or_minus_one = ietf_version; wsi_node = lws_client_connect_via_info(&info); if(wsi_node == nullptr) { fprintf(stderr, "lws node connect failed\n"); return -1; } else { //... } } else { //fprintf(stderr, "closing mirror session\n"); //lws_close_and_free_session(context, // wsi_mirror, LWS_CLOSE_STATUS_GOINGAWAY); } if(!run) { break; } } lws_context_destroy(context); return 0; } static struct option options[] = { { "command", required_argument, nullptr, 'c'}, { "help", no_argument, nullptr, 'h' }, { "host", required_argument, nullptr, 'H'}, { "port", required_argument, nullptr, 'p' }, { "raw", no_argument, nullptr, 'r'}, { nullptr, 0, 0, 0 } }; static const char* USAGE = "Usage: muniacli [OPTION]... NODE COMMAND\n" "Commandline client to munia." "Options:\n" " -p, --port Port on host\n" " -H, --host Host\n" " -c, --command Command\n"; int main(int argc, char** argv) { int port = 7681; std::string host = "localhost"; std::string cmd; // bool raw = true; run = true; int n = 0; while(n >= 0) { n = getopt_long(argc, argv, "c:H:p:r", options, nullptr); if(n < 0) { continue; } switch(n) { case 'c': cmd = optarg; break; case 'p': port = atoi(optarg); break; case 'H': host = optarg; break; case 'r': //raw = true; break; case 'h': fprintf(stderr, "%s\n", USAGE); exit(1); break; } } msgs = cmd; client(host.c_str(), port); return 0; } #if 0 enum demo_protocols { PROTOCOL_NODE }; enum cmd_t { DEFAULT, CREATE, LIST, REMOVE, UPDATE }; static bool run; static bool interactive; static std::string msgs; static int nodeid; 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]; childlist.unique(); 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; 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]; //if(childlist.find(msg.create.id) == childlist.end()) //{ 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(nodeid); } static int callback_node(struct lws_context *me, struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 + LWS_SEND_BUFFER_POST_PADDING]; int l; char msg[4096]; std::string r; switch (reason) { case LWS_CALLBACK_CLOSED: fprintf(stderr, "mirror: LWS_CALLBACK_CLOSED\n"); // wsi_mirror = nullptr; break; case LWS_CALLBACK_CLIENT_ESTABLISHED: lws_callback_on_writable(me, wsi); break; case LWS_CALLBACK_CLIENT_RECEIVE: //fprintf(stderr, "rx %d '", (int)len); //fwrite(in, len, 1, stderr); //fprintf(stderr, "\n"); pretty_print((char*)in); lws_callback_on_writable(me, wsi); if(!interactive) { run = false; } break; case LWS_CALLBACK_CLIENT_WRITEABLE: if(interactive) { fgets(msg, sizeof(msg), stdin); msgs += msg; printf("send...\n"); } if(!msgs.empty()) { // printf("Sending %s\n", msgs.c_str()); l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING], "%s", msgs.c_str()); lws_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], l, LWS_WRITE_TEXT); msgs.clear(); } break; default: break; } return 0; } static struct lws_protocols protocols[] = { { "lws-node-protocol", callback_node, 0, }, { nullptr, nullptr, 0 } }; int client(const char *address, int port) { struct lws_context *context; struct lws *wsi_node = nullptr; int ietf_version = -1; // latest context = lws_create_context(CONTEXT_PORT_NO_LISTEN, nullptr, protocols, lws_internal_extensions, nullptr, nullptr, -1, -1, 0); if (context == nullptr) { fprintf(stderr, "Creating lws context failed\n"); return 1; } // sit there servicing the websocket context to handle incoming // packets, and drawing random circles on the mirror protocol websocket int n = 1; while(n >= 0) { n = lws_service(context, 10); if (wsi_node == nullptr) { wsi_node = lws_client_connect(context, address, port, 0, "/", address, address, protocols[lws-node-protocol].name, ietf_version); if(wsi_node == nullptr) { fprintf(stderr, "lws node connect failed\n"); return -1; } } else { //fprintf(stderr, "closing mirror session\n"); //lws_close_and_free_session(context, // wsi_mirror, LWS_CLOSE_STATUS_GOINGAWAY); } if(!run) { break; } } //fprintf(stderr, "Exiting\n"); lws_context_destroy(context); return 0; } static struct option options[] = { { "create", no_argument, nullptr, 'C'}, { "help", no_argument, nullptr, 'h' }, { "host", required_argument, nullptr, 'H'}, { "interactive", no_argument, nullptr, 'i'}, { "id", required_argument, nullptr, 'I'}, { "list", no_argument, nullptr, 'L'}, { "name", required_argument, nullptr, 'n'}, { "port", required_argument, nullptr, 'p' }, { "remove", no_argument, nullptr, 'R'}, { "update", required_argument, nullptr, 'U'}, { nullptr, 0, 0, 0 } }; static const char* USAGE = "Usage: muniacli [OPTION]... NODE 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" "Node:\n" " -N, --name Select node by name\n" " -I, --id Select node by id\n" "Commands:\n" " -C, --create Create new subnode in NODE\n" " -L, --list List subnodes in NODE\n" " -R, --remove Remove subnode from NODE\n" " -U, --update Update data in NODE"; int main(int argc, char** argv) { int port = 7681; std::string host = "localhost"; std::string nodebyid; std::string nodebyname; 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:CLRU:hH:", options, nullptr); 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': nodebyname = optarg; break; case 'I': nodebyid = 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(!interactive && cmd == DEFAULT) { fprintf(stderr, "%s\n", USAGE); exit(1); } if(!interactive && !nodebyname.empty()) { nodebyid = -1; fprintf(stderr, "Option '-N, --name' is not yet supported\n"); fprintf(stderr, "%s\n", USAGE); exit(1); } if(!interactive && nodebyid.empty()) { fprintf(stderr, "%s\n", USAGE); exit(1); } nodeid = atoi(nodebyid.c_str()); switch(cmd) { case CREATE: msgs = "subscribe " + nodebyid + ";"; msgs += "create " + nodebyid + ";"; break; case LIST: msgs = "subscribe " + nodebyid + ";"; //+ // "; unsubscribe " + node + ";"; break; case REMOVE: msgs = "remove " + nodebyid + ";"; break; case UPDATE: msgs = "subscribe " + nodebyid + ";"; msgs += "update " + nodebyid + " \"" + cmd_opts + "\"; "; break; case DEFAULT: break; } // printf("msgs: %s\n", msgs.c_str()); // 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(host.c_str(), port); return 0; } #endif/*0*/