batchioman.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. #include "../include/batchioman.h"
  2. #include <iostream>
  3. #include <string>
  4. #include <vector>
  5. BatchIoMan::BatchIoMan(bool usessl, bool beverbose, std::string batchpath) : IoMan(usessl) {
  6. /* setup json stuff */
  7. Json::CharReaderBuilder rbuilder;
  8. wbuilder.settings_["indentation"] = "";
  9. reader = rbuilder.newCharReader();
  10. /* initialize print command map */
  11. printmap["error"] = &BatchIoMan::printError;
  12. printmap["connect"] = &BatchIoMan::printConnect;
  13. printmap["help"] = &BatchIoMan::printHelp;
  14. printmap["status"] = &BatchIoMan::printStatus;
  15. printmap["disconnect"] = &BatchIoMan::printDisconnect;
  16. printmap["put"] = &BatchIoMan::printPut;
  17. printmap["get"] = &BatchIoMan::printGet;
  18. printmap["list"] = &BatchIoMan::printList;
  19. printmap["version"] = &BatchIoMan::printVersion;
  20. printmap["login"] = &BatchIoMan::printLogin;
  21. printmap["signup"] = &BatchIoMan::printSignup;
  22. printmap["putdata"] = &BatchIoMan::printPutdata;
  23. printmap["getdata"] = &BatchIoMan::printGetdata;
  24. printmap["head"] = &BatchIoMan::printHead;
  25. printmap["deletefile"] = &BatchIoMan::printDeletefile;
  26. printmap["deleteme"] = &BatchIoMan::printDeleteme;
  27. printmap["keyfile"] = &BatchIoMan::printKeyfile;
  28. printmap["closekey"] = &BatchIoMan::printClosekey;
  29. getnextline = true;
  30. verbose = beverbose;
  31. filepath = batchpath;
  32. }
  33. bool BatchIoMan::init() {
  34. batchin.open(filepath);
  35. normalout.open(filepath + ".out");
  36. if (verbose)
  37. debugout.open(filepath + ".debug");
  38. errorout.open(filepath + ".err");
  39. if (!batchin.is_open() || !normalout.is_open() || (verbose && !debugout.is_open()) || !errorout.is_open())
  40. return false;
  41. return IoMan::init();
  42. }
  43. BatchIoMan::~BatchIoMan() {
  44. batchin.close();
  45. normalout.close();
  46. if (verbose)
  47. debugout.close();
  48. errorout.close();
  49. delete reader;
  50. }
  51. void BatchIoMan::printMessage(std::string msg, OutMsgType type) {
  52. Json::Value root;
  53. msgmutex.lock();
  54. switch (type) {
  55. case normal: {
  56. // this should never happen outside of development
  57. if (!reader->parse(msg.c_str(), msg.c_str() + msg.size(), &root, &jsonerror)) {
  58. printMessage(string(__PRETTY_FUNCTION__) + " couldnt parse json data: " + jsonerror, debug);
  59. } else {
  60. normalout << printJson(root) << std::endl;
  61. }
  62. break;
  63. }
  64. case error: {
  65. // this should never happen outside of development
  66. if (!reader->parse(msg.c_str(), msg.c_str() + msg.size(), &root, &jsonerror)) {
  67. printMessage(string(__PRETTY_FUNCTION__) + " couldnt parse json data: " + jsonerror, debug);
  68. } else {
  69. errorout << printJson(root) << std::endl;
  70. }
  71. break;
  72. }
  73. case debug: {
  74. if (verbose)
  75. debugout << msg << std::endl;
  76. break;
  77. }
  78. }
  79. msgmutex.unlock();
  80. }
  81. void BatchIoMan::printWelcomeMessage() {}
  82. std::string BatchIoMan::getCmdPrompt() { return ""; }
  83. /* modified handleInCmdResponse to abort on error */
  84. void BatchIoMan::handleInCmdResponse(CmdMan::CmdRet cmdret) {
  85. // determine wether to send something and do so if required
  86. if (cmdret.type & CmdMan::rettype::print) {
  87. printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
  88. if (!(cmdret.type ^ CmdMan::rettype::print)) {
  89. // xor here works because flag is set at this point
  90. // if we only printed something get the next line
  91. linemutex.lock();
  92. printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
  93. getnextline = true;
  94. linemutex.unlock();
  95. printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
  96. linecv.notify_all();
  97. }
  98. }
  99. if (cmdret.type & CmdMan::rettype::send) {
  100. printMessage("IoMan::inputMain() sending json \"" + Json::writeString(wbuilder, cmdret.msg) + "\"", debug);
  101. if (usessl)
  102. boost::asio::write(*sslsock, boost::asio::buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode);
  103. else
  104. boost::asio::write(*tcpsock, boost::asio::buffer(Json::writeString(wbuilder, cmdret.msg) + "\n"), errcode);
  105. if (errcode) {
  106. printMessage("IoMan::inputMain() couldnt send json data\n" + errcode.message() + "\n", error);
  107. mainmutex.lock();
  108. runmain = false;
  109. mainmutex.unlock();
  110. linemutex.lock();
  111. printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
  112. getnextline = true;
  113. linemutex.unlock();
  114. printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
  115. linecv.notify_all();
  116. return;
  117. }
  118. }
  119. if (cmdret.type & CmdMan::rettype::error) {
  120. printMessage(Json::writeString(wbuilder, cmdret.msg), error);
  121. mainmutex.lock();
  122. runmain = false;
  123. mainmutex.unlock();
  124. linemutex.lock();
  125. printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
  126. getnextline = true;
  127. linemutex.unlock();
  128. printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
  129. linecv.notify_all();
  130. }
  131. if (cmdret.type & CmdMan::rettype::close) {
  132. /* TODO i dunno */
  133. mainmutex.lock();
  134. runmain = false;
  135. mainmutex.unlock();
  136. linemutex.lock();
  137. printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
  138. getnextline = true;
  139. linemutex.unlock();
  140. printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
  141. linecv.notify_all();
  142. }
  143. if (cmdret.type & CmdMan::rettype::connect) {
  144. ipstring = cmdret.msg["address"].asString();
  145. port = cmdret.msg["port"].asUInt();
  146. if (connect()) {
  147. runnetwork = true;
  148. tnetwork = std::thread(&BatchIoMan::networkMain, this);
  149. // put new commands into global vector
  150. localmutex.lock();
  151. printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug);
  152. localinput.push_back("version");
  153. cmdman.stateSetConnectionOk();
  154. localmutex.unlock();
  155. printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug);
  156. localcv.notify_all();
  157. }
  158. }
  159. if (cmdret.type & CmdMan::rettype::exit) {
  160. mainmutex.lock();
  161. runmain = false;
  162. mainmutex.unlock();
  163. linemutex.lock();
  164. printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
  165. getnextline = true;
  166. linemutex.unlock();
  167. printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
  168. linecv.notify_all();
  169. return;
  170. }
  171. if (cmdret.nextcommand.size()) {
  172. localmutex.lock();
  173. printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug);
  174. localinput.push_back(cmdret.nextcommand);
  175. localmutex.unlock();
  176. printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug);
  177. localcv.notify_all();
  178. }
  179. }
  180. /* modified handleOutCmdResponse to fetch next command and abort on error */
  181. void BatchIoMan::handleOutCmdResponse(CmdMan::CmdRet cmdret, std::vector<std::string> &toput) {
  182. if (cmdret.type & CmdMan::rettype::close) {
  183. // connection closed, stop network thread and shutdown any operations remaining
  184. networkmutex.lock();
  185. runnetwork = false;
  186. networkmutex.unlock();
  187. disconnect();
  188. tnetwork.join();
  189. if (cmdret.nextcommand.size()) {
  190. toput.push_back(cmdret.nextcommand);
  191. }
  192. }
  193. if (cmdret.type & CmdMan::rettype::error) {
  194. printMessage(Json::writeString(wbuilder, cmdret.msg), error);
  195. mainmutex.lock();
  196. runmain = false;
  197. mainmutex.unlock();
  198. linemutex.lock();
  199. printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
  200. getnextline = true;
  201. linemutex.unlock();
  202. printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
  203. linecv.notify_all();
  204. return;
  205. }
  206. if (cmdret.type & CmdMan::rettype::print) {
  207. printMessage(Json::writeString(wbuilder, cmdret.msg), normal);
  208. }
  209. if (cmdret.type & CmdMan::rettype::send) {
  210. printMessage(string(__PRETTY_FUNCTION__) + string(" send new cmd"), debug);
  211. if (cmdret.nextcommand.size()) {
  212. toput.push_back(cmdret.nextcommand);
  213. }
  214. }
  215. if (!(cmdret.type & CmdMan::rettype::send)) {
  216. // only fetch next line if we did not send a new command on our own
  217. // if we managed to get here, get next command from file
  218. linemutex.lock();
  219. printMessage(string(__PRETTY_FUNCTION__) + string(" get linemutex"), debug);
  220. getnextline = true;
  221. linemutex.unlock();
  222. printMessage(string(__PRETTY_FUNCTION__) + string(" release linemutex"), debug);
  223. linecv.notify_all();
  224. }
  225. }
  226. /* main user input loop */
  227. void BatchIoMan::run() {
  228. std::string line;
  229. printMessage(string(__PRETTY_FUNCTION__) + " begin", debug);
  230. std::unique_lock<std::mutex> ulock;
  231. runmain = true;
  232. mainmutex.lock();
  233. while (runmain) {
  234. mainmutex.unlock();
  235. line.erase();
  236. ulock = std::unique_lock<std::mutex>(linemutex);
  237. while (!getnextline && runmain) {
  238. linecv.wait(ulock);
  239. }
  240. if (!runmain)
  241. break;
  242. printMessage(string(__PRETTY_FUNCTION__) + " fetch next line", debug);
  243. while (!line.size()) {
  244. // skip empty lines until either eof or non-empty line
  245. if (batchin.eof()) {
  246. line = "exit";
  247. } else
  248. std::getline(batchin, line);
  249. }
  250. getnextline = false;
  251. linemutex.unlock();
  252. localmutex.lock();
  253. printMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"), debug);
  254. localinput.push_back(line);
  255. localmutex.unlock();
  256. printMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"), debug);
  257. localcv.notify_all();
  258. mainmutex.lock();
  259. }
  260. mainmutex.unlock();
  261. }
  262. std::string BatchIoMan::printJson(Json::Value root) {
  263. map<string, std::string (BatchIoMan::*)(Json::Value)>::iterator it = printmap.find(root["command"].asString());
  264. if (it == printmap.end()) {
  265. // this should never happen outside of development
  266. printMessage(string(__PRETTY_FUNCTION__) + " unknown command \"" + root["command"].asString() + "\".\nensure code is implemented.", debug);
  267. return "";
  268. }
  269. return (this->*(printmap[root["command"].asString()]))(root);
  270. }
  271. std::string BatchIoMan::printError(Json::Value root) { return std::string("Error: ") + root["error"].asString(); }
  272. std::string BatchIoMan::printConnect(Json::Value root) {
  273. if (!root["accept"].asBool()) {
  274. return std::string("Couldnt connect to ") + root["address"].asString() + ":" + std::to_string(root["port"].asUInt()) + "\n" +
  275. "Reason: " + root["error"].asString();
  276. }
  277. return "";
  278. }
  279. std::string BatchIoMan::printHelp(Json::Value root) {
  280. std::string ret = std::string("Available commands are: ") + "\n";
  281. for (Json::Value i : root["names"])
  282. ret += i.asString() + "\n";
  283. return ret;
  284. }
  285. std::string BatchIoMan::printStatus(Json::Value root) { return std::string("Server reports status: ") + root["response"].asString(); }
  286. std::string BatchIoMan::printDisconnect(Json::Value root) {
  287. if (!root["accept"].asBool()) {
  288. return "Disconnect failed.";
  289. } else {
  290. return "Disconnect successful.";
  291. }
  292. }
  293. std::string BatchIoMan::printPut(Json::Value root) {
  294. if (!root["accept"].asBool()) {
  295. if (root.isMember("file")) {
  296. return std::string("Upload request for file ") + root["file"].asString() + " failed: " + root["error"].asString();
  297. } else {
  298. return std::string("Upload request failed: ") + root["error"].asString();
  299. }
  300. } else
  301. return std::string("Begin uploading file ") + root["file"].asString();
  302. }
  303. std::string BatchIoMan::printGet(Json::Value root) {
  304. if (!root["accept"].asBool()) {
  305. if (root.isMember("file")) {
  306. return std::string("Download request for file ") + root["file"].asString() + " failed: " + root["error"].asString();
  307. } else {
  308. return std::string("Download request failed: ") + root["error"].asString();
  309. }
  310. } else
  311. return std::string("Begin downloading file ") + root["file"].asString();
  312. }
  313. std::string BatchIoMan::printList(Json::Value root) {
  314. std::string ret;
  315. if (!root["accept"].asBool()) {
  316. ret = std::string("Listing files failed: ") + root["error"].asString();
  317. } else {
  318. ret = std::string("Listing files stored on server: ") + "\n";
  319. for (Json::Value i : root["names"])
  320. ret += i.asString() + "\n";
  321. ret += "End of list.";
  322. }
  323. return ret;
  324. }
  325. std::string BatchIoMan::printVersion(Json::Value root) {
  326. if (!root["accept"].asBool()) {
  327. return std::string("Version check failed. Server reports ") + root["serverversion"].asString() + " but client is " + root["clientversion"].asString();
  328. } else
  329. return "Version check ok.";
  330. }
  331. std::string BatchIoMan::printLogin(Json::Value root) {
  332. if (!root["accept"].asBool()) {
  333. return std::string("Login failed: ") + root["error"].asString();
  334. } else
  335. return "Login ok.";
  336. }
  337. std::string BatchIoMan::printSignup(Json::Value root) {
  338. if (!root["accept"].asBool()) {
  339. return std::string("Signup failed: ") + root["error"].asString();
  340. } else
  341. return "Signup ok. You are now logged in.";
  342. }
  343. std::string BatchIoMan::printDeleteme(Json::Value root) {
  344. if (!root["accept"].asBool()) {
  345. return std::string("User deletion failed: ") + root["error"].asString();
  346. } else
  347. return "User deletion ok. You are now disconnected from the server.";
  348. }
  349. std::string BatchIoMan::printPutdata(Json::Value root) { return ""; }
  350. std::string BatchIoMan::printGetdata(Json::Value root) { return ""; }
  351. std::string BatchIoMan::printListdata(Json::Value root) { return ""; }
  352. std::string BatchIoMan::printHead(Json::Value root) {
  353. if (!root["accept"].asBool())
  354. return std::string("Request of the first four bytes failed. ") + root["error"].asString();
  355. else
  356. return std::string("First four bytes of file ") + root["file"].asString() + " are: " + root["data"].asString();
  357. }
  358. std::string BatchIoMan::printDeletefile(Json::Value root) {
  359. if (!root["accept"].asBool())
  360. return std::string("Deletion of file ") + root["file"].asString() + " failed. " + root["error"].asString();
  361. else
  362. return std::string("File ") + root["file"].asString() + " deleted succesfully";
  363. }
  364. std::string BatchIoMan::printKeyfile(Json::Value root) {
  365. if (!root["accept"].asBool())
  366. return std::string("Couldnt select keyfile ") + root["file"].asString() + ": " + root["error"].asString();
  367. else
  368. return std::string("Using keyfile ") + root["file"].asString();
  369. }
  370. std::string BatchIoMan::printClosekey(Json::Value root) {
  371. if (!root["accept"].asBool())
  372. return std::string("Failed to close key: ") + root["error"].asString();
  373. else
  374. return "Key closed.";
  375. }