ioman.cpp 11 KB

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