#include "../include/batchioman.h" #include #include #include BatchIoMan::BatchIoMan(bool usessl, bool beverbose, std::string batchpath) : IoMan(usessl) { /* setup json stuff */ Json::CharReaderBuilder rbuilder; wbuilder.settings_["indentation"] = ""; reader = rbuilder.newCharReader(); /* initialize print command map */ printmap["error"] = &BatchIoMan::printError; printmap["connect"] = &BatchIoMan::printConnect; printmap["help"] = &BatchIoMan::printHelp; printmap["status"] = &BatchIoMan::printStatus; printmap["disconnect"] = &BatchIoMan::printDisconnect; printmap["put"] = &BatchIoMan::printPut; printmap["get"] = &BatchIoMan::printGet; printmap["list"] = &BatchIoMan::printList; printmap["version"] = &BatchIoMan::printVersion; printmap["login"] = &BatchIoMan::printLogin; printmap["signup"] = &BatchIoMan::printSignup; printmap["putdata"] = &BatchIoMan::printPutdata; printmap["getdata"] = &BatchIoMan::printGetdata; printmap["head"] = &BatchIoMan::printHead; printmap["deletefile"] = &BatchIoMan::printDeletefile; printmap["deleteme"] = &BatchIoMan::printDeleteme; printmap["keyfile"] = &BatchIoMan::printKeyfile; printmap["closekey"] = &BatchIoMan::printClosekey; getnextline = true; verbose = beverbose; filepath = batchpath; } bool BatchIoMan::init() { batchin.open(filepath); normalout.open(filepath + ".out"); if (verbose) debugout.open(filepath + ".debug"); errorout.open(filepath + ".err"); if (!batchin.is_open() || !normalout.is_open() || (verbose && !debugout.is_open()) || !errorout.is_open()) return false; return IoMan::init(); } BatchIoMan::~BatchIoMan() { batchin.close(); normalout.close(); if (verbose) debugout.close(); errorout.close(); delete reader; } void BatchIoMan::printMessage(std::string msg, OutMsgType type) { Json::Value root; msgmutex.lock(); switch (type) { case normal: { // this should never happen outside of development if (!reader->parse(msg.c_str(), msg.c_str() + msg.size(), &root, &jsonerror)) { printMessage(string(__PRETTY_FUNCTION__) + " couldnt parse json data: " + jsonerror, debug); } else { normalout << printJson(root) << std::endl; } break; } case error: { // this should never happen outside of development if (!reader->parse(msg.c_str(), msg.c_str() + msg.size(), &root, &jsonerror)) { printMessage(string(__PRETTY_FUNCTION__) + " couldnt parse json data: " + jsonerror, debug); } else { errorout << printJson(root) << std::endl; } break; } case debug: { if (verbose) debugout << msg << std::endl; break; } } msgmutex.unlock(); } void BatchIoMan::printWelcomeMessage() {} std::string BatchIoMan::getCmdPrompt() { return ""; } /* modified handleInCmdResponse to abort on error */ void BatchIoMan::handleInCmdResponse(CmdMan::CmdRet cmdret) { // determine wether to send something and do so if required if (cmdret.type & CmdMan::rettype::print) { printMessage(Json::writeString(wbuilder, cmdret.msg), normal); if (!(cmdret.type ^ CmdMan::rettype::print)) { // xor here works because flag is set at this point // if we only printed something get the next line linemutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug); getnextline = true; linemutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug); linecv.notify_all(); } } if (cmdret.type & CmdMan::rettype::send) { printMessage("IoMan::inputMain() sending json \"" + Json::writeString(wbuilder, cmdret.msg) + "\"", debug); if (usessl) boost::asio::write(*sslsock, boost::asio::buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode); else boost::asio::write(*tcpsock, boost::asio::buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode); if (errcode) { printMessage("IoMan::inputMain() couldnt send json data\n" + errcode.message() + "\n", error); mainmutex.lock(); runmain = false; mainmutex.unlock(); linemutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug); getnextline = true; linemutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug); linecv.notify_all(); return; } } if (cmdret.type & CmdMan::rettype::error) { printMessage(Json::writeString(wbuilder, cmdret.msg), error); mainmutex.lock(); runmain = false; mainmutex.unlock(); linemutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug); getnextline = true; linemutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug); linecv.notify_all(); } if (cmdret.type & CmdMan::rettype::close) { /* TODO i dunno */ mainmutex.lock(); runmain = false; mainmutex.unlock(); linemutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug); getnextline = true; linemutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug); linecv.notify_all(); } if (cmdret.type & CmdMan::rettype::connect) { ipstring = cmdret.msg["address"].asString(); port = cmdret.msg["port"].asUInt(); if (connect()) { runnetwork = true; tnetwork = std::thread(&BatchIoMan::networkMain, this); // put new commands into global vector localmutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug); localinput.push_back("version"); cmdman.stateSetConnectionOk(); localmutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug); localcv.notify_all(); } } if (cmdret.type & CmdMan::rettype::exit) { mainmutex.lock(); runmain = false; mainmutex.unlock(); linemutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug); getnextline = true; linemutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug); linecv.notify_all(); return; } if (cmdret.nextcommand.size()) { localmutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug); localinput.push_back(cmdret.nextcommand); localmutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug); localcv.notify_all(); } } /* modified handleOutCmdResponse to fetch next command and abort on error */ void BatchIoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, std::vector &toput) { if (cmdret.type & CmdMan::rettype::close) { // connection closed, stop network thread and shutdown any operations remaining networkmutex.lock(); runnetwork = false; networkmutex.unlock(); disconnect(); tnetwork.join(); if (cmdret.nextcommand.size()) { toput.push_back(cmdret.nextcommand); } } if (cmdret.type & CmdMan::rettype::error) { printMessage(Json::writeString(wbuilder, cmdret.msg), error); mainmutex.lock(); runmain = false; mainmutex.unlock(); linemutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug); getnextline = true; linemutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug); linecv.notify_all(); return; } if (cmdret.type & CmdMan::rettype::print) { printMessage(Json::writeString(wbuilder, cmdret.msg), normal); } if (cmdret.type & CmdMan::rettype::send) { printMessage(string(__PRETTY_FUNCTION__) + string(" send new cmd"), debug); if (cmdret.nextcommand.size()) { toput.push_back(cmdret.nextcommand); } } if (!(cmdret.type & CmdMan::rettype::send)) { // only fetch next line if we did not send a new command on our own // if we managed to get here, get next command from file linemutex.lock(); printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug); getnextline = true; linemutex.unlock(); printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug); linecv.notify_all(); } } /* main user input loop */ void BatchIoMan::run() { std::string line; printMessage(string(__PRETTY_FUNCTION__) + " begin", debug); std::unique_lock ulock; runmain = true; mainmutex.lock(); while (runmain) { mainmutex.unlock(); line.erase(); ulock = std::unique_lock(linemutex); while (!getnextline && runmain) { linecv.wait(ulock); } if (!runmain) break; printMessage(string(__PRETTY_FUNCTION__) + " fetch next line", debug); while (!line.size()) { // skip empty lines until either eof or non-empty line if (batchin.eof()) { line = "exit"; } else std::getline(batchin, line); } getnextline = false; linemutex.unlock(); 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(); mainmutex.lock(); } mainmutex.unlock(); } std::string BatchIoMan::printJson(Json::Value root) { map::iterator it = printmap.find(root["command"].asString()); if (it == printmap.end()) { // this should never happen outside of development printMessage(string(__PRETTY_FUNCTION__) + " unknown command \"" + root["command"].asString() + "\".\nensure code is implemented.", debug); return ""; } return (this->*(printmap[root["command"].asString()]))(root); } std::string BatchIoMan::printError(Json::Value root) { return std::string("Error: ") + root["error"].asString(); } std::string BatchIoMan::printConnect(Json::Value root) { if (!root["accept"].asBool()) { return std::string("Couldnt connect to ") + root["address"].asString() + ":" + std::to_string(root["port"].asUInt()) + "\n" + "Reason: " + root["error"].asString(); } return ""; } std::string BatchIoMan::printHelp(Json::Value root) { std::string ret = std::string("Available commands are: ") + "\n"; for (Json::Value i : root["names"]) ret += i.asString() + "\n"; return ret; } std::string BatchIoMan::printStatus(Json::Value root) { return std::string("Server reports status: ") + root["response"].asString(); } std::string BatchIoMan::printDisconnect(Json::Value root) { if (!root["accept"].asBool()) { return "Disconnect failed."; } else { return "Disconnect successful."; } } std::string BatchIoMan::printPut(Json::Value root) { if (!root["accept"].asBool()) { if (root.isMember("file")) { return std::string("Upload request for file ") + root["file"].asString() + " failed: " + root["error"].asString(); } else { return std::string("Upload request failed: ") + root["error"].asString(); } } else return std::string("Begin uploading file ") + root["file"].asString(); } std::string BatchIoMan::printGet(Json::Value root) { if (!root["accept"].asBool()) { if (root.isMember("file")) { return std::string("Download request for file ") + root["file"].asString() + " failed: " + root["error"].asString(); } else { return std::string("Download request failed: ") + root["error"].asString(); } } else return std::string("Begin downloading file ") + root["file"].asString(); } std::string BatchIoMan::printList(Json::Value root) { std::string ret; if (!root["accept"].asBool()) { ret = std::string("Listing files failed: ") + root["error"].asString(); } else { ret = std::string("Listing files stored on server: ") + "\n"; for (Json::Value i : root["names"]) ret += i.asString() + "\n"; ret += "End of list."; } return ret; } std::string BatchIoMan::printVersion(Json::Value root) { if (!root["accept"].asBool()) { return std::string("Version check failed. Server reports ") + root["serverversion"].asString() + " but client is " + root["clientversion"].asString(); } else return "Version check ok."; } std::string BatchIoMan::printLogin(Json::Value root) { if (!root["accept"].asBool()) { return std::string("Login failed: ") + root["error"].asString(); } else return "Login ok."; } std::string BatchIoMan::printSignup(Json::Value root) { if (!root["accept"].asBool()) { return std::string("Signup failed: ") + root["error"].asString(); } else return "Signup ok. You are now logged in."; } std::string BatchIoMan::printDeleteme(Json::Value root) { if (!root["accept"].asBool()) { return std::string("User deletion failed: ") + root["error"].asString(); } else return "User deletion ok. You are now disconnected from the server."; } std::string BatchIoMan::printPutdata(Json::Value root) { return ""; } std::string BatchIoMan::printGetdata(Json::Value root) { return ""; } std::string BatchIoMan::printListdata(Json::Value root) { return ""; } std::string BatchIoMan::printHead(Json::Value root) { if (!root["accept"].asBool()) return std::string("Request of the first four bytes failed. ") + root["error"].asString(); else return std::string("First four bytes of file ") + root["file"].asString() + " are: " + root["data"].asString(); } std::string BatchIoMan::printDeletefile(Json::Value root) { if (!root["accept"].asBool()) return std::string("Deletion of file ") + root["file"].asString() + " failed. " + root["error"].asString(); else return std::string("File ") + root["file"].asString() + " deleted succesfully"; } std::string BatchIoMan::printKeyfile(Json::Value root) { if (!root["accept"].asBool()) return std::string("Couldnt select keyfile ") + root["file"].asString() + ": " + root["error"].asString(); else return std::string("Using keyfile ") + root["file"].asString(); } std::string BatchIoMan::printClosekey(Json::Value root) { if (!root["accept"].asBool()) return std::string("Failed to close key: ") + root["error"].asString(); else return "Key closed."; }