A tool for adding anime to your anidb list.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

340 lines
9.5KB

  1. #include <stddef.h>
  2. #include <sqlite3.h>
  3. #include "cache.h"
  4. #include "config.h"
  5. #include "uio.h"
  6. #include "ed2k.h"
  7. #include "util.h"
  8. static bool cache_did_init = false;
  9. #define sqlite_bind_goto(smt, name, type, ...) { \
  10. int sb_idx = sqlite3_bind_parameter_index(smt, name); \
  11. if (sb_idx == 0) { \
  12. uio_error("Cannot get named parameter for var: %s", name); \
  13. err = ERR_CACHE_SQLITE; \
  14. goto fail; \
  15. } \
  16. int sb_sret = sqlite3_bind_##type(smt, sb_idx, __VA_ARGS__); \
  17. if (sb_sret != SQLITE_OK) {\
  18. uio_error("Cannot bind to statement: %s", sqlite3_errmsg(cache_db));\
  19. err = ERR_CACHE_SQLITE;\
  20. goto fail;\
  21. } \
  22. }
  23. static sqlite3 *cache_db = NULL;
  24. static const char sql_create_table[] = "CREATE TABLE IF NOT EXISTS mylist ("
  25. "lid INTEGER NOT NULL PRIMARY KEY,"
  26. "fname TEXT NOT NULL,"
  27. "fsize INTEGER NOT NULL,"
  28. "ed2k TEXT NOT NULL,"
  29. "watchdate INTEGER,"
  30. "state INTEGER NOT NULL,"
  31. "moddate INTEGER NOT NULL DEFAULT (strftime('%s')),"
  32. "UNIQUE (fname, fsize) )";
  33. static const char sql_mylist_add[] = "INSERT INTO mylist "
  34. "(lid, fname, fsize, ed2k, watchdate, state) VALUES "
  35. "(:lid, :fname, :fsize, :ed2k, :watchdate, :state)";
  36. static const char sql_mylist_get[] = "SELECT * FROM mylist WHERE "
  37. "fsize=:fsize AND fname=:fname";
  38. static const char sql_mylist_update[] = "UPDATE mylist "
  39. "SET %s "
  40. "WHERE lid=:lid";
  41. #if 0
  42. static const char sql_has_tables[] = "SELECT 1 FROM sqlite_master "
  43. "WHERE type='table' AND tbl_name='mylist'";
  44. /* Return 0 if false, 1 if true, and -1 if error */
  45. static int cache_has_tables()
  46. {
  47. sqlite3_smt smt;
  48. int sret;
  49. sret = sqlite3_prepare_v2(cache_db, sql_has_tables,
  50. sizeof(sql_has_tables), &smt, NULL);
  51. if (sret != SQLITE_OK) {
  52. uio_error("Cannot prepare statement: %s", sqlite3_errmsg(cache_db));
  53. return -1;
  54. }
  55. sqlite3_step(&smt);
  56. // ehh fuck this, lets just use if not exists
  57. sret = sqlite3_finalize(&smt);
  58. if (sret != SQLITE_OK)
  59. uio_debug("sql3_finalize failed: %s", sqlite3_errmsg(cache_db));
  60. }
  61. #endif
  62. /*
  63. * Create database table(s)
  64. */
  65. static enum error cache_init_table()
  66. {
  67. sqlite3_stmt *smt;
  68. int sret;
  69. enum error err = NOERR;
  70. sret = sqlite3_prepare_v2(cache_db, sql_create_table,
  71. sizeof(sql_create_table), &smt, NULL);
  72. if (sret != SQLITE_OK) {
  73. uio_error("Cannot prepare statement: %s", sqlite3_errmsg(cache_db));
  74. return ERR_CACHE_SQLITE;
  75. }
  76. sret = sqlite3_step(smt);
  77. if (sret != SQLITE_DONE) {
  78. uio_error("sql3_step is not done: %s", sqlite3_errmsg(cache_db));
  79. err = ERR_CACHE_SQLITE;
  80. }
  81. sret = sqlite3_finalize(smt);
  82. if (sret != SQLITE_OK)
  83. uio_debug("sql3_finalize failed: %s", sqlite3_errmsg(cache_db));
  84. return err;
  85. }
  86. enum error cache_init()
  87. {
  88. char **db_path;
  89. enum error err;
  90. int sret;
  91. err = config_get("cachedb", (void**)&db_path);
  92. if (err != NOERR) {
  93. uio_error("Cannot get cache db path from args");
  94. return err;
  95. }
  96. uio_debug("Opening cache db: '%s'", *db_path);
  97. sret = sqlite3_open(*db_path, &cache_db);
  98. if (sret != SQLITE_OK) {
  99. uio_error("Cannot create sqlite3 database: %s", sqlite3_errstr(sret));
  100. sqlite3_close(cache_db); /* Even if arg is NULL, it's A'OK */
  101. return ERR_CACHE_SQLITE;
  102. }
  103. sqlite3_extended_result_codes(cache_db, 1);
  104. err = cache_init_table();
  105. if (err != NOERR)
  106. goto fail;
  107. cache_did_init = true;
  108. return NOERR;
  109. fail:
  110. cache_free();
  111. return err;
  112. }
  113. bool cache_is_init()
  114. {
  115. return cache_did_init;
  116. }
  117. void cache_free()
  118. {
  119. cache_did_init = false;
  120. sqlite3_close(cache_db);
  121. uio_debug("Closed cache db");
  122. }
  123. enum error cache_add(uint64_t lid, const char *fname,
  124. uint64_t fsize, const uint8_t *ed2k, uint64_t watchdate,
  125. enum mylist_state state)
  126. {
  127. char ed2k_str[ED2K_HASH_SIZE * 2 + 1];
  128. sqlite3_stmt *smt;
  129. int sret;
  130. enum error err = NOERR;
  131. sret = sqlite3_prepare_v2(cache_db, sql_mylist_add,
  132. sizeof(sql_mylist_add), &smt, NULL);
  133. if (sret != SQLITE_OK) {
  134. uio_error("Cannot prepare statement: %s", sqlite3_errmsg(cache_db));
  135. return ERR_CACHE_SQLITE;
  136. }
  137. util_byte2hex(ed2k, ED2K_HASH_SIZE, false, ed2k_str);
  138. sqlite_bind_goto(smt, ":lid", int64, lid);
  139. sqlite_bind_goto(smt, ":fname", text, fname, -1, SQLITE_STATIC);
  140. sqlite_bind_goto(smt, ":fsize", int64, fsize);
  141. sqlite_bind_goto(smt, ":ed2k", text, ed2k_str, -1, SQLITE_STATIC);
  142. sqlite_bind_goto(smt, ":watchdate", int64, watchdate);
  143. sqlite_bind_goto(smt, ":state", int64, state);
  144. sret = sqlite3_step(smt);
  145. if (sret != SQLITE_DONE) {
  146. if (sret == SQLITE_CONSTRAINT_PRIMARYKEY) {
  147. uio_debug("Attempted to add duplicate entry!");
  148. err = ERR_CACHE_EXISTS;
  149. } else if (sret == SQLITE_CONSTRAINT_UNIQUE) {
  150. uio_debug("An entry with the same name and size already exists!");
  151. err = ERR_CACHE_NON_UNIQUE;
  152. } else {
  153. uio_error("error after sql3_step: %s %d", sqlite3_errmsg(cache_db), sret);
  154. err = ERR_CACHE_SQLITE;
  155. }
  156. }
  157. fail:
  158. sqlite3_finalize(smt);
  159. return err;
  160. }
  161. enum error cache_get(const char *fname, uint64_t fsize, enum cache_select sel,
  162. struct cache_entry *out_ce)
  163. {
  164. sqlite3_stmt *smt;
  165. int sret;
  166. enum error err = NOERR;
  167. sret = sqlite3_prepare_v2(cache_db, sql_mylist_get,
  168. sizeof(sql_mylist_get), &smt, NULL);
  169. if (sret != SQLITE_OK) {
  170. uio_error("Cannot prepare statement: %s", sqlite3_errmsg(cache_db));
  171. return ERR_CACHE_SQLITE;
  172. }
  173. sqlite_bind_goto(smt, ":fname", text, fname, -1, SQLITE_STATIC);
  174. sqlite_bind_goto(smt, ":fsize", int64, fsize);
  175. sret = sqlite3_step(smt);
  176. if (sret == SQLITE_DONE) {
  177. uio_debug("Cache entry with size (%lu) and name (%s) not found", fsize, fname);
  178. err = ERR_CACHE_NO_EXISTS;
  179. goto fail;
  180. } else if (sret == SQLITE_ROW) {
  181. uio_debug("Found Cache entry with size (%lu) and name (%s)", fsize, fname);
  182. } else {
  183. uio_error("sqlite_step failed: %s", sqlite3_errmsg(cache_db));
  184. err = ERR_CACHE_SQLITE;
  185. goto fail;
  186. }
  187. if (!out_ce)
  188. goto end;
  189. if (sel == 0)
  190. sel = 0xFFFFFFFF;
  191. if (sel & CACHE_S_LID)
  192. out_ce->lid = sqlite3_column_int64(smt, 0);
  193. if (sel & CACHE_S_FNAME)
  194. out_ce->fname = strdup((const char *)sqlite3_column_text(smt, 1));
  195. if (sel & CACHE_S_FSIZE)
  196. out_ce->fsize = sqlite3_column_int64(smt, 2);
  197. if (sel & CACHE_S_ED2K) {
  198. const char *txt = (const char *)sqlite3_column_text(smt, 3);
  199. util_hex2byte(txt, out_ce->ed2k);
  200. }
  201. if (sel & CACHE_S_WATCHDATE)
  202. out_ce->wdate = sqlite3_column_int64(smt, 4);
  203. if (sel & CACHE_S_STATE)
  204. out_ce->state = sqlite3_column_int(smt, 5);
  205. if (sel & CACHE_S_MODDATE)
  206. out_ce->moddate = sqlite3_column_int64(smt, 6);
  207. end:
  208. fail:
  209. sqlite3_finalize(smt);
  210. return err;
  211. }
  212. static size_t cache_update_sqlprep_set(char *out, size_t out_size,
  213. const struct api_mylistadd_opts *mods)
  214. {
  215. size_t wr = 0;
  216. if (mods->state_set)
  217. wr += snprintf(out + wr, out ? out_size - wr : 0, "%s, ",
  218. "state = :state");
  219. if (mods->watched_set) {
  220. if (!mods->watched)
  221. wr += snprintf(out + wr, out ? out_size - wr : 0, "%s, ",
  222. "watchdate = 0");
  223. else if (mods->wdate_set)
  224. wr += snprintf(out + wr, out ? out_size - wr : 0,
  225. "%s, ", "watchdate = :watchdate");
  226. else
  227. wr += snprintf(out + wr, out ? out_size - wr : 0, "%s, ",
  228. "watchdate = strftime('%s')");
  229. }
  230. wr += snprintf(out + wr, out ? out_size - wr : 0, "%s",
  231. "moddate = strftime('%s')");
  232. return wr;
  233. }
  234. static size_t cache_update_sqlprep(char *out,
  235. const struct api_mylistadd_opts *mods)
  236. {
  237. size_t wr = cache_update_sqlprep_set(NULL, 0, mods);
  238. if (!out)
  239. return snprintf(NULL, 0, sql_mylist_update, "") + wr;
  240. char set_str[wr + 1];
  241. cache_update_sqlprep_set(set_str, wr + 1, mods);
  242. return sprintf(out, sql_mylist_update, (char*)set_str);
  243. }
  244. enum error cache_update(uint64_t lid, const struct api_mylistadd_opts *mods)
  245. {
  246. sqlite3_stmt *smt;
  247. int sret;
  248. enum error err = NOERR;
  249. size_t sql_len = cache_update_sqlprep(NULL, mods);
  250. char sql[sql_len + 1];
  251. cache_update_sqlprep(sql, mods);
  252. uio_debug("Update sql: '%s'", sql);
  253. sret = sqlite3_prepare_v2(cache_db, sql,
  254. sql_len, &smt, NULL);
  255. if (sret != SQLITE_OK) {
  256. uio_error("Cannot prepare statement: %s", sqlite3_errmsg(cache_db));
  257. return ERR_CACHE_SQLITE;
  258. }
  259. sqlite_bind_goto(smt, ":lid", int64, lid);
  260. if (mods->state_set) {
  261. sqlite_bind_goto(smt, ":state", int, mods->state);
  262. }
  263. if (mods->watched_set && mods->wdate_set) {
  264. sqlite_bind_goto(smt, ":watchdate", int64, mods->wdate);
  265. }
  266. sret = sqlite3_step(smt);
  267. if (sret == SQLITE_DONE) {
  268. uio_debug("Cache entry (%lu) succesfully updated", lid);
  269. } else {
  270. uio_error("sqlite_step failed: %s", sqlite3_errmsg(cache_db));
  271. err = ERR_CACHE_SQLITE;
  272. goto fail;
  273. }
  274. fail:
  275. sqlite3_finalize(smt);
  276. return err;
  277. }
  278. bool cache_exists(const char *fname, uint64_t size)
  279. {
  280. return cache_get(fname, size, 0, NULL) == NOERR;
  281. }