datalite.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. /*
  2. * This file is the main code of Timeless
  3. * Copyright (C) <2019> <alkeon> [alkeon@autistici.org]
  4. *
  5. * Texdi is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * Texdi is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with timeless. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. #include "datalite.h"
  20. #include "json.hpp"
  21. #include <sqlite3.h>
  22. #include <iostream>
  23. #include <fstream>
  24. #include <vector>
  25. using namespace std;
  26. using json = nlohmann::json;
  27. static int callback(void *NotUsed, int argc, char **argv, char **azColName){
  28. return 0;
  29. }
  30. int datalite::create(){
  31. sqlite3 * sq;
  32. int rc = sqlite3_open(_file.c_str(), &sq);
  33. int result = 0;
  34. if (!rc){
  35. char *zErrMsg = 0;
  36. string sql = "DROP TABLE IF EXISTS NEWS; \
  37. CREATE TABLE NEWS( \
  38. LINK TEXT NOT NULL, \
  39. TITLE TEXT NOT NULL, \
  40. DESCRIPTION TEXT NOT NULL, \
  41. MARKED INTEGER, \
  42. UNIQUE (LINK,TITLE,DESCRIPTION) \
  43. );";
  44. rc = sqlite3_exec(sq, sql.c_str(), callback, 0, &zErrMsg);
  45. if (rc == SQLITE_OK)
  46. result = SQLITE_OK;
  47. else{
  48. sqlite3_free(zErrMsg);
  49. result = rc;
  50. }
  51. } else
  52. result = 1;
  53. sqlite3_close(sq);
  54. string channel = _file + "_channel";
  55. rc = sqlite3_open(channel.c_str(), &sq);
  56. result = 0;
  57. if (!rc){
  58. char *zErrMsg = 0;
  59. string sql = "DROP TABLE IF EXISTS CHANNEL; \
  60. CREATE TABLE CHANNEL( \
  61. URL TEXT NOT NULL UNIQUE, \
  62. TITLE TEXT NOT NULL UNIQUE \
  63. );";
  64. rc = sqlite3_exec(sq, sql.c_str(), callback, 0, &zErrMsg);
  65. if (rc == SQLITE_OK)
  66. result = SQLITE_OK;
  67. else{
  68. sqlite3_free(zErrMsg);
  69. result = rc;
  70. }
  71. } else
  72. result = 1;
  73. sqlite3_close(sq);
  74. return result;
  75. }
  76. datalite::datalite(const string& file): _file(file){
  77. _position = 1;
  78. _last_position = 1;
  79. int result = create();
  80. if(result != 0)
  81. throw datalite::Invalid("Couldn't create database.\n ERROR CODE: " + to_string(result));
  82. }
  83. /*
  84. * Return:
  85. * 0 : failed
  86. * 1 : OK
  87. * 2 : inserted before
  88. */
  89. int datalite::insert_row(const string& link, const string& title,
  90. const string& description){
  91. sqlite3 * sq;
  92. int rc = sqlite3_open(_file.c_str(), &sq);
  93. int result = 0;
  94. if (!rc){
  95. sqlite3_stmt * res;
  96. string sql = "INSERT INTO NEWS VALUES ('";
  97. sql += link + "', '" + title + "', '" + description + "', 0);";
  98. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  99. if (rc == SQLITE_OK) {
  100. int step = sqlite3_step(res);
  101. if(step == SQLITE_CONSTRAINT)
  102. result = 2;
  103. else if(step == SQLITE_DONE)
  104. result = 1;
  105. else if(step == SQLITE_OK)
  106. result = 1;
  107. }else
  108. result = 2;
  109. sqlite3_finalize(res);
  110. }
  111. sqlite3_close(sq);
  112. return result;
  113. }
  114. /*
  115. * Return:
  116. * 0 : failed
  117. * 1 : OK
  118. * 2 : inserted before
  119. */
  120. int datalite::bulk_insert(const vector<string>& links, const vector<string>& titles,
  121. const vector<string>& descriptions){
  122. int result = 0;
  123. if(links.size() > 0){
  124. sqlite3 * sq;
  125. int rc = sqlite3_open(_file.c_str(), &sq);
  126. if (!rc){
  127. sqlite3_stmt * res;
  128. string sql = "INSERT OR IGNORE INTO NEWS VALUES ('";
  129. sql += links[0] + "', '" + titles[0] + "', '"+ descriptions[0] +"', 0)";
  130. for(unsigned i = 1; i < links.size(); ++i)
  131. sql += ",('" + links[i] + "', '" + titles[i] + "', '"+ descriptions[i] +"', 0)";
  132. sql+= ";";
  133. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  134. if (rc == SQLITE_OK)
  135. sqlite3_step(res);
  136. else
  137. result = 2;
  138. sqlite3_finalize(res);
  139. }
  140. sqlite3_close(sq);
  141. }
  142. return result;
  143. }
  144. int datalite::delete_news(){
  145. sqlite3 * sq;
  146. int rc = sqlite3_open(_file.c_str(), &sq);
  147. int result = 0;
  148. if (!rc){
  149. sqlite3_stmt * res;
  150. string sql = "DELETE FROM NEWS WHERE MARKED=0;";
  151. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  152. if (rc == SQLITE_OK) {
  153. int step = sqlite3_step(res);
  154. if(step == SQLITE_CONSTRAINT)
  155. result = 2;
  156. else if(step == SQLITE_DONE)
  157. result = 1;
  158. else if(step == SQLITE_OK)
  159. result = 1;
  160. }else
  161. result = 2;
  162. sqlite3_finalize(res);
  163. }
  164. sqlite3_close(sq);
  165. return result;
  166. }
  167. void datalite::show_news(){
  168. string sql = "SELECT LINK, TITLE, DESCRIPTION, MARKED, rowid FROM NEWS "
  169. "ORDER BY rowid DESC;";
  170. sqlite3 *sq;
  171. int rc = sqlite3_open(_file.c_str(), &sq);
  172. vector<int64_t> vector_positions;
  173. if (!rc){
  174. sqlite3_stmt *res;
  175. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  176. if (rc == SQLITE_OK) {
  177. int step = sqlite3_step(res);
  178. int option = 4;
  179. int iterations = 0;
  180. vector<long long> rowids;
  181. bool repeat = false;
  182. int i = 0;
  183. do{
  184. if(!repeat){
  185. rowids = vector<long long>();
  186. i = 0;
  187. }
  188. while (step == SQLITE_ROW && i < 3 && !repeat){
  189. const char * rowid = (char *) sqlite3_column_text(res,4);
  190. if(rowid != NULL){
  191. string rowid_s(rowid);
  192. rowids.push_back(stoll(rowid_s));
  193. }
  194. step = sqlite3_step(res);
  195. ++i;
  196. }
  197. int aux = 0;
  198. if(repeat) repeat = false;
  199. for(vector<long long>::iterator it = rowids.begin(); it != rowids.end(); ++it){
  200. cout << "\n" << aux << "----------------" << endl;
  201. cout << get_one_new(*it) << endl;
  202. ++aux;
  203. }
  204. if(i >= 3){
  205. cout << "\nUse news number to un/mark one of it" << endl;
  206. cout << "Do you want more news" << endl;
  207. cout << "3.- Yes" << endl;
  208. cout << "4.- No" << endl;
  209. cin >> option;
  210. cout << option << endl;
  211. if(option < 3 && option >= 0){
  212. vector_positions.push_back(rowids[option]);
  213. repeat = true;
  214. option = 3;
  215. }else if(option > 4 or option < 0){
  216. repeat = true;
  217. option = 3;
  218. }
  219. } else
  220. option = 3;
  221. ++iterations;
  222. }while(option == 3 && step == SQLITE_ROW);
  223. }
  224. sqlite3_finalize(res);
  225. }
  226. sqlite3_close(sq);
  227. for(unsigned i = 0; i < vector_positions.size(); ++i)
  228. set_mark(vector_positions[i]);
  229. }
  230. int datalite::get_mark(int64_t position){
  231. sqlite3 *sq;
  232. int rc = sqlite3_open(_file.c_str(), &sq);
  233. string link = "0";
  234. if (!rc){
  235. sqlite3_stmt *res;
  236. string sql = "SELECT MARKED FROM NEWS WHERE rowid=" + to_string(position);
  237. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  238. if (rc == SQLITE_OK){
  239. sqlite3_step(res);
  240. const char * marked = (char *) sqlite3_column_text(res,0);
  241. if(marked != NULL) link = string(marked);
  242. }
  243. sqlite3_finalize(res);
  244. }
  245. sqlite3_close(sq);
  246. return stoi(link);
  247. }
  248. int datalite::set_mark(int64_t position){
  249. sqlite3 *sq;
  250. int rc = sqlite3_open(_file.c_str(), &sq);
  251. int result = 0;
  252. if (!rc){
  253. sqlite3_stmt *res;
  254. string sql = "UPDATE NEWS SET MARKED=" + to_string((get_mark(position)
  255. + 1) % 2) + " where rowid=" + to_string(position);
  256. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  257. if(rc == SQLITE_OK){
  258. sqlite3_step(res);
  259. result = SQLITE_OK;
  260. } else result = rc;
  261. sqlite3_finalize(res);
  262. }
  263. sqlite3_close(sq);
  264. return result;
  265. }
  266. /*
  267. * Error: line.size = 0
  268. * Success: line.size > 0
  269. *
  270. */
  271. string datalite::get_new_line(){
  272. sqlite3 *sq;
  273. int rc = sqlite3_open(_file.c_str(), &sq);
  274. string link;
  275. if (!rc){
  276. sqlite3_stmt *res;
  277. string sql = "SELECT LINK FROM NEWS WHERE rowid=" + to_string(_position);
  278. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  279. if (rc == SQLITE_OK) {
  280. sqlite3_step(res);
  281. const char * retri = (char *) sqlite3_column_text(res,0);
  282. if(retri != NULL){
  283. link = string(retri);
  284. ++_position;
  285. }
  286. }
  287. sqlite3_finalize(res);
  288. }
  289. sqlite3_close(sq);
  290. return link;
  291. }
  292. /*
  293. * Error: line.size = 0
  294. * Success: line.size > 0
  295. *
  296. */
  297. string datalite::get_new_channel(){
  298. std::ifstream in(_file + "_channel");
  299. json j = json::parse(in);
  300. string channel = j["urls"].at(_position_channel);
  301. ++_position_channel;
  302. return channel;
  303. }
  304. /*
  305. * Error: line.size = 0
  306. * Success: line.size > 0
  307. *
  308. */
  309. string datalite::get_link(int64_t position){
  310. sqlite3 *sq;
  311. int rc = sqlite3_open(_file.c_str(), &sq);
  312. string link;
  313. if (!rc){
  314. sqlite3_stmt *res;
  315. string sql = "SELECT LINK FROM NEWS WHERE rowid=" + to_string(position);
  316. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  317. if (rc == SQLITE_OK) {
  318. sqlite3_step(res);
  319. const char * retri = (char *) sqlite3_column_text(res,0);
  320. if(retri != NULL) link = string(retri);
  321. }
  322. sqlite3_finalize(res);
  323. }
  324. sqlite3_close(sq);
  325. return link;
  326. }
  327. /*
  328. * Error: line.size = 0
  329. * Success: line.size > 0
  330. *
  331. */
  332. string datalite::get_channel(int64_t position){
  333. std::ifstream in(_file + "_channel");
  334. json j = json::parse(in);
  335. return j["urls"].at(position);
  336. }
  337. bool datalite::is_valid_line(){
  338. bool valid = false;
  339. if(_position <= _last_position) valid = true;
  340. else {
  341. _last_position = get_last_position();
  342. if(_position <= _last_position) valid = true;
  343. else valid = false;
  344. }
  345. return valid;
  346. }
  347. bool datalite::is_valid_channel(){
  348. bool valid = false;
  349. if(_position_channel < _last_position_channel) valid = true;
  350. else {
  351. _last_position_channel = get_last_channel();
  352. if(_position_channel <= _last_position_channel) valid = true;
  353. else valid = false;
  354. }
  355. return valid;
  356. }
  357. /*
  358. * Return rowid if worked and -1 if doesn't
  359. *
  360. */
  361. int64_t datalite::get_last_position(){
  362. if(_position > _last_position){
  363. sqlite3 *sq;
  364. int rc = sqlite3_open(_file.c_str(), &sq);
  365. if (!rc){
  366. sqlite3_stmt *res;
  367. string sql = "SELECT rowid FROM NEWS WHERE rowid=(SELECT MAX(rowid)"
  368. " FROM NEWS)";
  369. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  370. if (rc == SQLITE_OK) {
  371. sqlite3_step(res);
  372. const char *retri = (char *) sqlite3_column_text(res,0);
  373. if(retri != NULL){
  374. string text(retri);
  375. _last_position = stoll(text);
  376. }
  377. }
  378. sqlite3_finalize(res);
  379. }
  380. sqlite3_close(sq);
  381. }
  382. return _last_position;
  383. }
  384. /*
  385. * Return rowid if worked and -1 if doesn't
  386. *
  387. */
  388. int64_t datalite::get_last_channel(){
  389. if(_position_channel > _last_position_channel){
  390. std::ifstream in(_file + "_channel");
  391. json j = json::parse(in);
  392. int i = -1;
  393. for(auto json_building : j["urls"]){
  394. ++i;
  395. }
  396. _last_position_channel = i;
  397. }
  398. return _last_position_channel;
  399. }
  400. void datalite::set_position(int64_t position){
  401. if(position <= _last_position) _position = position;
  402. else {
  403. _last_position = get_last_position();
  404. if(position <= _last_position) _position = position;
  405. else throw datalite::Invalid("Rowid greater than table rowid");
  406. }
  407. }
  408. datalite& datalite::operator=(datalite& src){
  409. if (this != &src) {
  410. _file = src.get_file();
  411. _position = src.get_position();
  412. _last_position = src.get_last_position();
  413. }
  414. return *this;
  415. }
  416. string datalite::get_title(const int64_t& position){
  417. sqlite3 *sq;
  418. int rc = sqlite3_open(_file.c_str(), &sq);
  419. string link;
  420. if (!rc){
  421. sqlite3_stmt *res;
  422. string sql = "SELECT TITLE FROM COB WHERE rowid=" + to_string(position);
  423. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  424. if (rc == SQLITE_OK) {
  425. sqlite3_step(res);
  426. const char * title = (char *) sqlite3_column_text(res,0);
  427. if(title != NULL)
  428. link = string(title);
  429. }
  430. sqlite3_finalize(res);
  431. }
  432. sqlite3_close(sq);
  433. return link;
  434. }
  435. string datalite::get_metainfo(const int64_t& position){
  436. sqlite3 *sq;
  437. int rc = sqlite3_open(_file.c_str(), &sq);
  438. string link;
  439. if (!rc){
  440. sqlite3_stmt *res;
  441. string sql = "SELECT DESCRIPTION FROM COB WHERE rowid=" + to_string(position);
  442. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  443. if (rc == SQLITE_OK) {
  444. sqlite3_step(res);
  445. const char * description = (char *) sqlite3_column_text(res,0);
  446. if(description != NULL)
  447. link = string(description);
  448. }
  449. sqlite3_finalize(res);
  450. }
  451. sqlite3_close(sq);
  452. return link;
  453. }
  454. void datalite::insert_datalite(datalite& db){
  455. int64_t position = db.get_position();
  456. db.set_position(1);
  457. cout << "Wait until insertion stop" << endl;
  458. while(db.is_valid_line()){
  459. string title = db.get_title(db.get_position());
  460. string metainfo = db.get_metainfo(db.get_position());
  461. insert_row(db.get_new_line(), title, metainfo);
  462. }
  463. cout << "Insertion finished" << endl;
  464. db.set_position(position);
  465. }
  466. /*
  467. * Return:
  468. * 0 : failed
  469. * 1 : OK
  470. * 2 : cancelled by user
  471. */
  472. int datalite::show_unique_database_fields(const string& sql){
  473. sqlite3 *sq;
  474. int rc = sqlite3_open(_file.c_str(), &sq);
  475. int result = 0;
  476. if (!rc){
  477. sqlite3_stmt *res;
  478. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  479. if (rc == SQLITE_OK) {
  480. int step = sqlite3_step(res);
  481. int option;
  482. do{
  483. int i = 0;
  484. while (step == SQLITE_ROW && i < 10) {
  485. char * text_c = (char *) sqlite3_column_text(res, 0);
  486. string text(text_c);
  487. if(_found_links.find(text) == _found_links.end()){
  488. cout << text << endl;
  489. _found_links.insert(text);
  490. }
  491. step = sqlite3_step(res);
  492. ++i;
  493. }
  494. if(i > 5){
  495. cout << "Do you want more links?\n"
  496. "1.- Yes\n"
  497. "2.- No" << endl;
  498. cin >> option;
  499. } else
  500. option = 1;
  501. }while(option == 1 && step == SQLITE_ROW);
  502. result = option;
  503. }
  504. sqlite3_finalize(res);
  505. }
  506. sqlite3_close(sq);
  507. return result;
  508. }
  509. string datalite::get_one_new(int64_t position){
  510. string result;
  511. sqlite3 *sq;
  512. int rc = sqlite3_open(_file.c_str(), &sq);
  513. string link;
  514. if (!rc){
  515. sqlite3_stmt *res;
  516. string sql = "SELECT TITLE, LINK, DESCRIPTION, MARKED FROM NEWS WHERE rowid=" + to_string(position);
  517. rc = sqlite3_prepare_v2(sq, sql.c_str(), -1, &res, 0);
  518. if (rc == SQLITE_OK) {
  519. sqlite3_step(res);
  520. char * retri = (char *) sqlite3_column_text(res, 3);
  521. string text(retri);
  522. if(text[0]== '1')
  523. cout << "\n MARKED(*)" << endl;
  524. retri = (char *) sqlite3_column_text(res, 0);
  525. if(retri != NULL) link = string(retri);
  526. result += "\n" + link + "\n\n";
  527. retri = (char *) sqlite3_column_text(res, 1);
  528. if(retri != NULL) link = string(retri);
  529. result += link + "\n\n";
  530. retri = (char *) sqlite3_column_text(res, 2);
  531. if(retri != NULL) link = string(retri);
  532. result += link;
  533. }
  534. sqlite3_finalize(res);
  535. }
  536. sqlite3_close(sq);
  537. return result;
  538. }