#include "../include/global.h" #include "../include/ioman.h" #include #include #include #include #include #include #include using std::string; using std::vector; using boost::asio::ip::tcp; using boost::asio::buffer; IoMan::IoMan(char *ipcstring) : cmdman(fileman) { ipstring = std::string(ipcstring); port = 1234; tcpsock = new tcp::socket(ios); connected = false; /* to be put elsewhere */ /* setup json stuff */ Json::CharReaderBuilder rbuilder; wbuilder.settings_["indentation"] = ""; reader = rbuilder.newCharReader(); runnetwork = false; runinput = false; runresponse = false; startlist = false; versionstatus = off; loginstatus = off; } IoMan::~IoMan() { runnetwork = false; runinput = false; runresponse = false; tnetwork.join(); tinput.join(); tresponse.join(); if(connected) { disconnect(); } delete tcpsock; delete reader; } void IoMan::printMessage(string nouse, OutMsgType nouse2) { } bool IoMan::connect() { tcp::endpoint *ep; ep = new tcp::endpoint(boost::asio::ip::address::from_string(ipstring), 1234); // establish connection printMessage("IoMan::connect() connecting to " + ipstring, debug); tcpsock->connect(*ep, errcode); if (errcode) { delete ep; printMessage("IoMan::connect() couldnt connect to " + ipstring + "\n" + errcode.message(), error); return false; } connected = true; delete ep; return true; } void IoMan::disconnect() { printMessage("IoMan::disconnect()", debug); tcpsock->close(); connected = false; } bool IoMan::init() { CmdMan::CmdRet ret; string work; Json::Value root; printMessage("IoMan::Init() begin", debug); if(!connect()) return false; printMessage("IoMan::Init() versioncheck", debug); localmutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug); localinput.push_back("version " + protocolVersion); localmutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug); printMessage("IoMan::Init() begin", debug); runnetwork = true; runinput = true; runresponse = true; tnetwork = std::thread(&IoMan::networkMain, this); tinput = std::thread(&IoMan::inputMain, this); tresponse = std::thread(&IoMan::responseMain, this); while(versionstatus == off); if(versionstatus == err) { runnetwork = false; runinput = false; runresponse = false; return false; } printWelcomeMessage(); return true; } void IoMan::networkMain() { vector toput; char *recvjson; Json::Value root; unsigned int jsonsize, readsize; printMessage("IoMan::networkMain() begin", debug); while(runnetwork) { std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); /* read from network until \n try to parse json - output error if not ok store all ok json in local vector get networkmutex put all local jsons into network vector release networkmutex */ // read from network readsize = boost::asio::read_until(*tcpsock, recvbuf, '\n', errcode); printMessage(string(__PRETTY_FUNCTION__) + string(" asio::read() ok ") + std::to_string(readsize), debug); // printMessage(string("have ") + std::to_string(toprocess.size()) + string(" commands"), debug); if (errcode && errcode != boost::asio::error::eof) { printMessage("IoMan::networkMain() couldnt read json data\n" + errcode.message(), error); continue; } if(!readsize) break; recvjson = (char *)(boost::asio::buffer_cast(recvbuf.data())); recvjson[readsize] = 0; while(strchr(recvjson, '\n')) { // parse jsonsize = strchr(recvjson, '\n') - recvjson + 1; printMessage(string(__PRETTY_FUNCTION__) + string(" found jsondata ") + string(recvjson), debug); if (!reader->parse(recvjson, recvjson + jsonsize, &root, &jsonerror)) { printMessage("IoMan::networkMain() couldnt parse json data: " + jsonerror, error); recvbuf.consume(jsonsize); continue; } recvbuf.consume(jsonsize); readsize -= jsonsize; printMessage(string(__PRETTY_FUNCTION__) + string(" remaining recvbuf ") + string(boost::asio::buffer_cast(recvbuf.data())), debug); for(int i = 0; i < jsonsize; i++) recvjson++; // store locally toput.push_back(root); } if(toput.size()){ // put into global vector netmutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get netmutex"), debug); netinput.insert(netinput.end(), toput.begin(), toput.end()); netmutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release netmutex"), debug); } // clean up local stuff toput = vector(); recvbuf.consume(readsize); } } void IoMan::inputMain() { vector toprocess; string command; vector args; CmdMan::CmdRet cmdret; size_t prev, index, quot; printMessage("IoMan::inputMain() begin", debug); while(runinput) { std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); /* get inputmutex read all input vector into local vector release inputmutex process inputs send to server if required */ // read into local vector if(localinput.size()) { localmutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" has localmutex"), debug); toprocess = vector(localinput); localinput = vector(); localmutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug); } // printMessage(string("have ") + std::to_string(toprocess.size()) + string(" commands"), debug); // process for(string cmd : toprocess) { args = vector(); if((index = cmd.find(" ")) == string::npos) { // only command no args command = cmd; } else { command = cmd.substr(0, index); //~ index++; while(true) { // find first char thats not a space while(cmd[index] == ' ') { index++; // bounds check if(index == cmd.size()) goto end_tokenizing; } cmd = cmd.substr(index); if(cmd[0] == '\"') { // quoted string index = cmd.find("\""); args.push_back(cmd.substr(1, index-1)); index++; /* tokens.push_back(cmd.substr(0, ++index)); */ // char after closing quote should be space while within bounds if(index == cmd.size()) goto end_tokenizing; } else { // non-quoted string index = cmd.find(" "); if(index == string::npos) { // no spaces, last arg args.push_back(cmd); goto end_tokenizing; } else { args.push_back(cmd.substr(0, index)); } } } end_tokenizing: ; } cmdret = cmdman.execute(command, args); // determine wether to send something and do so if required switch(cmdret.type) { case CmdMan::rettype::send: { printMessage("IoMan::inputMain() sending json \"" + cmdret.msg + "\"", debug); boost::asio::write(*tcpsock, buffer(cmdret.msg + "\n"), errcode); if (errcode) { printMessage("IoMan::inputMain() couldnt send json data\n" + errcode.message() + "\n", error); continue; } break; } case CmdMan::rettype::notsend: { printMessage(cmdret.msg, normal); break; } case CmdMan::rettype::error: { printMessage(cmdret.msg, error); break; } } } // clean up local stuff toprocess = vector(); } } void IoMan::responseMain() { vector toprocess; vector toput; CmdMan::CmdRet cmdret; printMessage("IoMan::responseMain() begin", debug); while(runresponse) { std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); /* get networkmutex read all network vector into local vector release networkmutex process all jsons process putdata process getdata process listdata get inputmutex place new commands into input vector release inputmutex */ // read into local vector if(netinput.size()) { netmutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get netmutex"), debug); toprocess = vector(netinput); netinput = vector(); netmutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release netmutex"), debug); } // process jsons for(Json::Value root : toprocess) { cmdret = cmdman.handle(root); switch(cmdret.type) { case CmdMan::rettype::startlist: { startlist = true; break; } case CmdMan::rettype::stoplist: { startlist = false; break; } case CmdMan::rettype::close: { /* TODO i dunno */ runmain = false; break; } case CmdMan::rettype::error: { if(versionstatus == off) versionstatus = err; else if(loginstatus == off) loginstatus = err; printMessage(cmdret.msg, error); break; } case CmdMan::rettype::seton: { if(versionstatus == off) versionstatus = on; else loginstatus = on; } case CmdMan::rettype::notsend: { printMessage(cmdret.msg, normal); break; } case CmdMan::rettype::send: { toput.push_back(cmdret.msg); break; } } } if(toput.size()) { // put new commands into global vector localmutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug); localinput.insert(localinput.end(), toput.begin(), toput.end()); localmutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug); } // clean up local stuff toprocess = vector(); toput = vector(); } } void IoMan::run() { printMessage("IoMan::run() begin", debug); char *line = NULL, *user = NULL, *pass = NULL; vector tokens; string work, command; CmdMan::CmdRet cmdret; Json::Value root; runmain = true; while(!user) { user = readline(getUserPrompt().c_str()); printMessage("Using user: " + string(user), error); } while(!pass) { pass = readline(getPassPrompt().c_str()); printMessage("Using pass: " + string(pass), error); } printMessage("IoMan::run() login", debug); localmutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug); localinput.push_back("login " + string(user) + " " + string(pass)); localmutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug); free(user); free(pass); while(loginstatus == off); if(loginstatus == err) return; while(runmain) { free(line); std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); line = readline(getCmdPrompt().c_str()); if(!runmain) break; // if no input, do not add to history, and go to reading next line if (strlen(line) == 0) { continue; } // split input line into tokens boost::algorithm::split(tokens, std::string(line), boost::algorithm::is_any_of(" "), boost::algorithm::token_compress_on); // if input contains only spaces, do not add to history, and go to reading // next line if (tokens.size() < 1) { continue; } // add the line to history add_history(line); localmutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug); localinput.push_back(line); localmutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug); if(!connected) break; } free(line); }