ioman.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. #include "../include/global.h"
  2. #include "../include/ioman.h"
  3. #include <boost/asio.hpp>
  4. #include <iostream>
  5. #include <boost/algorithm/string.hpp>
  6. #include <string>
  7. #include <vector>
  8. #include <readline/history.h>
  9. #include <readline/readline.h>
  10. using std::string;
  11. using std::vector;
  12. using boost::asio::ip::tcp;
  13. using boost::asio::buffer;
  14. IoMan::IoMan(char *ipcstring) : cmdman(fileman) {
  15. ipstring = std::string(ipcstring);
  16. port = 1234;
  17. tcpsock = new tcp::socket(ios);
  18. connected = false;
  19. /* to be put elsewhere */
  20. /* setup json stuff */
  21. Json::CharReaderBuilder rbuilder;
  22. wbuilder.settings_["indentation"] = "";
  23. reader = rbuilder.newCharReader();
  24. runnetwork = false;
  25. runinput = false;
  26. runresponse = false;
  27. startlist = false;
  28. versionstatus = off;
  29. loginstatus = off;
  30. }
  31. IoMan::~IoMan() {
  32. runnetwork = false;
  33. runinput = false;
  34. runresponse = false;
  35. tnetwork.join();
  36. tinput.join();
  37. tresponse.join();
  38. if(connected) {
  39. disconnect();
  40. }
  41. delete tcpsock;
  42. delete reader;
  43. }
  44. void IoMan::printNormalMessage(string nouse) {
  45. }
  46. void IoMan::printErrorMessage(string nouse) {
  47. }
  48. void IoMan::printDebugMessage(string nouse) {
  49. }
  50. bool IoMan::connect() {
  51. tcp::endpoint *ep;
  52. ep = new tcp::endpoint(boost::asio::ip::address::from_string(ipstring), 1234);
  53. // establish connection
  54. printDebugMessage("IoMan::connect() connecting to " + ipstring);
  55. tcpsock->connect(*ep, errcode);
  56. if (errcode) {
  57. delete ep;
  58. printErrorMessage("IoMan::connect() couldnt connect to " + ipstring + "\n" + errcode.message());
  59. return false;
  60. }
  61. connected = true;
  62. delete ep;
  63. return true;
  64. }
  65. void IoMan::disconnect() {
  66. printDebugMessage("IoMan::disconnect()");
  67. tcpsock->close();
  68. connected = false;
  69. }
  70. bool IoMan::init() {
  71. CmdMan::CmdRet ret;
  72. string work;
  73. Json::Value root;
  74. printDebugMessage("IoMan::Init() begin");
  75. if(!connect()) return false;
  76. printDebugMessage("IoMan::Init() versioncheck");
  77. localmutex.lock();
  78. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"));
  79. localinput.push_back("version " + protocolVersion);
  80. localmutex.unlock();
  81. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"));
  82. printDebugMessage("IoMan::Init() begin");
  83. runnetwork = true;
  84. runinput = true;
  85. runresponse = true;
  86. tnetwork = std::thread(&IoMan::networkMain, this);
  87. tinput = std::thread(&IoMan::inputMain, this);
  88. tresponse = std::thread(&IoMan::responseMain, this);
  89. while(versionstatus == off);
  90. if(versionstatus == err) {
  91. runnetwork = false;
  92. runinput = false;
  93. runresponse = false;
  94. return false;
  95. }
  96. printWelcomeMessage();
  97. return true;
  98. }
  99. void IoMan::networkMain() {
  100. vector<Json::Value> toput;
  101. char *recvjson;
  102. Json::Value root;
  103. unsigned int jsonsize, readsize;
  104. printDebugMessage("IoMan::networkMain() begin");
  105. while(runnetwork) {
  106. std::this_thread::yield();
  107. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  108. /*
  109. read from network until \n
  110. try to parse json
  111. - output error if not ok
  112. store all ok json in local vector
  113. get networkmutex
  114. put all local jsons into network vector
  115. release networkmutex
  116. */
  117. // read from network
  118. readsize = boost::asio::read_until(*tcpsock, recvbuf, '\n', errcode);
  119. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" asio::read() ok"));
  120. if (errcode && errcode != boost::asio::error::eof) {
  121. printErrorMessage("IoMan::networkMain() couldnt read json data\n" + errcode.message());
  122. continue;
  123. }
  124. recvjson = (char *)(boost::asio::buffer_cast<const char *>(recvbuf.data()));
  125. while(strchr(recvjson, '\n')) {
  126. // parse
  127. jsonsize = strchr(recvjson, '\n') - recvjson + 1;
  128. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" found jsondata ") + string(recvjson));
  129. if (!reader->parse(recvjson, recvjson + jsonsize, &root, &jsonerror)) {
  130. printErrorMessage("IoMan::networkMain() couldnt parse json data: " + jsonerror);
  131. recvbuf.consume(jsonsize);
  132. continue;
  133. }
  134. recvbuf.consume(jsonsize);
  135. readsize -= jsonsize;
  136. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" remaining recvbuf ") + string(boost::asio::buffer_cast<const char *>(recvbuf.data())));
  137. for(int i = 0; i < jsonsize; i++) recvjson++;
  138. // store locally
  139. toput.push_back(root);
  140. }
  141. if(toput.size()){
  142. // put into global vector
  143. netmutex.lock();
  144. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get netmutex"));
  145. netinput.insert(netinput.end(), toput.begin(), toput.end());
  146. netmutex.unlock();
  147. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release netmutex"));
  148. }
  149. // clean up local stuff
  150. toput = vector<Json::Value>();
  151. recvbuf.consume(readsize);
  152. }
  153. }
  154. void IoMan::inputMain() {
  155. vector<string> toprocess;
  156. string command;
  157. vector<string> args;
  158. CmdMan::CmdRet cmdret;
  159. size_t prev, index, quot;
  160. printDebugMessage("IoMan::inputMain() begin");
  161. while(runinput) {
  162. std::this_thread::yield();
  163. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  164. /*
  165. get inputmutex
  166. read all input vector into local vector
  167. release inputmutex
  168. process inputs
  169. send to server if required
  170. */
  171. // read into local vector
  172. if(localinput.size()) {
  173. localmutex.lock();
  174. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" has localmutex"));
  175. toprocess = vector<string>(localinput);
  176. localinput = vector<string>();
  177. localmutex.unlock();
  178. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"));
  179. }
  180. // printDebugMessage(string("have ") + std::to_string(toprocess.size()) + string(" commands"));
  181. // process
  182. for(string cmd : toprocess) {
  183. args = vector<string>();
  184. if((index = cmd.find(" ")) == string::npos) {
  185. // only command no args
  186. command = cmd;
  187. }
  188. else {
  189. command = cmd.substr(0, index);
  190. //~ index++;
  191. while(true) {
  192. // find first char thats not a space
  193. while(cmd[index] == ' ') {
  194. index++;
  195. // bounds check
  196. if(index == cmd.size()) goto end_tokenizing;
  197. }
  198. cmd = cmd.substr(index);
  199. if(cmd[0] == '\"') {
  200. // quoted string
  201. index = cmd.find("\"");
  202. args.push_back(cmd.substr(1, index-1));
  203. index++;
  204. /*
  205. tokens.push_back(cmd.substr(0, ++index));
  206. */
  207. // char after closing quote should be space while within bounds
  208. if(index == cmd.size()) goto end_tokenizing;
  209. }
  210. else {
  211. // non-quoted string
  212. index = cmd.find(" ");
  213. if(index == string::npos) { // no spaces, last arg
  214. args.push_back(cmd);
  215. goto end_tokenizing;
  216. }
  217. else {
  218. args.push_back(cmd.substr(0, index));
  219. }
  220. }
  221. }
  222. end_tokenizing: ;
  223. }
  224. cmdret = cmdman.execute(command, args);
  225. // determine wether to send something and do so if required
  226. switch(cmdret.type) {
  227. case CmdMan::rettype::send: {
  228. printDebugMessage("IoMan::inputMain() sending json \"" + cmdret.msg + "\"");
  229. boost::asio::write(*tcpsock, buffer(cmdret.msg + "\n"), errcode);
  230. if (errcode) {
  231. printErrorMessage("IoMan::inputMain() couldnt send json data\n" + errcode.message() + "\n");
  232. continue;
  233. }
  234. break;
  235. }
  236. case CmdMan::rettype::notsend: {
  237. printNormalMessage(cmdret.msg);
  238. break;
  239. }
  240. case CmdMan::rettype::error: {
  241. printErrorMessage(cmdret.msg);
  242. break;
  243. }
  244. }
  245. }
  246. // clean up local stuff
  247. toprocess = vector<string>();
  248. }
  249. }
  250. void IoMan::responseMain() {
  251. vector<Json::Value> toprocess;
  252. vector<string> toput;
  253. CmdMan::CmdRet cmdret;
  254. printDebugMessage("IoMan::responseMain() begin");
  255. while(runresponse) {
  256. std::this_thread::yield();
  257. std::this_thread::sleep_for(std::chrono::milliseconds(10));
  258. /*
  259. get networkmutex
  260. read all network vector into local vector
  261. release networkmutex
  262. process all jsons
  263. process putdata
  264. process getdata
  265. process listdata
  266. get inputmutex
  267. place new commands into input vector
  268. release inputmutex
  269. */
  270. // read into local vector
  271. if(netinput.size()) {
  272. netmutex.lock();
  273. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get netmutex"));
  274. toprocess = vector<Json::Value>(netinput);
  275. netinput = vector<Json::Value>();
  276. netmutex.unlock();
  277. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release netmutex"));
  278. }
  279. // process jsons
  280. for(Json::Value root : toprocess) {
  281. cmdret = cmdman.handle(root);
  282. switch(cmdret.type) {
  283. case CmdMan::rettype::startlist: {
  284. startlist = true;
  285. break;
  286. }
  287. case CmdMan::rettype::stoplist: {
  288. startlist = false;
  289. break;
  290. }
  291. case CmdMan::rettype::close: {
  292. /* TODO i dunno */
  293. runmain = false;
  294. break;
  295. }
  296. case CmdMan::rettype::error: {
  297. if(versionstatus == off) versionstatus = err;
  298. else if(loginstatus == off) loginstatus = err;
  299. printErrorMessage(cmdret.msg);
  300. break;
  301. }
  302. case CmdMan::rettype::seton: {
  303. if(versionstatus == off) versionstatus = on;
  304. else loginstatus = on;
  305. }
  306. case CmdMan::rettype::notsend: {
  307. printNormalMessage(cmdret.msg);
  308. break;
  309. }
  310. case CmdMan::rettype::send: {
  311. toput.push_back(cmdret.msg);
  312. break;
  313. }
  314. }
  315. }
  316. if(toput.size()) {
  317. // put new commands into global vector
  318. localmutex.lock();
  319. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"));
  320. localinput.insert(localinput.end(), toput.begin(), toput.end());
  321. localmutex.unlock();
  322. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"));
  323. }
  324. // clean up local stuff
  325. toprocess = vector<Json::Value>();
  326. toput = vector<string>();
  327. }
  328. }
  329. void IoMan::run() {
  330. printDebugMessage("IoMan::run() begin");
  331. char *line = NULL, *user = NULL, *pass = NULL;
  332. vector<string> tokens;
  333. string work, command;
  334. CmdMan::CmdRet cmdret;
  335. Json::Value root;
  336. runmain = true;
  337. while(!user) {
  338. user = readline(getUserPrompt().c_str());
  339. printErrorMessage("Using user: " + string(user));
  340. }
  341. while(!pass) {
  342. pass = readline(getPassPrompt().c_str());
  343. printErrorMessage("Using pass: " + string(pass));
  344. }
  345. printDebugMessage("IoMan::run() login");
  346. localmutex.lock();
  347. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"));
  348. localinput.push_back("login " + string(user) + " " + string(pass));
  349. localmutex.unlock();
  350. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"));
  351. free(user);
  352. free(pass);
  353. while(loginstatus == off);
  354. if(loginstatus == err) return;
  355. while(runmain) {
  356. free(line);
  357. line = readline(getCmdPrompt().c_str());
  358. if(!runmain) break;
  359. // if no input, do not add to history, and go to reading next line
  360. if (strlen(line) == 0) {
  361. continue;
  362. }
  363. // split input line into tokens
  364. boost::algorithm::split(tokens, std::string(line),
  365. boost::algorithm::is_any_of(" "),
  366. boost::algorithm::token_compress_on);
  367. // if input contains only spaces, do not add to history, and go to reading
  368. // next line
  369. if (tokens.size() < 1) {
  370. continue;
  371. }
  372. // add the line to history
  373. add_history(line);
  374. localmutex.lock();
  375. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" get localmutex"));
  376. localinput.push_back(line);
  377. localmutex.unlock();
  378. printDebugMessage(string(__PRETTY_FUNCTION__) + string(" release localmutex"));
  379. if(!connected) break;
  380. }
  381. free(line);
  382. }