123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- #include "../include/ioman.h"
- #include "../include/global.h"
- #include <boost/asio.hpp>
- #include <iostream>
- #include <boost/algorithm/string.hpp>
- #include <string>
- #include <vector>
- #include <readline/history.h>
- #include <readline/readline.h>
- using std::string;
- using std::vector;
- using boost::asio::buffer;
- using boost::asio::ip::tcp;
- 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() {
- networkmutex.lock();
- inputmutex.lock();
- responsemutex.lock();
- runnetwork = false;
- runinput = false;
- runresponse = false;
- networkmutex.unlock();
- inputmutex.unlock();
- responsemutex.unlock();
- initcv.notify_all();
- localcv.notify_all();
- netcv.notify_all();
- 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;
- std::unique_lock<std::mutex> ulock;
- 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);
- localcv.notify_all();
- 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);
- ulock = std::unique_lock<std::mutex>(initmutex);
- while (versionstatus == off) {
- initcv.wait(ulock);
- }
- if (versionstatus == err) {
- runnetwork = false;
- runinput = false;
- runresponse = false;
- return false;
- }
- initmutex.unlock();
- initcv.notify_all();
- printWelcomeMessage();
- return true;
- }
- void IoMan::networkMain() {
- vector<Json::Value> toput;
- char *recvjson;
- Json::Value root;
- unsigned int jsonsize, readsize;
- printMessage("IoMan::networkMain() begin", debug);
- networkmutex.lock();
- while (runnetwork) {
- networkmutex.unlock();
- /*
- 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<const char *>(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<const char *>(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);
- }
- netcv.notify_all();
- // clean up local stuff
- toput = vector<Json::Value>();
- recvbuf.consume(readsize);
- networkmutex.lock();
- }
- }
- void IoMan::inputMain() {
- vector<string> toprocess;
- string command;
- vector<string> args;
- CmdMan::CmdRet cmdret;
- std::unique_lock<std::mutex> ulock;
- size_t prev, index, quot;
- printMessage("IoMan::inputMain() begin", debug);
- inputmutex.lock();
- while (runinput) {
- inputmutex.unlock();
- /*
- get inputmutex
- read all input vector into local vector
- release inputmutex
- process inputs
- send to server if required
- */
- // read into local vector
- ulock = std::unique_lock<std::mutex>(localmutex);
- while (!localinput.size() && runinput) {
- localcv.wait(ulock);
- }
- printMessage(string(__PRETTY_FUNCTION__) + string(" has localmutex"),
- debug);
- toprocess = vector<string>(localinput);
- localinput = vector<string>();
- localmutex.unlock();
- printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"),
- debug);
- localcv.notify_all();
- if (!runinput)
- return;
- // printMessage(string("have ") + std::to_string(toprocess.size()) +
- // string(" commands"), debug);
- // process
- for (string cmd : toprocess) {
- args = vector<string>();
- /* tokenize string into command and arguments vector*/
- if ((index = cmd.find(" ")) == string::npos) {
- // only command no args
- command = cmd;
- } else {
- command = cmd.substr(0, index);
- //~ index++;
- bool end_tokenizing = false;
- while (!end_tokenizing) {
- // find first char thats not a space
- while (cmd[index] == ' ') {
- index++;
- // bounds check
- if (index == cmd.size())
- end_tokenizing = true;
- }
- if (end_tokenizing)
- break;
- 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())
- end_tokenizing = true;
- } else {
- // non-quoted string
- index = cmd.find(" ");
- if (index == string::npos) { // no spaces, last arg
- args.push_back(cmd);
- end_tokenizing = true;
- } else {
- args.push_back(cmd.substr(0, index));
- }
- }
- }
- }
- 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<string>();
- inputmutex.lock();
- }
- }
- void IoMan::responseMain() {
- vector<Json::Value> toprocess;
- vector<string> toput;
- CmdMan::CmdRet cmdret;
- std::unique_lock<std::mutex> ulock;
- printMessage("IoMan::responseMain() begin", debug);
- responsemutex.lock();
- while (runresponse) {
- responsemutex.unlock();
- /*
- 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
- ulock = std::unique_lock<std::mutex>(netmutex);
- while (!netinput.size() && runresponse) {
- netcv.wait(ulock);
- }
- printMessage(string(__PRETTY_FUNCTION__) + string(" get netmutex"), debug);
- toprocess = vector<Json::Value>(netinput);
- netinput = vector<Json::Value>();
- netmutex.unlock();
- printMessage(string(__PRETTY_FUNCTION__) + string(" release netmutex"),
- debug);
- netcv.notify_all();
- if (!runresponse)
- return;
- // 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 */
- mainmutex.lock();
- runmain = false;
- mainmutex.unlock();
- break;
- }
- case CmdMan::rettype::error: {
- initmutex.lock();
- if (versionstatus == off)
- versionstatus = err;
- else if (loginstatus == off)
- loginstatus = err;
- initmutex.unlock();
- initcv.notify_all();
- printMessage(cmdret.msg, error);
- break;
- }
- case CmdMan::rettype::seton: {
- initmutex.lock();
- if (versionstatus == off)
- versionstatus = on;
- else
- loginstatus = on;
- initmutex.unlock();
- initcv.notify_all();
- }
- 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);
- }
- localcv.notify_all();
- // clean up local stuff
- toprocess = vector<Json::Value>();
- toput = vector<string>();
- responsemutex.lock();
- }
- }
- void IoMan::run() {
- printMessage("IoMan::run() begin", debug);
- char *line = NULL, *user = NULL, *pass = NULL;
- vector<string> tokens;
- string work, command;
- CmdMan::CmdRet cmdret;
- Json::Value root;
- std::unique_lock<std::mutex> ulock;
- 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);
- localcv.notify_all();
- ulock = std::unique_lock<std::mutex>(initmutex);
- while (loginstatus == off) {
- initcv.wait(ulock);
- }
- if (loginstatus == err)
- return;
- initcv.notify_all();
- mainmutex.lock();
- while (runmain) {
- mainmutex.unlock();
- free(line);
- 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);
- localcv.notify_all();
- if (!connected)
- break;
- mainmutex.lock();
- }
- free(line);
- }
|