luat_lib_fskv.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /*
  2. @module fskv
  3. @summary kv数据库,掉电不丢数据
  4. @version 1.0
  5. @date 2022.12.29
  6. @demo fskv
  7. @tag LUAT_USE_FSKV
  8. @usage
  9. fskv.init()
  10. fskv.set("wendal", 1234)
  11. log.info("fskv", "wendal", fskv.get("wendal"))
  12. */
  13. #include "luat_base.h"
  14. #include "luat_msgbus.h"
  15. #include "luat_mem.h"
  16. #include "luat_fskv.h"
  17. #include "luat_sfd.h"
  18. #ifndef LUAT_LOG_TAG
  19. #define LUAT_LOG_TAG "fskv"
  20. #include "luat_log.h"
  21. #endif
  22. #define LUAT_FSKV_MAX_SIZE (4096)
  23. #ifndef LUAT_CONF_FSKV_CUSTOM
  24. extern sfd_drv_t* sfd_onchip;
  25. extern luat_sfd_lfs_t* sfd_lfs;
  26. #endif
  27. static int fskv_inited;
  28. /**
  29. 初始化kv数据库
  30. @api fskv.init()
  31. @return boolean 成功返回true,否则返回false
  32. @usage
  33. if fskv.init() then
  34. log.info("fskv", "kv数据库初始化成功")
  35. end
  36. */
  37. static int l_fskvdb_init(lua_State *L) {
  38. if (fskv_inited == 0) {
  39. #ifndef LUAT_CONF_FSKV_CUSTOM
  40. if (sfd_onchip == NULL) {
  41. luat_sfd_onchip_init();
  42. }
  43. if (sfd_onchip == NULL) {
  44. LLOGE("sfd-onchip init failed");
  45. return 0;
  46. }
  47. if (sfd_lfs == NULL) {
  48. luat_sfd_lfs_init(sfd_onchip);
  49. }
  50. if (sfd_lfs == NULL) {
  51. LLOGE("sfd-onchip lfs int failed");
  52. return 0;
  53. }
  54. fskv_inited = 1;
  55. #else
  56. fskv_inited = luat_fskv_init() == 0;
  57. #endif
  58. }
  59. lua_pushboolean(L, fskv_inited);
  60. return 1;
  61. }
  62. /**
  63. 设置一对kv数据
  64. @api fskv.set(key, value)
  65. @string key的名称,必填,不能空字符串
  66. @string 用户数据,必填,不能nil, 支持字符串/数值/table/布尔值, 数据长度最大4095字节
  67. @return boolean 成功返回true,否则返回false
  68. @usage
  69. -- 设置数据, 字符串,数值,table,布尔值,均可
  70. -- 但不可以是nil, function, userdata, task
  71. log.info("fskv", fskv.set("wendal", "goodgoodstudy"))
  72. log.info("fskv", fskv.set("upgrade", true))
  73. log.info("fskv", fskv.set("timer", 1))
  74. log.info("fskv", fskv.set("bigd", {name="wendal",age=123}))
  75. */
  76. static int l_fskv_set(lua_State *L) {
  77. if (fskv_inited == 0) {
  78. LLOGE("call fskv.init() first!!!");
  79. return 0;
  80. }
  81. size_t len;
  82. luaL_Buffer buff;
  83. luaL_buffinit(L, &buff);
  84. const char* key = luaL_checkstring(L, 1);
  85. //luaL_addchar(&buff, 0xA5);
  86. int type = lua_type(L, 2);
  87. switch (type)
  88. {
  89. case LUA_TBOOLEAN:
  90. luaL_addchar(&buff, LUA_TBOOLEAN);
  91. bool val = lua_toboolean(L, 2);
  92. luaL_addlstring(&buff, (const char*)&val, sizeof(val));
  93. break;
  94. case LUA_TNUMBER:
  95. if (lua_isinteger(L, 2)) {
  96. luaL_addchar(&buff, LUA_TINTEGER); // 自定义类型
  97. lua_Integer val = luaL_checkinteger(L, 2);
  98. luaL_addlstring(&buff, (const char*)&val, sizeof(val));
  99. }
  100. else {
  101. luaL_addchar(&buff, LUA_TNUMBER);
  102. lua_getglobal(L, "pack");
  103. if (lua_isnil(L, -1)) {
  104. LLOGW("float number need pack lib");
  105. lua_pushboolean(L, 0);
  106. return 1;
  107. }
  108. lua_getfield(L, -1, "pack");
  109. lua_pushstring(L, ">f");
  110. lua_pushvalue(L, 2);
  111. lua_call(L, 2, 1);
  112. if (lua_isstring(L, -1)) {
  113. const char* val = luaL_checklstring(L, -1, &len);
  114. luaL_addlstring(&buff, val, len);
  115. }
  116. else {
  117. LLOGW("kdb store number fail!!");
  118. lua_pushboolean(L, 0);
  119. return 1;
  120. }
  121. }
  122. break;
  123. case LUA_TSTRING:
  124. {
  125. luaL_addchar(&buff, LUA_TSTRING);
  126. const char* val = luaL_checklstring(L, 2, &len);
  127. luaL_addlstring(&buff, val, len);
  128. break;
  129. }
  130. case LUA_TTABLE:
  131. {
  132. lua_settop(L, 2);
  133. lua_getglobal(L, "json");
  134. if (lua_isnil(L, -1)) {
  135. LLOGW("miss json lib, not support table value");
  136. lua_pushboolean(L, 0);
  137. return 1;
  138. }
  139. lua_getfield(L, -1, "encode");
  140. if (lua_isfunction(L, -1)) {
  141. lua_pushvalue(L, 2);
  142. lua_call(L, 1, 1);
  143. if (lua_isstring(L, -1)) {
  144. luaL_addchar(&buff, LUA_TTABLE);
  145. const char* val = luaL_checklstring(L, -1, &len);
  146. luaL_addlstring(&buff, val, len);
  147. }
  148. else {
  149. LLOGW("json.encode(val) report error");
  150. lua_pushboolean(L, 0);
  151. return 1;
  152. }
  153. }
  154. else {
  155. LLOGW("miss json.encode, not support table value");
  156. lua_pushboolean(L, 0);
  157. return 1;
  158. }
  159. break;
  160. }
  161. default:
  162. {
  163. LLOGW("function/userdata/nil/thread isn't allow");
  164. lua_pushboolean(L, 0);
  165. return 1;
  166. }
  167. }
  168. if (buff.n > LUAT_FSKV_MAX_SIZE) {
  169. LLOGE("value too big %d max %d", buff.n, LUAT_FSKV_MAX_SIZE);
  170. lua_pushboolean(L, 0);
  171. return 1;
  172. }
  173. int ret = luat_fskv_set(key, buff.b, buff.n);
  174. lua_pushboolean(L, ret == buff.n ? 1 : 0);
  175. // lua_pushinteger(L, ret);
  176. return 1;
  177. }
  178. /**
  179. 设置table内的键值对数据
  180. @api fskv.sett(key, skey, value)
  181. @string key的名称,必填,不能空字符串
  182. @string table的key名称, 必填, 不能是空字符串
  183. @string 用户数据,必填,支持字符串/数值/table/布尔值, 数据长度最大4095字节
  184. @return boolean 成功返回true,否则返回false/nil
  185. @usage
  186. -- 本API在2023.7.26新增,注意与set函数区别
  187. -- 设置数据, 字符串,数值,table,布尔值,均可
  188. -- 但不可以是function, userdata, task
  189. log.info("fskv", fskv.sett("mytable", "wendal", "goodgoodstudy"))
  190. log.info("fskv", fskv.sett("mytable", "upgrade", true))
  191. log.info("fskv", fskv.sett("mytable", "timer", 1))
  192. log.info("fskv", fskv.sett("mytable", "bigd", {name="wendal",age=123}))
  193. -- 下列语句将打印出4个元素的table
  194. log.info("fskv", fskv.get("mytable"), json.encode(fskv.get("mytable")))
  195. -- 注意: 如果key不存在, 或者原本的值不是table类型,将会完全覆盖
  196. -- 例如下列写法,最终获取到的是table,而非第一行的字符串
  197. log.info("fskv", fskv.set("mykv", "123"))
  198. log.info("fskv", fskv.sett("mykv", "age", "123")) -- 保存的将是 {age:"123"}
  199. -- 如果设置的数据填nil, 代表删除对应的key
  200. log.info("fskv", fskv.sett("mykv", "name", "wendal"))
  201. log.info("fskv", fskv.sett("mykv", "name")) -- 相当于删除
  202. --
  203. */
  204. static int l_fskv_sett(lua_State *L) {
  205. if (fskv_inited == 0) {
  206. LLOGE("call fskv.init() first!!!");
  207. return 0;
  208. }
  209. const char* key = luaL_checkstring(L, 1);
  210. const char* skey = luaL_checkstring(L, 2);
  211. if (lua_gettop(L) < 3) {
  212. LLOGD("require key skey value");
  213. return 0;
  214. }
  215. char tmp[256] = {0};
  216. char *buff = NULL;
  217. char *rbuff = NULL;
  218. int size = luat_fskv_size(key, tmp);
  219. if (size >= 256) {
  220. rbuff = luat_heap_malloc(size);
  221. if (rbuff == NULL) {
  222. LLOGW("out of memory when malloc key-value buff");
  223. return 0;
  224. }
  225. size_t read_len = luat_fskv_get(key, rbuff, size);
  226. if (read_len != size) {
  227. luat_heap_free(rbuff);
  228. LLOGW("read key-value fail, ignore as not exist");
  229. return 0;
  230. }
  231. buff = rbuff;
  232. }
  233. else {
  234. buff = tmp;
  235. }
  236. if (buff[0] == LUA_TTABLE) {
  237. lua_getglobal(L, "json");
  238. lua_getfield(L, -1, "decode");
  239. lua_pushlstring(L, (const char*)(buff + 1), size - 1);
  240. lua_call(L, 1, 1);
  241. if (lua_type(L, -1) != LUA_TTABLE) {
  242. lua_pop(L, 1);
  243. lua_newtable(L);
  244. }
  245. }
  246. else {
  247. lua_newtable(L);
  248. }
  249. if (rbuff) {
  250. luat_heap_free(rbuff);
  251. rbuff = NULL;
  252. }
  253. lua_pushvalue(L, 3);
  254. lua_setfield(L, -2, skey);
  255. lua_pushcfunction(L, l_fskv_set);
  256. lua_pushvalue(L, 1);
  257. lua_pushvalue(L, -3);
  258. lua_call(L, 2, 1);
  259. return 1;
  260. }
  261. /**
  262. 根据key获取对应的数据
  263. @api fskv.get(key, skey)
  264. @string key的名称,必填,不能空字符串
  265. @string 可选的次级key,仅当原始值为table时有效,相当于 fskv.get(key)[skey]
  266. @return any 存在则返回数据,否则返回nil
  267. @usage
  268. if fskv.init() then
  269. log.info("fskv", fskv.get("wendal"))
  270. end
  271. -- 若需要"默认值", 对应非bool布尔值, 可以这样写
  272. local v = fskv.get("wendal") or "123"
  273. */
  274. static int l_fskv_get(lua_State *L) {
  275. if (fskv_inited == 0) {
  276. LLOGE("call fskv.init() first!!!");
  277. return 0;
  278. }
  279. // luaL_Buffer buff;
  280. const char* key = luaL_checkstring(L, 1);
  281. const char* skey = luaL_optstring(L, 2, "");
  282. // luaL_buffinitsize(L, &buff, 8192);
  283. char tmp[256] = {0};
  284. char *buff = NULL;
  285. char *rbuff = NULL;
  286. int size = luat_fskv_size(key, tmp);
  287. if (size < 2) {
  288. return 0; // 对应的KEY不存在
  289. }
  290. if (size >= 256) {
  291. rbuff = luat_heap_malloc(size);
  292. if (rbuff == NULL) {
  293. LLOGW("out of memory when malloc key-value buff");
  294. return 0;
  295. }
  296. size_t read_len = luat_fskv_get(key, rbuff, size);
  297. if (read_len != size) {
  298. luat_heap_free(rbuff);
  299. LLOGW("read key-value fail, ignore as not exist");
  300. return 0;
  301. }
  302. buff = rbuff;
  303. }
  304. else {
  305. buff = tmp;
  306. }
  307. lua_Integer intVal;
  308. // lua_Number *numVal;
  309. // LLOGD("KV value T=%02X", buff.b[0]);
  310. switch(buff[0]) {
  311. case LUA_TBOOLEAN:
  312. lua_pushboolean(L, buff[1]);
  313. break;
  314. case LUA_TNUMBER:
  315. lua_getglobal(L, "pack");
  316. lua_getfield(L, -1, "unpack");
  317. lua_pushlstring(L, (char*)(buff + 1), size - 1);
  318. lua_pushstring(L, ">f");
  319. lua_call(L, 2, 2);
  320. // _, val = pack.unpack(data, ">f")
  321. break;
  322. case LUA_TINTEGER:
  323. //不能直接赋值,右边指针地址和左边的位宽不一致
  324. memcpy(&intVal, &buff[1], sizeof(lua_Integer));
  325. // intVal = (lua_Integer*)(&buff[1]);
  326. // lua_pushinteger(L, *intVal);
  327. lua_pushinteger(L, intVal);
  328. break;
  329. case LUA_TSTRING:
  330. lua_pushlstring(L, (const char*)(buff + 1), size - 1);
  331. break;
  332. case LUA_TTABLE:
  333. lua_getglobal(L, "json");
  334. lua_getfield(L, -1, "decode");
  335. lua_pushlstring(L, (const char*)(buff + 1), size - 1);
  336. lua_call(L, 1, 1);
  337. if (strlen(skey) > 0 && lua_istable(L, -1)) {
  338. lua_getfield(L, -1, skey);
  339. }
  340. break;
  341. default :
  342. LLOGW("bad value prefix %02X", buff[0]);
  343. lua_pushnil(L);
  344. break;
  345. }
  346. if (rbuff)
  347. luat_heap_free(rbuff);
  348. return 1;
  349. }
  350. /**
  351. 根据key删除数据
  352. @api fskv.del(key)
  353. @string key的名称,必填,不能空字符串
  354. @return bool 成功返回true,否则返回false
  355. @usage
  356. log.info("fskv", fskv.del("wendal"))
  357. */
  358. static int l_fskv_del(lua_State *L) {
  359. if (fskv_inited == 0) {
  360. LLOGE("call fskv.init() first!!!");
  361. return 0;
  362. }
  363. const char* key = luaL_checkstring(L, 1);
  364. if (key == NULL) {
  365. lua_pushboolean(L, 0);
  366. return 1;
  367. }
  368. int ret = luat_fskv_del(key);
  369. lua_pushboolean(L, ret == 0 ? 1 : 0);
  370. return 1;
  371. }
  372. /**
  373. 清空整个kv数据库
  374. @api fskv.clear()
  375. @return bool 成功返回true,否则返回false
  376. @usage
  377. -- 清空
  378. fskv.clear()
  379. */
  380. static int l_fskv_clr(lua_State *L) {
  381. if (fskv_inited == 0) {
  382. LLOGE("call fskv.init() first!!!");
  383. return 0;
  384. }
  385. int ret = luat_fskv_clear();
  386. lua_pushboolean(L, ret == 0 ? 1 : 0);
  387. return 1;
  388. }
  389. /**
  390. kv数据库迭代器
  391. @api fskv.iter()
  392. @return userdata 成功返回迭代器指针,否则返回nil
  393. @usage
  394. -- 清空
  395. local iter = fskv.iter()
  396. if iter then
  397. while 1 do
  398. local k = fskv.next(iter)
  399. if not k then
  400. break
  401. end
  402. log.info("fskv", k, "value", fskv.kv_get(k))
  403. end
  404. end
  405. */
  406. static int l_fskv_iter(lua_State *L) {
  407. if (fskv_inited == 0) {
  408. LLOGE("call fskv.init() first!!!");
  409. return 0;
  410. }
  411. size_t *offset = lua_newuserdata(L, sizeof(size_t));
  412. memset(offset, 0, sizeof(size_t));
  413. return 1;
  414. }
  415. /**
  416. kv迭代器获取下一个key
  417. @api fskv.next(iter)
  418. @userdata fskv.iter()返回的指针
  419. @return string 成功返回字符串key值, 否则返回nil
  420. @usage
  421. -- 清空
  422. local iter = fskv.iter()
  423. if iter then
  424. while 1 do
  425. local k = fskv.next(iter)
  426. if not k then
  427. break
  428. end
  429. log.info("fskv", k, "value", fskv.get(k))
  430. end
  431. end
  432. */
  433. static int l_fskv_next(lua_State *L) {
  434. size_t *offset = lua_touserdata(L, 1);
  435. char buff[256] = {0};
  436. int ret = luat_fskv_next(buff, *offset);
  437. // LLOGD("fskv.next %d %d", *offset, ret);
  438. if (ret == 0) {
  439. lua_pushstring(L, buff);
  440. *offset = *offset + 1;
  441. return 1;
  442. }
  443. return 0;
  444. }
  445. /*
  446. 获取kv数据库状态
  447. @api fskv.status()
  448. @return int 已使用的空间,单位字节
  449. @return int 总可用空间, 单位字节
  450. @return int 总kv键值对数量, 单位个
  451. @usage
  452. local used, total,kv_count = fskv.status()
  453. log.info("fskv", "kv", used,total,kv_count)
  454. */
  455. static int l_fskv_stat(lua_State *L) {
  456. size_t using_sz = 0;
  457. size_t max_sz = 0;
  458. size_t kv_count = 0;
  459. if (fskv_inited == 0) {
  460. LLOGE("call fskv.init() first!!!");
  461. return 0;
  462. }
  463. luat_fskv_stat(&using_sz, &max_sz, &kv_count);
  464. lua_pushinteger(L, using_sz);
  465. lua_pushinteger(L, max_sz);
  466. lua_pushinteger(L, kv_count);
  467. return 3;
  468. }
  469. #include "rotable2.h"
  470. static const rotable_Reg_t reg_fskv[] =
  471. {
  472. { "init" , ROREG_FUNC(l_fskvdb_init)},
  473. { "set", ROREG_FUNC(l_fskv_set)},
  474. { "get", ROREG_FUNC(l_fskv_get)},
  475. { "del", ROREG_FUNC(l_fskv_del)},
  476. { "clr", ROREG_FUNC(l_fskv_clr)},
  477. { "clear", ROREG_FUNC(l_fskv_clr)},
  478. { "stat", ROREG_FUNC(l_fskv_stat)},
  479. { "status", ROREG_FUNC(l_fskv_stat)},
  480. { "iter", ROREG_FUNC(l_fskv_iter)},
  481. { "next", ROREG_FUNC(l_fskv_next)},
  482. { "sett", ROREG_FUNC(l_fskv_sett)},
  483. // -- 提供与fdb兼容的API
  484. { "kvdb_init" , ROREG_FUNC(l_fskvdb_init)},
  485. { "kv_set", ROREG_FUNC(l_fskv_set)},
  486. { "kv_get", ROREG_FUNC(l_fskv_get)},
  487. { "kv_del", ROREG_FUNC(l_fskv_del)},
  488. { "kv_clr", ROREG_FUNC(l_fskv_clr)},
  489. { "kv_stat", ROREG_FUNC(l_fskv_stat)},
  490. { "kv_iter", ROREG_FUNC(l_fskv_iter)},
  491. { "kv_next", ROREG_FUNC(l_fskv_next)},
  492. { NULL, ROREG_INT(0)}
  493. };
  494. LUAMOD_API int luaopen_fskv( lua_State *L ) {
  495. luat_newlib2(L, reg_fskv);
  496. lua_pushvalue(L, -1);
  497. lua_setglobal(L, "fdb");
  498. return 1;
  499. }