nolo-cli 0.143.0-alpha.1 → 0.145.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (455) hide show
  1. package/README.md +2 -0
  2. package/{_executeModel-QK43QR2R.js → _executeModel-M3FASQ2Z.js} +18 -17
  3. package/{agentDeleteCommand-SE4WUIRR.js → agentDeleteCommand-K7GCEEVS.js} +10 -9
  4. package/{agentEmailCommands-LW5JMYH2.js → agentEmailCommands-MNXRO36L.js} +24 -23
  5. package/{agentListCommands-LGZG2OQR.js → agentListCommands-KMZR6VVM.js} +12 -11
  6. package/{agentMachineCommands-BNOXYSPZ.js → agentMachineCommands-75TIBYDY.js} +10 -9
  7. package/{agentProviderCommands-AOG3OZJA.js → agentProviderCommands-TWB6E5WD.js} +1 -1
  8. package/{agentRecordCommands-W5ZXPHZV.js → agentRecordCommands-RDO5L3N4.js} +23 -22
  9. package/{agentRunCommand-VRLCL57M.js → agentRunCommand-FVJJPL27.js} +23 -22
  10. package/{agentRuntimeLocal-VOQ3UYZB.js → agentRuntimeLocal-DAK7RCER.js} +8 -7
  11. package/{agentSlice-4AK24F5F.js → agentSlice-6MRJR2BJ.js} +1 -1
  12. package/{appDeleteCommands-XWAIUHTN.js → appDeleteCommands-JMMXK3XT.js} +11 -10
  13. package/{appDeployCommands-CBJJCUMG.js → appDeployCommands-JFU6GALI.js} +11 -10
  14. package/{appDeployStatusCommands-LTTZTJQS.js → appDeployStatusCommands-AXTZ4GAN.js} +11 -10
  15. package/{appGetCommands-QHUB7MFF.js → appGetCommands-CR2W3DCM.js} +11 -10
  16. package/{appListCommands-HINIDJE7.js → appListCommands-2TV6P3EU.js} +11 -10
  17. package/{authCommand-LARLQ3GC.js → authCommand-UBJ4EWYZ.js} +6 -6
  18. package/{authCommands-GBIFZWD3.js → authCommands-H6WKKCRW.js} +1 -1
  19. package/{builtinSkillRegistry-AFPSTTAU.js → builtinSkillRegistry-ZMF6YGNO.js} +4 -3
  20. package/{chatQueueReduxAdapter-KIQ3FQ62.js → chatQueueReduxAdapter-CDOHVTSE.js} +2 -2
  21. package/{chromeCommands-NKU3OWKH.js → chromeCommands-2N6MEWRU.js} +94 -23
  22. package/{chromeOpsCommands-OQDJGD4Y.js → chromeOpsCommands-IXRLN57H.js} +4 -3
  23. package/{chunk-7MUSNQ6E.js → chunk-27ONFIEY.js} +20 -2
  24. package/{chunk-OZ6V53WV.js → chunk-2EE5UD3N.js} +1 -1
  25. package/{chunk-44QZPYLI.js → chunk-2SYTUTLI.js} +92 -20
  26. package/{chunk-DID5AVGT.js → chunk-2TKVOEQF.js} +11 -10
  27. package/chunk-5J3PYNUP.js +255 -0
  28. package/{chunk-OUOJE2P2.js → chunk-5XYFIDFU.js} +5 -5
  29. package/{chunk-WTUVMKSQ.js → chunk-62XHRZG4.js} +2 -2
  30. package/{chunk-WC6A2Q7S.js → chunk-6TPOEJMQ.js} +5 -2
  31. package/{chunk-RRMAZ2BI.js → chunk-7NANRWL4.js} +1 -1
  32. package/{chunk-44F6KKUE.js → chunk-7YAK46ML.js} +3 -3
  33. package/{chunk-NOGH7HCP.js → chunk-A6FNUMCF.js} +47 -6
  34. package/{chunk-OFYHCA6W.js → chunk-AATZZAZE.js} +1 -1
  35. package/{chunk-KUPDS66Q.js → chunk-ANX7Z7Z2.js} +8 -8
  36. package/{chunk-J5H6SUOW.js → chunk-B2XUQXQX.js} +2 -2
  37. package/{chunk-A5MB5RIT.js → chunk-CCOXTK3I.js} +1 -1
  38. package/chunk-GNMAFAIS.js +29 -0
  39. package/{chunk-GZQNKKDG.js → chunk-HKBFZONG.js} +1 -1
  40. package/{chunk-7LLWEG6F.js → chunk-I44MDY73.js} +3 -3
  41. package/{chunk-QDT5T7MK.js → chunk-I4OPU5TK.js} +1 -1
  42. package/{chunk-VPFEPRME.js → chunk-IVZJWTDI.js} +3 -0
  43. package/{chunk-CTGZO35O.js → chunk-JLQKV2ZJ.js} +2 -2
  44. package/{chunk-PQVOC2CZ.js → chunk-M2YBIBBS.js} +1 -1
  45. package/{chunk-ZOI6KA4N.js → chunk-M76SRQ3H.js} +34 -22
  46. package/{chunk-K25DK52L.js → chunk-OKSJZ4UU.js} +21 -223
  47. package/{chunk-U5QTKTZE.js → chunk-P6GMCCAT.js} +1 -1
  48. package/{chunk-L6RB42ZR.js → chunk-QFZM5BFI.js} +3 -3
  49. package/{chunk-GH4MH73K.js → chunk-RHDOQWXZ.js} +175 -17
  50. package/{chunk-M6NK74VP.js → chunk-S5XGT6GB.js} +1 -1
  51. package/{chunk-KUWT3C2P.js → chunk-T76D3OYX.js} +1 -1
  52. package/{chunk-MXRUAINC.js → chunk-UMB7CHAY.js} +3 -3
  53. package/{chunk-VVUSRF5D.js → chunk-VJ4FUWPC.js} +3 -3
  54. package/{chunk-T36EFAW7.js → chunk-VZVTPDPL.js} +3 -3
  55. package/{chunk-AAROOKLX.js → chunk-X2QRZXZH.js} +1 -1
  56. package/{chunk-WYYO2YOL.js → chunk-XNXNHAAP.js} +1 -1
  57. package/{chunk-O6OSWFZQ.js → chunk-XUWRURDF.js} +6 -0
  58. package/{chunk-DOBBRISY.js → chunk-Y6XHJ4JJ.js} +22 -10
  59. package/{chunk-W247GBSQ.js → chunk-YU2THNST.js} +1 -1
  60. package/{chunk-OY5IJI2N.js → chunk-YUNJN43V.js} +23 -3
  61. package/{commandRegistry-DETYXF5I.js → commandRegistry-ZF6YXQWV.js} +76 -65
  62. package/{contentThunks-6QBTPLWT.js → contentThunks-6Y6ATG3A.js} +3 -3
  63. package/{createAgentAutomationAction-TZVIJTZ7.js → createAgentAutomationAction-OQTLA2FC.js} +3 -3
  64. package/{createDialogAction-KTDAEA42.js → createDialogAction-IF5EZMBD.js} +6 -5
  65. package/{createPageAction-4RASVDAU.js → createPageAction-GU766R3L.js} +3 -3
  66. package/{dialogCommands-GY7LRERG.js → dialogCommands-QV7XAX2V.js} +11 -10
  67. package/{dialogSlice-J24APUGG.js → dialogSlice-CVHMDSVV.js} +2 -2
  68. package/{docCreateCommands-T7KII3WP.js → docCreateCommands-FSBANQTO.js} +10 -9
  69. package/{docDeleteCommands-SQ26EFE6.js → docDeleteCommands-4IR4YSGU.js} +11 -10
  70. package/{docReadCommands-I6NA2ZKV.js → docReadCommands-4EYPGUE3.js} +10 -9
  71. package/{docStore-SPOGE7K3.js → docStore-RQOWPNON.js} +1 -1
  72. package/{docUpdateCommands-IG43SZ6U.js → docUpdateCommands-RW2BYLSE.js} +10 -9
  73. package/{handleSendMessageAction-I2IN64DS.js → handleSendMessageAction-UDTPG5WK.js} +4 -3
  74. package/index.js +4 -4
  75. package/{machineCommands-U7VABJPW.js → machineCommands-WBQ4TCPD.js} +22 -21
  76. package/{machineWsRunDispatch-ZNU6LRNG.js → machineWsRunDispatch-7DNDXUOS.js} +22 -21
  77. package/node_modules/abstract-level/CHANGELOG.md +150 -0
  78. package/node_modules/abstract-level/LICENSE +21 -0
  79. package/node_modules/abstract-level/README.md +1957 -0
  80. package/node_modules/abstract-level/UPGRADING.md +669 -0
  81. package/node_modules/abstract-level/abstract-chained-batch.js +397 -0
  82. package/node_modules/abstract-level/abstract-iterator.js +404 -0
  83. package/node_modules/abstract-level/abstract-level.js +1127 -0
  84. package/node_modules/abstract-level/abstract-snapshot.js +84 -0
  85. package/node_modules/abstract-level/index.d.ts +52 -0
  86. package/node_modules/abstract-level/index.js +9 -0
  87. package/node_modules/abstract-level/lib/abstract-sublevel-iterator.js +141 -0
  88. package/node_modules/abstract-level/lib/abstract-sublevel.js +290 -0
  89. package/node_modules/abstract-level/lib/common.js +33 -0
  90. package/node_modules/abstract-level/lib/default-chained-batch.js +29 -0
  91. package/node_modules/abstract-level/lib/default-kv-iterator.js +74 -0
  92. package/node_modules/abstract-level/lib/deferred-iterator.js +110 -0
  93. package/node_modules/abstract-level/lib/deferred-queue.js +84 -0
  94. package/node_modules/abstract-level/lib/errors.js +21 -0
  95. package/node_modules/abstract-level/lib/event-monitor.js +30 -0
  96. package/node_modules/abstract-level/lib/hooks.js +78 -0
  97. package/node_modules/abstract-level/lib/prefixes.js +21 -0
  98. package/node_modules/abstract-level/lib/prewrite-batch.js +96 -0
  99. package/node_modules/abstract-level/lib/range-options.js +26 -0
  100. package/node_modules/abstract-level/package.json +66 -0
  101. package/node_modules/abstract-level/test/async-iterator-test.js +132 -0
  102. package/node_modules/abstract-level/test/batch-test.js +214 -0
  103. package/node_modules/abstract-level/test/chained-batch-test.js +315 -0
  104. package/node_modules/abstract-level/test/clear-range-test.js +262 -0
  105. package/node_modules/abstract-level/test/clear-test.js +110 -0
  106. package/node_modules/abstract-level/test/common.js +90 -0
  107. package/node_modules/abstract-level/test/deferred-open-test.js +209 -0
  108. package/node_modules/abstract-level/test/del-test.js +65 -0
  109. package/node_modules/abstract-level/test/encoding-buffer-test.js +336 -0
  110. package/node_modules/abstract-level/test/encoding-custom-test.js +92 -0
  111. package/node_modules/abstract-level/test/encoding-decode-error-test.js +85 -0
  112. package/node_modules/abstract-level/test/encoding-json-test.js +75 -0
  113. package/node_modules/abstract-level/test/encoding-test.js +130 -0
  114. package/node_modules/abstract-level/test/events/write.js +132 -0
  115. package/node_modules/abstract-level/test/factory-test.js +36 -0
  116. package/node_modules/abstract-level/test/get-many-test.js +157 -0
  117. package/node_modules/abstract-level/test/get-sync-test.js +61 -0
  118. package/node_modules/abstract-level/test/get-test.js +83 -0
  119. package/node_modules/abstract-level/test/has-many-test.js +144 -0
  120. package/node_modules/abstract-level/test/has-test.js +81 -0
  121. package/node_modules/abstract-level/test/hooks/newsub.js +57 -0
  122. package/node_modules/abstract-level/test/hooks/postopen.js +229 -0
  123. package/node_modules/abstract-level/test/hooks/prewrite.js +816 -0
  124. package/node_modules/abstract-level/test/hooks/shared.js +38 -0
  125. package/node_modules/abstract-level/test/index.js +86 -0
  126. package/node_modules/abstract-level/test/iterator-explicit-snapshot-test.js +393 -0
  127. package/node_modules/abstract-level/test/iterator-no-snapshot-test.js +49 -0
  128. package/node_modules/abstract-level/test/iterator-range-test.js +277 -0
  129. package/node_modules/abstract-level/test/iterator-seek-test.js +335 -0
  130. package/node_modules/abstract-level/test/iterator-snapshot-test.js +56 -0
  131. package/node_modules/abstract-level/test/iterator-test.js +621 -0
  132. package/node_modules/abstract-level/test/manifest-test.js +21 -0
  133. package/node_modules/abstract-level/test/open-create-if-missing-test.js +39 -0
  134. package/node_modules/abstract-level/test/open-error-if-exists-test.js +25 -0
  135. package/node_modules/abstract-level/test/open-test.js +263 -0
  136. package/node_modules/abstract-level/test/put-get-del-test.js +97 -0
  137. package/node_modules/abstract-level/test/put-test.js +70 -0
  138. package/node_modules/abstract-level/test/self/abstract-iterator-test.js +182 -0
  139. package/node_modules/abstract-level/test/self/async-iterator-test.js +242 -0
  140. package/node_modules/abstract-level/test/self/attach-resource-test.js +74 -0
  141. package/node_modules/abstract-level/test/self/defer-test.js +140 -0
  142. package/node_modules/abstract-level/test/self/deferred-iterator-test.js +314 -0
  143. package/node_modules/abstract-level/test/self/deferred-operations-test.js +86 -0
  144. package/node_modules/abstract-level/test/self/deferred-queue-test.js +93 -0
  145. package/node_modules/abstract-level/test/self/encoding-test.js +391 -0
  146. package/node_modules/abstract-level/test/self/errors-test.js +11 -0
  147. package/node_modules/abstract-level/test/self/iterator-test.js +1050 -0
  148. package/node_modules/abstract-level/test/self/sublevel-test.js +1039 -0
  149. package/node_modules/abstract-level/test/self.js +905 -0
  150. package/node_modules/abstract-level/test/sublevel-test.js +209 -0
  151. package/node_modules/abstract-level/test/traits/closed.js +42 -0
  152. package/node_modules/abstract-level/test/traits/index.js +4 -0
  153. package/node_modules/abstract-level/test/traits/open.js +62 -0
  154. package/node_modules/abstract-level/test/util.js +275 -0
  155. package/node_modules/abstract-level/types/abstract-chained-batch.d.ts +124 -0
  156. package/node_modules/abstract-level/types/abstract-iterator.d.ts +241 -0
  157. package/node_modules/abstract-level/types/abstract-level.d.ts +636 -0
  158. package/node_modules/abstract-level/types/abstract-snapshot.d.ts +30 -0
  159. package/node_modules/abstract-level/types/abstract-sublevel.d.ts +76 -0
  160. package/node_modules/abstract-level/types/interfaces.d.ts +43 -0
  161. package/node_modules/base64-js/LICENSE +21 -0
  162. package/node_modules/base64-js/README.md +34 -0
  163. package/node_modules/base64-js/base64js.min.js +1 -0
  164. package/node_modules/base64-js/index.d.ts +3 -0
  165. package/node_modules/base64-js/index.js +150 -0
  166. package/node_modules/base64-js/package.json +47 -0
  167. package/node_modules/browser-level/CHANGELOG.md +44 -0
  168. package/node_modules/browser-level/LICENSE +21 -0
  169. package/node_modules/browser-level/README.md +124 -0
  170. package/node_modules/browser-level/UPGRADING.md +143 -0
  171. package/node_modules/browser-level/index.d.ts +108 -0
  172. package/node_modules/browser-level/index.js +323 -0
  173. package/node_modules/browser-level/iterator.js +239 -0
  174. package/node_modules/browser-level/package.json +48 -0
  175. package/node_modules/browser-level/util/clear.js +38 -0
  176. package/node_modules/browser-level/util/deserialize.js +17 -0
  177. package/node_modules/browser-level/util/key-range.js +20 -0
  178. package/node_modules/buffer/AUTHORS.md +73 -0
  179. package/node_modules/buffer/LICENSE +21 -0
  180. package/node_modules/buffer/README.md +410 -0
  181. package/node_modules/buffer/index.d.ts +194 -0
  182. package/node_modules/buffer/index.js +2106 -0
  183. package/node_modules/buffer/package.json +93 -0
  184. package/node_modules/classic-level/CHANGELOG.md +115 -0
  185. package/node_modules/classic-level/LICENSE +21 -0
  186. package/node_modules/classic-level/README.md +274 -0
  187. package/node_modules/classic-level/UPGRADING.md +131 -0
  188. package/node_modules/classic-level/binding.cc +2652 -0
  189. package/node_modules/classic-level/binding.gyp +71 -0
  190. package/node_modules/classic-level/binding.js +1 -0
  191. package/node_modules/classic-level/chained-batch.js +35 -0
  192. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/LICENSE +27 -0
  193. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/Makefile +424 -0
  194. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/build_detect_platform +256 -0
  195. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/autocompact_test.cc +118 -0
  196. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/builder.cc +88 -0
  197. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/builder.h +34 -0
  198. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/c.cc +595 -0
  199. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/c_test.c +390 -0
  200. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/corruption_test.cc +374 -0
  201. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/db_bench.cc +1020 -0
  202. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/db_impl.cc +1568 -0
  203. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/db_impl.h +212 -0
  204. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/db_iter.cc +317 -0
  205. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/db_iter.h +28 -0
  206. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/db_test.cc +2158 -0
  207. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/dbformat.cc +140 -0
  208. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/dbformat.h +230 -0
  209. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/dbformat_test.cc +112 -0
  210. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/dumpfile.cc +225 -0
  211. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/fault_injection_test.cc +554 -0
  212. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/filename.cc +144 -0
  213. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/filename.h +85 -0
  214. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/filename_test.cc +123 -0
  215. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/leveldbutil.cc +64 -0
  216. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/log_format.h +35 -0
  217. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/log_reader.cc +284 -0
  218. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/log_reader.h +113 -0
  219. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/log_test.cc +591 -0
  220. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/log_writer.cc +112 -0
  221. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/log_writer.h +54 -0
  222. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/memtable.cc +145 -0
  223. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/memtable.h +89 -0
  224. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/recovery_test.cc +324 -0
  225. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/repair.cc +461 -0
  226. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/skiplist.h +384 -0
  227. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/skiplist_test.cc +378 -0
  228. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/snapshot.h +67 -0
  229. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/table_cache.cc +127 -0
  230. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/table_cache.h +61 -0
  231. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/version_edit.cc +266 -0
  232. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/version_edit.h +107 -0
  233. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/version_edit_test.cc +46 -0
  234. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/version_set.cc +1535 -0
  235. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/version_set.h +399 -0
  236. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/version_set_test.cc +179 -0
  237. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/write_batch.cc +147 -0
  238. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/write_batch_internal.h +50 -0
  239. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/db/write_batch_test.cc +120 -0
  240. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/helpers/memenv/memenv.cc +398 -0
  241. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/helpers/memenv/memenv.h +20 -0
  242. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/helpers/memenv/memenv_test.cc +241 -0
  243. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/c.h +290 -0
  244. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/cache.h +110 -0
  245. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/comparator.h +63 -0
  246. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/db.h +164 -0
  247. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/dumpfile.h +25 -0
  248. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/env.h +351 -0
  249. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/filter_policy.h +70 -0
  250. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/iterator.h +100 -0
  251. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/options.h +213 -0
  252. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/slice.h +109 -0
  253. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/status.h +112 -0
  254. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/table.h +85 -0
  255. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/table_builder.h +92 -0
  256. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/value_sink.h +26 -0
  257. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/include/leveldb/write_batch.h +64 -0
  258. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/issues/issue178_test.cc +92 -0
  259. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/issues/issue200_test.cc +59 -0
  260. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/port/atomic_pointer.h +242 -0
  261. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/port/port.h +21 -0
  262. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/port/port_example.h +141 -0
  263. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/port/port_posix.cc +53 -0
  264. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/port/port_posix.h +156 -0
  265. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/port/port_posix_sse.cc +129 -0
  266. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/port/thread_annotations.h +60 -0
  267. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/port/win/stdint.h +24 -0
  268. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/block.cc +268 -0
  269. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/block.h +44 -0
  270. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/block_builder.cc +109 -0
  271. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/block_builder.h +57 -0
  272. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/filter_block.cc +111 -0
  273. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/filter_block.h +68 -0
  274. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/filter_block_test.cc +128 -0
  275. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/format.cc +144 -0
  276. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/format.h +108 -0
  277. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/iterator.cc +67 -0
  278. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/iterator_wrapper.h +66 -0
  279. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/merger.cc +197 -0
  280. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/merger.h +26 -0
  281. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/table.cc +285 -0
  282. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/table_builder.cc +270 -0
  283. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/table_test.cc +876 -0
  284. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/two_level_iterator.cc +182 -0
  285. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/table/two_level_iterator.h +34 -0
  286. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/arena.cc +68 -0
  287. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/arena.h +68 -0
  288. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/arena_test.cc +68 -0
  289. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/bloom.cc +95 -0
  290. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/bloom_test.cc +162 -0
  291. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/cache.cc +405 -0
  292. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/cache_test.cc +226 -0
  293. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/coding.cc +194 -0
  294. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/coding.h +104 -0
  295. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/coding_test.cc +196 -0
  296. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/comparator.cc +81 -0
  297. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/crc32c.cc +350 -0
  298. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/crc32c.h +45 -0
  299. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/crc32c_test.cc +72 -0
  300. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env.cc +100 -0
  301. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_posix.cc +695 -0
  302. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_posix_test.cc +66 -0
  303. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_posix_test_helper.h +28 -0
  304. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/env_test.cc +106 -0
  305. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/filter_policy.cc +11 -0
  306. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/hash.cc +52 -0
  307. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/hash.h +19 -0
  308. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/hash_test.cc +54 -0
  309. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/histogram.cc +139 -0
  310. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/histogram.h +42 -0
  311. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/logging.cc +72 -0
  312. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/logging.h +43 -0
  313. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/mutexlock.h +41 -0
  314. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/options.cc +30 -0
  315. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/posix_logger.h +98 -0
  316. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/random.h +64 -0
  317. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/status.cc +75 -0
  318. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testharness.cc +77 -0
  319. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testharness.h +138 -0
  320. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testutil.cc +51 -0
  321. package/node_modules/classic-level/deps/leveldb/leveldb-1.20/util/testutil.h +63 -0
  322. package/node_modules/classic-level/deps/leveldb/leveldb.gyp +282 -0
  323. package/node_modules/classic-level/deps/leveldb/patches/001-value-sink.patch +164 -0
  324. package/node_modules/classic-level/deps/leveldb/port-libuv/atomic_pointer_win.h +48 -0
  325. package/node_modules/classic-level/deps/leveldb/port-libuv/env_win.cc +692 -0
  326. package/node_modules/classic-level/deps/leveldb/port-libuv/port_uv.cc +36 -0
  327. package/node_modules/classic-level/deps/leveldb/port-libuv/port_uv.h +157 -0
  328. package/node_modules/classic-level/deps/leveldb/port-libuv/port_uv.h.bak +153 -0
  329. package/node_modules/classic-level/deps/leveldb/port-libuv/stdint-msvc2008.h +247 -0
  330. package/node_modules/classic-level/deps/leveldb/port-libuv/uv_condvar.h +45 -0
  331. package/node_modules/classic-level/deps/leveldb/port-libuv/uv_condvar_posix.cc +139 -0
  332. package/node_modules/classic-level/deps/leveldb/port-libuv/win_logger.cc +79 -0
  333. package/node_modules/classic-level/deps/leveldb/port-libuv/win_logger.h +28 -0
  334. package/node_modules/classic-level/deps/snappy/freebsd/config.h +135 -0
  335. package/node_modules/classic-level/deps/snappy/freebsd/snappy-stubs-public.h +100 -0
  336. package/node_modules/classic-level/deps/snappy/linux/config.h +135 -0
  337. package/node_modules/classic-level/deps/snappy/linux/snappy-stubs-public.h +100 -0
  338. package/node_modules/classic-level/deps/snappy/mac/config.h +137 -0
  339. package/node_modules/classic-level/deps/snappy/mac/snappy-stubs-public.h +100 -0
  340. package/node_modules/classic-level/deps/snappy/openbsd/config.h +135 -0
  341. package/node_modules/classic-level/deps/snappy/openbsd/snappy-stubs-public.h +100 -0
  342. package/node_modules/classic-level/deps/snappy/snappy/COPYING +54 -0
  343. package/node_modules/classic-level/deps/snappy/snappy/cmake/SnappyConfig.cmake +1 -0
  344. package/node_modules/classic-level/deps/snappy/snappy/cmake/config.h.in +62 -0
  345. package/node_modules/classic-level/deps/snappy/snappy/snappy-c.cc +90 -0
  346. package/node_modules/classic-level/deps/snappy/snappy/snappy-c.h +138 -0
  347. package/node_modules/classic-level/deps/snappy/snappy/snappy-internal.h +224 -0
  348. package/node_modules/classic-level/deps/snappy/snappy/snappy-sinksource.cc +104 -0
  349. package/node_modules/classic-level/deps/snappy/snappy/snappy-sinksource.h +182 -0
  350. package/node_modules/classic-level/deps/snappy/snappy/snappy-stubs-internal.cc +42 -0
  351. package/node_modules/classic-level/deps/snappy/snappy/snappy-stubs-internal.h +561 -0
  352. package/node_modules/classic-level/deps/snappy/snappy/snappy-stubs-public.h.in +94 -0
  353. package/node_modules/classic-level/deps/snappy/snappy/snappy-test.cc +612 -0
  354. package/node_modules/classic-level/deps/snappy/snappy/snappy-test.h +573 -0
  355. package/node_modules/classic-level/deps/snappy/snappy/snappy.cc +1515 -0
  356. package/node_modules/classic-level/deps/snappy/snappy/snappy.h +203 -0
  357. package/node_modules/classic-level/deps/snappy/snappy/snappy_unittest.cc +1410 -0
  358. package/node_modules/classic-level/deps/snappy/snappy.gyp +119 -0
  359. package/node_modules/classic-level/deps/snappy/solaris/config.h +135 -0
  360. package/node_modules/classic-level/deps/snappy/solaris/snappy-stubs-public.h +100 -0
  361. package/node_modules/classic-level/deps/snappy/win32/config.h +29 -0
  362. package/node_modules/classic-level/deps/snappy/win32/snappy-stubs-public.h +100 -0
  363. package/node_modules/classic-level/index.d.ts +343 -0
  364. package/node_modules/classic-level/index.js +311 -0
  365. package/node_modules/classic-level/iterator.js +122 -0
  366. package/node_modules/classic-level/package.json +70 -0
  367. package/node_modules/classic-level/prebuilds/android-arm/classic-level.armv7.node +0 -0
  368. package/node_modules/classic-level/prebuilds/android-arm64/classic-level.armv8.node +0 -0
  369. package/node_modules/classic-level/prebuilds/darwin-x64+arm64/classic-level.node +0 -0
  370. package/node_modules/classic-level/prebuilds/linux-arm/classic-level.armv6.node +0 -0
  371. package/node_modules/classic-level/prebuilds/linux-arm/classic-level.armv7.node +0 -0
  372. package/node_modules/classic-level/prebuilds/linux-arm64/classic-level.armv8.node +0 -0
  373. package/node_modules/classic-level/prebuilds/linux-x64/classic-level.musl.node +0 -0
  374. package/node_modules/classic-level/prebuilds/linux-x64/classic-level.node +0 -0
  375. package/node_modules/classic-level/prebuilds/win32-ia32/classic-level.node +0 -0
  376. package/node_modules/classic-level/prebuilds/win32-x64/classic-level.node +0 -0
  377. package/node_modules/ieee754/LICENSE +11 -0
  378. package/node_modules/ieee754/README.md +51 -0
  379. package/node_modules/ieee754/index.d.ts +10 -0
  380. package/node_modules/ieee754/index.js +85 -0
  381. package/node_modules/ieee754/package.json +52 -0
  382. package/node_modules/is-buffer/LICENSE +21 -0
  383. package/node_modules/is-buffer/README.md +54 -0
  384. package/node_modules/is-buffer/index.d.ts +2 -0
  385. package/node_modules/is-buffer/index.js +11 -0
  386. package/node_modules/is-buffer/package.json +65 -0
  387. package/node_modules/level/CHANGELOG.md +532 -0
  388. package/node_modules/level/LICENSE +21 -0
  389. package/node_modules/level/README.md +107 -0
  390. package/node_modules/level/UPGRADING.md +413 -0
  391. package/node_modules/level/browser.js +1 -0
  392. package/node_modules/level/index.d.ts +75 -0
  393. package/node_modules/level/index.js +1 -0
  394. package/node_modules/level/package.json +62 -0
  395. package/node_modules/level-supports/CHANGELOG.md +140 -0
  396. package/node_modules/level-supports/LICENSE +21 -0
  397. package/node_modules/level-supports/README.md +276 -0
  398. package/node_modules/level-supports/index.d.ts +137 -0
  399. package/node_modules/level-supports/index.js +26 -0
  400. package/node_modules/level-supports/package.json +46 -0
  401. package/node_modules/level-supports/test/cloneable.js +26 -0
  402. package/node_modules/level-supports/test/index.js +24 -0
  403. package/node_modules/level-supports/test/self.js +86 -0
  404. package/node_modules/level-supports/test/shape.js +23 -0
  405. package/node_modules/level-transcoder/CHANGELOG.md +15 -0
  406. package/node_modules/level-transcoder/LICENSE +21 -0
  407. package/node_modules/level-transcoder/README.md +214 -0
  408. package/node_modules/level-transcoder/UPGRADING.md +13 -0
  409. package/node_modules/level-transcoder/index.d.ts +27 -0
  410. package/node_modules/level-transcoder/index.js +158 -0
  411. package/node_modules/level-transcoder/lib/encoding.d.ts +158 -0
  412. package/node_modules/level-transcoder/lib/encoding.js +105 -0
  413. package/node_modules/level-transcoder/lib/encodings.d.ts +9 -0
  414. package/node_modules/level-transcoder/lib/encodings.js +135 -0
  415. package/node_modules/level-transcoder/lib/formats.d.ts +13 -0
  416. package/node_modules/level-transcoder/lib/formats.js +111 -0
  417. package/node_modules/level-transcoder/lib/text-endec.d.ts +6 -0
  418. package/node_modules/level-transcoder/lib/text-endec.js +19 -0
  419. package/node_modules/level-transcoder/package.json +46 -0
  420. package/node_modules/maybe-combine-errors/LICENSE.md +21 -0
  421. package/node_modules/maybe-combine-errors/README.md +94 -0
  422. package/node_modules/maybe-combine-errors/index.js +60 -0
  423. package/node_modules/maybe-combine-errors/package.json +33 -0
  424. package/node_modules/module-error/CHANGELOG.md +23 -0
  425. package/node_modules/module-error/LICENSE +21 -0
  426. package/node_modules/module-error/README.md +89 -0
  427. package/node_modules/module-error/index.d.ts +18 -0
  428. package/node_modules/module-error/index.js +22 -0
  429. package/node_modules/module-error/package.json +36 -0
  430. package/node_modules/napi-macros/LICENSE +21 -0
  431. package/node_modules/napi-macros/README.md +277 -0
  432. package/node_modules/napi-macros/index.js +1 -0
  433. package/node_modules/napi-macros/napi-macros.h +255 -0
  434. package/node_modules/napi-macros/package.json +22 -0
  435. package/node_modules/node-gyp-build/LICENSE +21 -0
  436. package/node_modules/node-gyp-build/README.md +58 -0
  437. package/node_modules/node-gyp-build/SECURITY.md +5 -0
  438. package/node_modules/node-gyp-build/bin.js +84 -0
  439. package/node_modules/node-gyp-build/build-test.js +19 -0
  440. package/node_modules/node-gyp-build/index.js +6 -0
  441. package/node_modules/node-gyp-build/node-gyp-build.js +207 -0
  442. package/node_modules/node-gyp-build/optional.js +7 -0
  443. package/node_modules/node-gyp-build/package.json +43 -0
  444. package/package.json +6 -3
  445. package/{providerPresetApply-7XEHTODR.js → providerPresetApply-XTEXOH7X.js} +3 -3
  446. package/{providerRegistry-GNV4FFSA.js → providerRegistry-ADYDSLKR.js} +3 -3
  447. package/{readlineWorkspace-46KDFUHN.js → readlineWorkspace-LO6ZLFTO.js} +1381 -1317
  448. package/{runAgentClientLoop-CQWLWU4W.js → runAgentClientLoop-KAYGKVTK.js} +16 -15
  449. package/{runtimeDoctorCommands-3USD722U.js → runtimeDoctorCommands-ID23PNNZ.js} +28 -0
  450. package/{spaceCommands-TSBC5UWP.js → spaceCommands-FA6RCZ2Y.js} +10 -9
  451. package/{streamAgentChatTurn-XD5JEJXA.js → streamAgentChatTurn-DFNDU2UY.js} +17 -16
  452. package/{tools-5NAJJTFN.js → tools-6HKH75NT.js} +13 -12
  453. package/{tuiSummaryLlmCaller-7KLLDP22.js → tuiSummaryLlmCaller-CFFVXQWX.js} +2 -2
  454. package/{updateCommands-XYMGOKF4.js → updateCommands-4EHDLF5J.js} +1 -1
  455. package/{updateDialogTitleAction-IKZPJCRA.js → updateDialogTitleAction-FFSYTLBC.js} +3 -3
@@ -0,0 +1,2652 @@
1
+ #define NAPI_VERSION 3
2
+
3
+ #include <napi-macros.h>
4
+ #include <node_api.h>
5
+ #include <assert.h>
6
+
7
+ #include <leveldb/db.h>
8
+ #include <leveldb/write_batch.h>
9
+ #include <leveldb/cache.h>
10
+ #include <leveldb/filter_policy.h>
11
+
12
+ #include <map>
13
+ #include <vector>
14
+ #include <mutex>
15
+ #include <atomic>
16
+ #include <optional>
17
+
18
+ /**
19
+ * Forward declarations.
20
+ */
21
+ struct Database;
22
+ struct Resource;
23
+ struct Iterator;
24
+ struct ExplicitSnapshot;
25
+ static leveldb::Status threadsafe_open(const leveldb::Options &options,
26
+ bool multithreading,
27
+ Database &db_instance);
28
+ static leveldb::Status threadsafe_close(Database &db_instance);
29
+
30
+ /**
31
+ * Global declarations for multi-threaded access. These are not context-aware
32
+ * by definition and is specifically to allow for cross thread access to the
33
+ * single database handle.
34
+ */
35
+ struct LevelDbHandle
36
+ {
37
+ leveldb::DB *db;
38
+ size_t open_handle_count;
39
+ };
40
+ static std::mutex handles_mutex;
41
+ // only access this when protected by the handles_mutex!
42
+ static std::map<std::string, LevelDbHandle> db_handles;
43
+
44
+ /**
45
+ * Macros.
46
+ */
47
+ #define NAPI_DB_CONTEXT() \
48
+ Database* database = NULL; \
49
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&database));
50
+
51
+ #define NAPI_ITERATOR_CONTEXT() \
52
+ Iterator* iterator = NULL; \
53
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&iterator));
54
+
55
+ #define NAPI_BATCH_CONTEXT() \
56
+ Batch* batch = NULL; \
57
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&batch));
58
+
59
+ #define NAPI_SNAPSHOT_CONTEXT() \
60
+ ExplicitSnapshot* snapshot = NULL; \
61
+ NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&snapshot));
62
+
63
+ #define NAPI_RETURN_UNDEFINED() \
64
+ return 0;
65
+
66
+ #define NAPI_PROMISE() \
67
+ napi_deferred deferred; \
68
+ napi_value promise; \
69
+ NAPI_STATUS_THROWS(napi_create_promise(env, &deferred, &promise));
70
+
71
+ #define NAPI_UTF8_NEW(name, val) \
72
+ size_t name##_size = 0; \
73
+ NAPI_STATUS_THROWS(napi_get_value_string_utf8(env, val, NULL, 0, &name##_size)) \
74
+ char* name = new char[name##_size + 1]; \
75
+ NAPI_STATUS_THROWS(napi_get_value_string_utf8(env, val, name, name##_size + 1, &name##_size)) \
76
+ name[name##_size] = '\0';
77
+
78
+ #define NAPI_ARGV_UTF8_NEW(name, i) \
79
+ NAPI_UTF8_NEW(name, argv[i])
80
+
81
+ // TODO: consider using encoding options instead of type checking
82
+ #define LD_STRING_OR_BUFFER_TO_COPY(env, from, to) \
83
+ char* to##Ch_ = 0; \
84
+ size_t to##Sz_ = 0; \
85
+ if (IsString(env, from)) { \
86
+ napi_get_value_string_utf8(env, from, NULL, 0, &to##Sz_); \
87
+ to##Ch_ = new char[to##Sz_ + 1]; \
88
+ napi_get_value_string_utf8(env, from, to##Ch_, to##Sz_ + 1, &to##Sz_); \
89
+ to##Ch_[to##Sz_] = '\0'; \
90
+ } else if (IsBuffer(env, from)) { \
91
+ char* buf = 0; \
92
+ napi_get_buffer_info(env, from, (void **)&buf, &to##Sz_); \
93
+ to##Ch_ = new char[to##Sz_]; \
94
+ memcpy(to##Ch_, buf, to##Sz_); \
95
+ } else { \
96
+ char* buf = 0; \
97
+ napi_typedarray_type type; \
98
+ napi_status status = napi_get_typedarray_info(env, from, &type, &to##Sz_, (void **)&buf, NULL, NULL); \
99
+ if (status != napi_ok || type != napi_typedarray_type::napi_uint8_array) { \
100
+ /* TODO: refactor so that we can napi_throw_type_error() here */ \
101
+ to##Sz_ = 0; \
102
+ to##Ch_ = new char[to##Sz_]; \
103
+ } else { \
104
+ to##Ch_ = new char[to##Sz_]; \
105
+ memcpy(to##Ch_, buf, to##Sz_); \
106
+ } \
107
+ }
108
+
109
+ #define undefined NULL
110
+
111
+ /**
112
+ * Bit fields.
113
+ */
114
+ #define STATE_ENDED 1
115
+
116
+ /*********************************************************************
117
+ * Helpers.
118
+ ********************************************************************/
119
+
120
+ /**
121
+ * Returns true if 'value' is a string.
122
+ */
123
+ static bool IsString (napi_env env, napi_value value) {
124
+ napi_valuetype type;
125
+ napi_typeof(env, value, &type);
126
+ return type == napi_string;
127
+ }
128
+
129
+ /**
130
+ * Returns true if 'value' is a buffer.
131
+ */
132
+ static bool IsBuffer (napi_env env, napi_value value) {
133
+ bool isBuffer;
134
+ napi_is_buffer(env, value, &isBuffer);
135
+ return isBuffer;
136
+ }
137
+
138
+ /**
139
+ * Returns true if 'value' is an object.
140
+ */
141
+ static bool IsObject (napi_env env, napi_value value) {
142
+ napi_valuetype type;
143
+ napi_typeof(env, value, &type);
144
+ return type == napi_object;
145
+ }
146
+
147
+ /**
148
+ * Create an error object.
149
+ */
150
+ static napi_value CreateError (napi_env env, const char* str) {
151
+ napi_value msg;
152
+ napi_create_string_utf8(env, str, strlen(str), &msg);
153
+ napi_value error;
154
+ napi_create_error(env, NULL, msg, &error);
155
+ return error;
156
+ }
157
+
158
+ static napi_value CreateCodeError (napi_env env, const char* code, const char* msg) {
159
+ napi_value codeValue;
160
+ napi_create_string_utf8(env, code, strlen(code), &codeValue);
161
+ napi_value msgValue;
162
+ napi_create_string_utf8(env, msg, strlen(msg), &msgValue);
163
+ napi_value error;
164
+ napi_create_error(env, codeValue, msgValue, &error);
165
+ return error;
166
+ }
167
+
168
+ static void ThrowError(napi_env env, leveldb::Status status) {
169
+ if (status.IsCorruption()) {
170
+ napi_throw_error(env, "LEVEL_CORRUPTION", status.ToString().c_str());
171
+ } else if (!status.ok()) {
172
+ napi_throw_error(env, NULL, status.ToString().c_str());
173
+ } else {
174
+ napi_throw_error(env, NULL, "Operation failed");
175
+ }
176
+ }
177
+
178
+ static napi_value ErrorOrNotFound(napi_env env, leveldb::Status status) {
179
+ if (status.IsNotFound()) {
180
+ return undefined;
181
+ } else {
182
+ ThrowError(env, status);
183
+ return undefined;
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Returns true if 'obj' has a property 'key'.
189
+ */
190
+ static bool HasProperty (napi_env env, napi_value obj, const char* key) {
191
+ bool has = false;
192
+ napi_has_named_property(env, obj, key, &has);
193
+ return has;
194
+ }
195
+
196
+ /**
197
+ * Returns a property in napi_value form.
198
+ */
199
+ static napi_value GetProperty (napi_env env, napi_value obj, const char* key) {
200
+ napi_value value;
201
+ napi_get_named_property(env, obj, key, &value);
202
+ return value;
203
+ }
204
+
205
+ /**
206
+ * Returns a boolean property 'key' from 'obj'.
207
+ * Returns 'DEFAULT' if the property doesn't exist.
208
+ */
209
+ static bool BooleanProperty (napi_env env, napi_value obj, const char* key,
210
+ bool DEFAULT) {
211
+ if (HasProperty(env, obj, key)) {
212
+ napi_value value = GetProperty(env, obj, key);
213
+ bool result;
214
+ napi_get_value_bool(env, value, &result);
215
+ return result;
216
+ }
217
+
218
+ return DEFAULT;
219
+ }
220
+
221
+ /**
222
+ * Returns a boolean value.
223
+ * Returns 'DEFAULT' if the JS value is undefined or otherwise not a boolean.
224
+ */
225
+ static bool BooleanValue (napi_env env, napi_value value, bool DEFAULT) {
226
+ bool result;
227
+
228
+ if (napi_get_value_bool(env, value, &result) == napi_ok) {
229
+ return result;
230
+ } else {
231
+ return DEFAULT;
232
+ }
233
+ }
234
+
235
+ enum Encoding { buffer, utf8, view };
236
+
237
+ /**
238
+ * Returns internal Encoding enum matching the given encoding option.
239
+ */
240
+ static Encoding GetEncoding (napi_env env, napi_value options, const char* option) {
241
+ napi_value value;
242
+ size_t copied;
243
+ char buf[2];
244
+
245
+ if (napi_get_named_property(env, options, option, &value) == napi_ok &&
246
+ napi_get_value_string_utf8(env, value, buf, 2, &copied) == napi_ok && copied == 1) {
247
+ // Value is either "buffer", "utf8" or "view" so we only have to read the first char
248
+ switch (buf[0]) {
249
+ case 'b': return Encoding::buffer;
250
+ case 'v': return Encoding::view;
251
+ }
252
+ }
253
+
254
+ return Encoding::utf8;
255
+ }
256
+
257
+ /**
258
+ * Returns internal Encoding enum by its equivalent numeric value.
259
+ */
260
+ static Encoding GetEncoding (napi_env env, napi_value value) {
261
+ int32_t result;
262
+
263
+ if (napi_get_value_int32(env, value, &result) == napi_ok) {
264
+ return static_cast<Encoding>(result);
265
+ }
266
+
267
+ return Encoding::utf8;
268
+ }
269
+
270
+ /**
271
+ * Returns a uint32 property 'key' from 'obj'.
272
+ * Returns 'DEFAULT' if the property doesn't exist.
273
+ */
274
+ static uint32_t Uint32Property (napi_env env, napi_value obj, const char* key,
275
+ uint32_t DEFAULT) {
276
+ if (HasProperty(env, obj, key)) {
277
+ napi_value value = GetProperty(env, obj, key);
278
+ uint32_t result;
279
+ napi_get_value_uint32(env, value, &result);
280
+ return result;
281
+ }
282
+
283
+ return DEFAULT;
284
+ }
285
+
286
+ /**
287
+ * Returns a int32 property 'key' from 'obj'.
288
+ * Returns 'DEFAULT' if the property doesn't exist.
289
+ */
290
+ static int Int32Property (napi_env env, napi_value obj, const char* key,
291
+ int DEFAULT) {
292
+ if (HasProperty(env, obj, key)) {
293
+ napi_value value = GetProperty(env, obj, key);
294
+ int result;
295
+ napi_get_value_int32(env, value, &result);
296
+ return result;
297
+ }
298
+
299
+ return DEFAULT;
300
+ }
301
+
302
+ /**
303
+ * Returns a string property 'key' from 'obj'.
304
+ * Returns empty string if the property doesn't exist.
305
+ */
306
+ static std::string StringProperty (napi_env env, napi_value obj, const char* key) {
307
+ if (HasProperty(env, obj, key)) {
308
+ napi_value value = GetProperty(env, obj, key);
309
+ if (IsString(env, value)) {
310
+ size_t size = 0;
311
+ napi_get_value_string_utf8(env, value, NULL, 0, &size);
312
+
313
+ char* buf = new char[size + 1];
314
+ napi_get_value_string_utf8(env, value, buf, size + 1, &size);
315
+ buf[size] = '\0';
316
+
317
+ std::string result = buf;
318
+ delete [] buf;
319
+ return result;
320
+ }
321
+ }
322
+
323
+ return "";
324
+ }
325
+
326
+ static void DisposeSliceBuffer (leveldb::Slice slice) {
327
+ if (!slice.empty()) delete [] slice.data();
328
+ }
329
+
330
+ /**
331
+ * Convert a napi_value to a leveldb::Slice.
332
+ */
333
+ static leveldb::Slice ToSlice (napi_env env, napi_value from) {
334
+ LD_STRING_OR_BUFFER_TO_COPY(env, from, to);
335
+ return leveldb::Slice(toCh_, toSz_);
336
+ }
337
+
338
+ /**
339
+ * Takes a Buffer, string or Uint8Array property 'name' from 'opts'.
340
+ * Returns null if the property does not exist.
341
+ */
342
+ static std::string* RangeOption (napi_env env, napi_value opts, const char* name) {
343
+ if (HasProperty(env, opts, name)) {
344
+ napi_value value = GetProperty(env, opts, name);
345
+ // TODO: we can avoid a copy here
346
+ LD_STRING_OR_BUFFER_TO_COPY(env, value, to);
347
+ std::string* result = new std::string(toCh_, toSz_);
348
+ delete [] toCh_;
349
+ return result;
350
+ }
351
+
352
+ return NULL;
353
+ }
354
+
355
+ /**
356
+ * Converts an array containing Buffer or string keys to a vector.
357
+ */
358
+ static std::vector<std::string> KeyArray (napi_env env, napi_value arr) {
359
+ uint32_t length;
360
+ std::vector<std::string> result;
361
+
362
+ if (napi_get_array_length(env, arr, &length) == napi_ok) {
363
+ result.reserve(length);
364
+
365
+ for (uint32_t i = 0; i < length; i++) {
366
+ napi_value element;
367
+
368
+ if (napi_get_element(env, arr, i, &element) == napi_ok) {
369
+ LD_STRING_OR_BUFFER_TO_COPY(env, element, to);
370
+ result.emplace_back(toCh_, toSz_);
371
+ delete [] toCh_;
372
+ }
373
+ }
374
+ }
375
+
376
+ return result;
377
+ }
378
+
379
+ // TODO: use in more places
380
+ enum Flags : uint32_t {
381
+ FILL_CACHE = 1,
382
+ KEY_AS_BUFFER = 2,
383
+ VALUE_AS_BUFFER = 4,
384
+ SHARED_KEY = 8
385
+ };
386
+
387
+ /**
388
+ * Whether to yield entries, keys or values.
389
+ */
390
+ enum Mode {
391
+ entries,
392
+ keys,
393
+ values
394
+ };
395
+
396
+ /**
397
+ * Helper struct for caching and converting a key-value pair to napi_values.
398
+ */
399
+ struct Entry {
400
+ Entry (const leveldb::Slice& key, const leveldb::Slice& value)
401
+ : key_(key.data(), key.size()),
402
+ value_(value.data(), value.size()) {}
403
+
404
+ void ConvertByMode (napi_env env, Mode mode, const Encoding keyEncoding, const Encoding valueEncoding, napi_value& result) const {
405
+ if (mode == Mode::entries) {
406
+ napi_create_array_with_length(env, 2, &result);
407
+
408
+ napi_value keyElement;
409
+ napi_value valueElement;
410
+
411
+ Convert(env, &key_, keyEncoding, keyElement);
412
+ Convert(env, &value_, valueEncoding, valueElement);
413
+
414
+ napi_set_element(env, result, 0, keyElement);
415
+ napi_set_element(env, result, 1, valueElement);
416
+ } else if (mode == Mode::keys) {
417
+ Convert(env, &key_, keyEncoding, result);
418
+ } else {
419
+ Convert(env, &value_, valueEncoding, result);
420
+ }
421
+ }
422
+
423
+ static void Convert (napi_env env, const std::string* s, const Encoding encoding, napi_value& result) {
424
+ if (s == NULL) {
425
+ napi_get_undefined(env, &result);
426
+ } else if (encoding == Encoding::buffer || encoding == Encoding::view) {
427
+ napi_create_buffer_copy(env, s->size(), s->data(), NULL, &result);
428
+ } else {
429
+ napi_create_string_utf8(env, s->data(), s->size(), &result);
430
+ }
431
+ }
432
+
433
+ private:
434
+ std::string key_;
435
+ std::string value_;
436
+ };
437
+
438
+ /**
439
+ * Base worker class. Handles the async work. Derived classes can override the
440
+ * following virtual methods (listed in the order in which they're called):
441
+ *
442
+ * - DoExecute (abstract, worker pool thread): main work
443
+ * - HandleOKCallback (main thread): resolve JS promise on success
444
+ * - HandleErrorCallback (main thread): reject JS promise on error
445
+ * - DoFinally (main thread): do cleanup regardless of success
446
+ */
447
+ struct BaseWorker {
448
+ // Note: storing env is discouraged as we'd end up using it in unsafe places.
449
+ BaseWorker (napi_env env,
450
+ Database* database,
451
+ napi_deferred deferred,
452
+ const char* resourceName)
453
+ : database_(database), errMsg_(NULL), deferred_(deferred) {
454
+ // Note: napi_deferred is a strong reference to the JS promise, so there's no need to
455
+ // create a reference ourselves. See `v8_deferred = new v8::Persistent<v8::Value>()` in:
456
+ // https://github.com/nodejs/node/commit/7efb8f7619100973877c660d0ee527ea3d92de8d
457
+
458
+ napi_value asyncResourceName;
459
+ NAPI_STATUS_THROWS_VOID(napi_create_string_utf8(env, resourceName,
460
+ NAPI_AUTO_LENGTH,
461
+ &asyncResourceName));
462
+ NAPI_STATUS_THROWS_VOID(napi_create_async_work(env, NULL,
463
+ asyncResourceName,
464
+ BaseWorker::Execute,
465
+ BaseWorker::Complete,
466
+ this, &asyncWork_));
467
+ }
468
+
469
+ virtual ~BaseWorker () {
470
+ delete [] errMsg_;
471
+ }
472
+
473
+ static void Execute (napi_env env, void* data) {
474
+ BaseWorker* self = (BaseWorker*)data;
475
+
476
+ // Don't pass env to DoExecute() because use of Node-API
477
+ // methods should generally be avoided in async work.
478
+ self->DoExecute();
479
+ }
480
+
481
+ bool SetStatus (leveldb::Status status) {
482
+ status_ = status;
483
+ if (!status.ok()) {
484
+ SetErrorMessage(status.ToString().c_str());
485
+ return false;
486
+ }
487
+ return true;
488
+ }
489
+
490
+ void SetErrorMessage(const char *msg) {
491
+ delete [] errMsg_;
492
+ size_t size = strlen(msg) + 1;
493
+ errMsg_ = new char[size];
494
+ memcpy(errMsg_, msg, size);
495
+ }
496
+
497
+ virtual void DoExecute () = 0;
498
+
499
+ static void Complete (napi_env env, napi_status status, void* data) {
500
+ BaseWorker* self = (BaseWorker*)data;
501
+
502
+ self->DoComplete(env);
503
+ self->DoFinally(env);
504
+ }
505
+
506
+ void DoComplete (napi_env env) {
507
+ if (status_.ok()) {
508
+ HandleOKCallback(env, deferred_);
509
+ } else {
510
+ HandleErrorCallback(env, deferred_);
511
+ }
512
+ }
513
+
514
+ virtual void HandleOKCallback (napi_env env, napi_deferred deferred) {
515
+ napi_value argv;
516
+ napi_get_undefined(env, &argv);
517
+ napi_resolve_deferred(env, deferred, argv);
518
+ }
519
+
520
+ virtual void HandleErrorCallback (napi_env env, napi_deferred deferred) {
521
+ napi_value argv;
522
+
523
+ if (status_.IsNotFound()) {
524
+ napi_get_undefined(env, &argv);
525
+ napi_resolve_deferred(env, deferred, argv);
526
+ return;
527
+ }
528
+
529
+ if (status_.IsCorruption()) {
530
+ argv = CreateCodeError(env, "LEVEL_CORRUPTION", errMsg_);
531
+ } else if (status_.IsIOError()) {
532
+ if (strlen(errMsg_) > 15 && strncmp("IO error: lock ", errMsg_, 15) == 0) { // env_posix.cc
533
+ argv = CreateCodeError(env, "LEVEL_LOCKED", errMsg_);
534
+ } else if (strlen(errMsg_) > 19 && strncmp("IO error: LockFile ", errMsg_, 19) == 0) { // env_win.cc
535
+ argv = CreateCodeError(env, "LEVEL_LOCKED", errMsg_);
536
+ } else {
537
+ argv = CreateCodeError(env, "LEVEL_IO_ERROR", errMsg_);
538
+ }
539
+ } else {
540
+ argv = CreateError(env, errMsg_);
541
+ }
542
+
543
+ napi_reject_deferred(env, deferred, argv);
544
+ }
545
+
546
+ virtual void DoFinally (napi_env env) {
547
+ napi_delete_async_work(env, asyncWork_);
548
+ deferred_ = NULL;
549
+ delete this;
550
+ }
551
+
552
+ void Queue (napi_env env) {
553
+ napi_queue_async_work(env, asyncWork_);
554
+ }
555
+
556
+ Database* database_;
557
+
558
+ private:
559
+ napi_deferred deferred_;
560
+ napi_async_work asyncWork_;
561
+ leveldb::Status status_;
562
+ char *errMsg_;
563
+ };
564
+
565
+ /**
566
+ * Owns the LevelDB storage, cache, filter policy and resources.
567
+ */
568
+ struct Database {
569
+ Database ()
570
+ : db_(NULL),
571
+ sharedBuffer_(NULL),
572
+ blockCache_(NULL),
573
+ filterPolicy_(leveldb::NewBloomFilterPolicy(10)),
574
+ resourceSequence_(0),
575
+ pendingCloseWorker_(NULL),
576
+ ref_(NULL),
577
+ sharedBufferRef_(NULL),
578
+ priorityWork_(0) {}
579
+
580
+ ~Database () {
581
+ if (db_ != NULL) {
582
+ threadsafe_close(*this);
583
+ }
584
+ }
585
+
586
+ leveldb::Status Open (const leveldb::Options& options,
587
+ const std::string &location,
588
+ bool multithreading) {
589
+ location_ = location;
590
+ return threadsafe_open(options, multithreading, *this);
591
+ }
592
+
593
+ void CloseDatabase () {
594
+ if (db_ != NULL) {
595
+ threadsafe_close(*this);
596
+ }
597
+ if (blockCache_) {
598
+ delete blockCache_;
599
+ blockCache_ = NULL;
600
+ }
601
+ }
602
+
603
+ leveldb::Status Put (const leveldb::WriteOptions& options,
604
+ leveldb::Slice key,
605
+ leveldb::Slice value) {
606
+ return db_->Put(options, key, value);
607
+ }
608
+
609
+ leveldb::Status Get (const leveldb::ReadOptions& options,
610
+ leveldb::Slice key,
611
+ leveldb::ValueSink& value) {
612
+ return db_->Get(options, key, &value);
613
+ }
614
+
615
+ leveldb::Status Del (const leveldb::WriteOptions& options,
616
+ leveldb::Slice key) {
617
+ return db_->Delete(options, key);
618
+ }
619
+
620
+ leveldb::Status WriteBatch (const leveldb::WriteOptions& options,
621
+ leveldb::WriteBatch* batch) {
622
+ return db_->Write(options, batch);
623
+ }
624
+
625
+ uint64_t ApproximateSize (const leveldb::Range* range) {
626
+ uint64_t size = 0;
627
+ db_->GetApproximateSizes(range, 1, &size);
628
+ return size;
629
+ }
630
+
631
+ void CompactRange (const leveldb::Slice* start,
632
+ const leveldb::Slice* end) {
633
+ db_->CompactRange(start, end);
634
+ }
635
+
636
+ void GetProperty (const leveldb::Slice& property, std::string* value) {
637
+ db_->GetProperty(property, value);
638
+ }
639
+
640
+ const leveldb::Snapshot* NewSnapshot () {
641
+ return db_->GetSnapshot();
642
+ }
643
+
644
+ leveldb::Iterator* NewIterator (leveldb::ReadOptions* options) {
645
+ return db_->NewIterator(*options);
646
+ }
647
+
648
+ void ReleaseSnapshot (const leveldb::Snapshot* snapshot) {
649
+ return db_->ReleaseSnapshot(snapshot);
650
+ }
651
+
652
+ // The env argument is unused but reminds us to increment priorityWork_
653
+ // only in the JavaScript main thread to avoid needing a lock around
654
+ // that and pendingCloseWorker_.
655
+ void IncrementPriorityWork (napi_env env) {
656
+ priorityWork_++;
657
+ }
658
+
659
+ void DecrementPriorityWork (napi_env env) {
660
+ if (--priorityWork_ == 0 && pendingCloseWorker_ != NULL) {
661
+ pendingCloseWorker_->Queue(env);
662
+ pendingCloseWorker_ = NULL;
663
+ }
664
+ }
665
+
666
+ bool HasPriorityWork () const {
667
+ return priorityWork_ > 0;
668
+ }
669
+
670
+ bool SetSharedBuffer (napi_env env, napi_value value) {
671
+ // Delete reference to previous buffer if any
672
+ if (sharedBufferRef_) {
673
+ napi_delete_reference(env, sharedBufferRef_);
674
+ sharedBufferRef_ = NULL;
675
+ }
676
+
677
+ // Get underlying data (length is separately communicated, on use)
678
+ if (napi_get_buffer_info(env, value, (void**)&sharedBuffer_, NULL) != napi_ok) {
679
+ sharedBuffer_ = NULL;
680
+ return false;
681
+ }
682
+
683
+ // Create reference in order to keep buffer alive
684
+ if (napi_create_reference(env, value, 1, &sharedBufferRef_) != napi_ok) {
685
+ sharedBufferRef_ = NULL;
686
+ return false;
687
+ }
688
+
689
+ return true;
690
+ }
691
+
692
+ void ReleaseReferences (napi_env env) {
693
+ if (ref_ != NULL) napi_reference_unref(env, ref_, NULL);
694
+ if (sharedBufferRef_ != NULL) napi_reference_unref(env, sharedBufferRef_, NULL);
695
+ }
696
+
697
+ void DeleteReferences (napi_env env) {
698
+ if (ref_ != NULL) napi_delete_reference(env, ref_);
699
+ if (sharedBufferRef_ != NULL) napi_delete_reference(env, sharedBufferRef_);
700
+ }
701
+
702
+ leveldb::DB* db_;
703
+ char* sharedBuffer_;
704
+ leveldb::Cache* blockCache_;
705
+ const leveldb::FilterPolicy* filterPolicy_;
706
+ uint32_t resourceSequence_;
707
+ BaseWorker *pendingCloseWorker_;
708
+ std::map<uint32_t, Resource*> resources_;
709
+ napi_ref ref_;
710
+
711
+ private:
712
+ napi_ref sharedBufferRef_;
713
+ std::atomic<uint32_t> priorityWork_;
714
+ std::string location_;
715
+
716
+ // for separation of concerns the threadsafe functionality was kept at the global
717
+ // level and made a friend so it is explict where the threadsafe boundary exists
718
+ friend leveldb::Status threadsafe_open(const leveldb::Options &options,
719
+ bool multithreading,
720
+ Database &db_instance);
721
+ friend leveldb::Status threadsafe_close(Database &db_instance);
722
+ };
723
+
724
+
725
+ leveldb::Status threadsafe_open(const leveldb::Options &options,
726
+ bool multithreading,
727
+ Database &db_instance) {
728
+ // Bypass lock and handles if multithreading is disabled
729
+ if (!multithreading) {
730
+ return leveldb::DB::Open(options, db_instance.location_, &db_instance.db_);
731
+ }
732
+
733
+ std::unique_lock<std::mutex> lock(handles_mutex);
734
+
735
+ auto it = db_handles.find(db_instance.location_);
736
+ if (it == db_handles.end()) {
737
+ // Database not opened yet for this location, unless it was with
738
+ // multithreading disabled, in which case we're expected to fail here.
739
+ LevelDbHandle handle = {nullptr, 0};
740
+ leveldb::Status status = leveldb::DB::Open(options, db_instance.location_, &handle.db);
741
+
742
+ if (status.ok()) {
743
+ handle.open_handle_count++;
744
+ db_instance.db_ = handle.db;
745
+ db_handles[db_instance.location_] = handle;
746
+ }
747
+
748
+ return status;
749
+ }
750
+
751
+ ++(it->second.open_handle_count);
752
+ db_instance.db_ = it->second.db;
753
+
754
+ return leveldb::Status::OK();
755
+ }
756
+
757
+ leveldb::Status threadsafe_close(Database &db_instance) {
758
+ std::unique_lock<std::mutex> lock(handles_mutex);
759
+
760
+ auto it = db_handles.find(db_instance.location_);
761
+ if (it == db_handles.end()) {
762
+ // Was not opened with multithreading enabled
763
+ delete db_instance.db_;
764
+ } else if (--(it->second.open_handle_count) == 0) {
765
+ delete it->second.db;
766
+ db_handles.erase(it);
767
+ }
768
+
769
+ // ensure db_ pointer is nullified in Database instance
770
+ db_instance.db_ = NULL;
771
+ return leveldb::Status::OK();
772
+ }
773
+
774
+ /**
775
+ * Represents an object that has a strong reference until explicitly closed. In
776
+ * addition, resources are tracked in database->resources in order to close
777
+ * them when the Node.js environment is tore down.
778
+ */
779
+ struct Resource {
780
+ Resource (Database* database)
781
+ : database(database),
782
+ id_(++database->resourceSequence_),
783
+ ref_(NULL) {
784
+ }
785
+
786
+ virtual ~Resource () { }
787
+ virtual void CloseResource () = 0;
788
+
789
+ void Attach (napi_env env, napi_value context) {
790
+ napi_create_reference(env, context, 1, &ref_);
791
+ database->resources_[id_] = this;
792
+ }
793
+
794
+ void Detach (napi_env env) {
795
+ database->resources_.erase(id_);
796
+ if (ref_ != NULL) napi_delete_reference(env, ref_);
797
+ }
798
+
799
+ static void CollectGarbage (napi_env env, void* data, void* hint) {
800
+ if (data) {
801
+ delete (Resource*)data;
802
+ }
803
+ }
804
+
805
+ Database* database;
806
+
807
+ private:
808
+ const uint32_t id_;
809
+ napi_ref ref_;
810
+ };
811
+
812
+ /**
813
+ * Explicit snapshot of database.
814
+ */
815
+ struct ExplicitSnapshot final : public Resource {
816
+ ExplicitSnapshot (Database* database)
817
+ : Resource(database),
818
+ nut(database->NewSnapshot()) {
819
+ }
820
+
821
+ void CloseResource () override {
822
+ database->ReleaseSnapshot(nut);
823
+ }
824
+
825
+ const leveldb::Snapshot* nut;
826
+ };
827
+
828
+ /**
829
+ * Base worker class for doing async work that defers closing the database.
830
+ */
831
+ struct PriorityWorker : public BaseWorker {
832
+ PriorityWorker (napi_env env, Database* database, napi_deferred deferred, const char* resourceName)
833
+ : BaseWorker(env, database, deferred, resourceName) {
834
+ database_->IncrementPriorityWork(env);
835
+ }
836
+
837
+ virtual ~PriorityWorker () {}
838
+
839
+ void DoFinally (napi_env env) override {
840
+ database_->DecrementPriorityWork(env);
841
+ BaseWorker::DoFinally(env);
842
+ }
843
+ };
844
+
845
+ /**
846
+ * Owns a leveldb iterator.
847
+ */
848
+ struct BaseIterator {
849
+ BaseIterator(Database* database,
850
+ const bool reverse,
851
+ std::string* lt,
852
+ std::string* lte,
853
+ std::string* gt,
854
+ std::string* gte,
855
+ const int limit,
856
+ const bool fillCache,
857
+ ExplicitSnapshot* snapshot)
858
+ : database_(database),
859
+ hasClosed_(false),
860
+ didSeek_(false),
861
+ reverse_(reverse),
862
+ lt_(lt),
863
+ lte_(lte),
864
+ gt_(gt),
865
+ gte_(gte),
866
+ limit_(limit),
867
+ count_(0) {
868
+ options_ = new leveldb::ReadOptions();
869
+ options_->fill_cache = fillCache;
870
+
871
+ if (snapshot == NULL) {
872
+ implicitSnapshot_ = database_->NewSnapshot();
873
+ options_->snapshot = implicitSnapshot_;
874
+ } else {
875
+ implicitSnapshot_ = NULL;
876
+ options_->snapshot = snapshot->nut;
877
+ }
878
+
879
+ dbIterator_ = database_->NewIterator(options_);
880
+ }
881
+
882
+ virtual ~BaseIterator () {
883
+ assert(hasClosed_);
884
+
885
+ if (lt_ != NULL) delete lt_;
886
+ if (gt_ != NULL) delete gt_;
887
+ if (lte_ != NULL) delete lte_;
888
+ if (gte_ != NULL) delete gte_;
889
+
890
+ delete options_;
891
+ }
892
+
893
+ bool DidSeek () const {
894
+ return didSeek_;
895
+ }
896
+
897
+ /**
898
+ * Seek to the first relevant key based on range options.
899
+ */
900
+ void SeekToRange () {
901
+ didSeek_ = true;
902
+
903
+ if (!reverse_ && gte_ != NULL) {
904
+ dbIterator_->Seek(*gte_);
905
+ } else if (!reverse_ && gt_ != NULL) {
906
+ dbIterator_->Seek(*gt_);
907
+
908
+ if (dbIterator_->Valid() && dbIterator_->key().compare(*gt_) == 0) {
909
+ dbIterator_->Next();
910
+ }
911
+ } else if (reverse_ && lte_ != NULL) {
912
+ dbIterator_->Seek(*lte_);
913
+
914
+ if (!dbIterator_->Valid()) {
915
+ dbIterator_->SeekToLast();
916
+ } else if (dbIterator_->key().compare(*lte_) > 0) {
917
+ dbIterator_->Prev();
918
+ }
919
+ } else if (reverse_ && lt_ != NULL) {
920
+ dbIterator_->Seek(*lt_);
921
+
922
+ if (!dbIterator_->Valid()) {
923
+ dbIterator_->SeekToLast();
924
+ } else if (dbIterator_->key().compare(*lt_) >= 0) {
925
+ dbIterator_->Prev();
926
+ }
927
+ } else if (reverse_) {
928
+ dbIterator_->SeekToLast();
929
+ } else {
930
+ dbIterator_->SeekToFirst();
931
+ }
932
+ }
933
+
934
+ /**
935
+ * Seek manually (during iteration).
936
+ */
937
+ void Seek (leveldb::Slice& target) {
938
+ didSeek_ = true;
939
+
940
+ if (OutOfRange(target)) {
941
+ return SeekToEnd();
942
+ }
943
+
944
+ dbIterator_->Seek(target);
945
+
946
+ if (dbIterator_->Valid()) {
947
+ int cmp = dbIterator_->key().compare(target);
948
+ if (reverse_ ? cmp > 0 : cmp < 0) {
949
+ Next();
950
+ }
951
+ } else { // TODO: can we skip this code path if not in reverse?
952
+ SeekToFirst();
953
+ if (dbIterator_->Valid()) {
954
+ int cmp = dbIterator_->key().compare(target);
955
+ if (reverse_ ? cmp > 0 : cmp < 0) {
956
+ SeekToEnd();
957
+ }
958
+ }
959
+ }
960
+ }
961
+
962
+ /**
963
+ * Seek to an exact key.
964
+ */
965
+ bool SeekExact (leveldb::Slice& target) {
966
+ didSeek_ = true;
967
+ dbIterator_->Seek(target);
968
+ return dbIterator_->Valid() && dbIterator_->key() == target;
969
+ }
970
+
971
+ void CloseIterator () {
972
+ if (!hasClosed_) {
973
+ hasClosed_ = true;
974
+
975
+ delete dbIterator_;
976
+ dbIterator_ = NULL;
977
+
978
+ if (implicitSnapshot_) {
979
+ database_->ReleaseSnapshot(implicitSnapshot_);
980
+ }
981
+ }
982
+ }
983
+
984
+ bool Valid () const {
985
+ return dbIterator_->Valid() && !OutOfRange(dbIterator_->key());
986
+ }
987
+
988
+ bool Increment () {
989
+ return limit_ < 0 || ++count_ <= limit_;
990
+ }
991
+
992
+ void Next () {
993
+ if (reverse_) dbIterator_->Prev();
994
+ else dbIterator_->Next();
995
+ }
996
+
997
+ void SeekToFirst () {
998
+ if (reverse_) dbIterator_->SeekToLast();
999
+ else dbIterator_->SeekToFirst();
1000
+ }
1001
+
1002
+ void SeekToLast () {
1003
+ if (reverse_) dbIterator_->SeekToFirst();
1004
+ else dbIterator_->SeekToLast();
1005
+ }
1006
+
1007
+ void SeekToEnd () {
1008
+ SeekToLast();
1009
+ Next();
1010
+ }
1011
+
1012
+ leveldb::Slice CurrentKey () const {
1013
+ return dbIterator_->key();
1014
+ }
1015
+
1016
+ leveldb::Slice CurrentValue () const {
1017
+ return dbIterator_->value();
1018
+ }
1019
+
1020
+ leveldb::Status Status () const {
1021
+ return dbIterator_->status();
1022
+ }
1023
+
1024
+ bool OutOfRange (const leveldb::Slice& target) const {
1025
+ // The lte and gte options take precedence over lt and gt respectively
1026
+ if (lte_ != NULL) {
1027
+ if (target.compare(*lte_) > 0) return true;
1028
+ } else if (lt_ != NULL) {
1029
+ if (target.compare(*lt_) >= 0) return true;
1030
+ }
1031
+
1032
+ if (gte_ != NULL) {
1033
+ if (target.compare(*gte_) < 0) return true;
1034
+ } else if (gt_ != NULL) {
1035
+ if (target.compare(*gt_) <= 0) return true;
1036
+ }
1037
+
1038
+ return false;
1039
+ }
1040
+
1041
+ Database* database_;
1042
+ bool hasClosed_;
1043
+
1044
+ private:
1045
+ leveldb::Iterator* dbIterator_;
1046
+ bool didSeek_;
1047
+ const bool reverse_;
1048
+ std::string* lt_;
1049
+ std::string* lte_;
1050
+ std::string* gt_;
1051
+ std::string* gte_;
1052
+ const int limit_;
1053
+ int count_;
1054
+ leveldb::ReadOptions* options_;
1055
+ const leveldb::Snapshot* implicitSnapshot_;
1056
+ };
1057
+
1058
+ /**
1059
+ * Extends BaseIterator for reading it from JS land.
1060
+ */
1061
+ struct Iterator final : public BaseIterator, public Resource {
1062
+ Iterator (Database* database,
1063
+ const bool reverse,
1064
+ const bool keys,
1065
+ const bool values,
1066
+ const int limit,
1067
+ std::string* lt,
1068
+ std::string* lte,
1069
+ std::string* gt,
1070
+ std::string* gte,
1071
+ const bool fillCache,
1072
+ const Encoding keyEncoding,
1073
+ const Encoding valueEncoding,
1074
+ const uint32_t highWaterMarkBytes,
1075
+ unsigned char* state,
1076
+ ExplicitSnapshot* snapshot)
1077
+ : BaseIterator(database, reverse, lt, lte, gt, gte, limit, fillCache, snapshot),
1078
+ Resource(database),
1079
+ keys_(keys),
1080
+ values_(values),
1081
+ keyEncoding_(keyEncoding),
1082
+ valueEncoding_(valueEncoding),
1083
+ highWaterMarkBytes_(highWaterMarkBytes),
1084
+ first_(true),
1085
+ nexting_(false),
1086
+ aborted_(false),
1087
+ ended_(false),
1088
+ state_(state) {
1089
+ }
1090
+
1091
+ ~Iterator () {}
1092
+
1093
+ void CloseResource () override {
1094
+ BaseIterator::CloseIterator();
1095
+ }
1096
+
1097
+ bool ReadMany (uint32_t size) {
1098
+ cache_.clear();
1099
+ cache_.reserve(size);
1100
+ size_t bytesRead = 0;
1101
+ leveldb::Slice empty;
1102
+
1103
+ while (!aborted_) {
1104
+ if (!first_) Next();
1105
+ else first_ = false;
1106
+
1107
+ if (!Valid() || !Increment()) break;
1108
+
1109
+ if (keys_ && values_) {
1110
+ leveldb::Slice k = CurrentKey();
1111
+ leveldb::Slice v = CurrentValue();
1112
+ cache_.emplace_back(k, v);
1113
+ bytesRead += k.size() + v.size();
1114
+ } else if (keys_) {
1115
+ leveldb::Slice k = CurrentKey();
1116
+ cache_.emplace_back(k, empty);
1117
+ bytesRead += k.size();
1118
+ } else if (values_) {
1119
+ leveldb::Slice v = CurrentValue();
1120
+ cache_.emplace_back(empty, v);
1121
+ bytesRead += v.size();
1122
+ }
1123
+
1124
+ if (bytesRead > highWaterMarkBytes_ || cache_.size() >= size) {
1125
+ return true;
1126
+ }
1127
+ }
1128
+
1129
+ ended_ = true;
1130
+ return false;
1131
+ }
1132
+
1133
+ const bool keys_;
1134
+ const bool values_;
1135
+ const Encoding keyEncoding_;
1136
+ const Encoding valueEncoding_;
1137
+ const uint32_t highWaterMarkBytes_;
1138
+ bool first_;
1139
+ bool nexting_;
1140
+ std::atomic<bool> aborted_;
1141
+ bool ended_;
1142
+ unsigned char* state_;
1143
+ std::vector<Entry> cache_;
1144
+ };
1145
+
1146
+ /**
1147
+ * Hook for when the environment exits. This hook will be called after
1148
+ * already-scheduled napi_async_work items have finished, which gives us
1149
+ * the guarantee that no db operations will be in-flight at this time.
1150
+ */
1151
+ static void env_cleanup_hook (void* arg) {
1152
+ Database* database = (Database*)arg;
1153
+
1154
+ // Do everything that db.close() does but synchronously. We're expecting that GC
1155
+ // did not (yet) collect the database because that would be a user mistake (not
1156
+ // closing their db) made during the lifetime of the environment. That's different
1157
+ // from an environment being torn down (like the main process or a worker thread)
1158
+ // where it's our responsibility to clean up. Note also, the following code must
1159
+ // be a safe noop if called before db_open() or after db_close().
1160
+ if (database && database->db_ != NULL) {
1161
+ for (const auto& kv : database->resources_) {
1162
+ kv.second->CloseResource();
1163
+ }
1164
+
1165
+ database->CloseDatabase();
1166
+ }
1167
+ }
1168
+
1169
+ /**
1170
+ * Runs when a Database is garbage collected.
1171
+ */
1172
+ static void FinalizeDatabase (napi_env env, void* data, void* hint) {
1173
+ if (data) {
1174
+ Database* database = (Database*)data;
1175
+ napi_remove_env_cleanup_hook(env, env_cleanup_hook, database);
1176
+ database->DeleteReferences(env);
1177
+ delete database;
1178
+ }
1179
+ }
1180
+
1181
+ /**
1182
+ * Returns a context object for a database.
1183
+ */
1184
+ NAPI_METHOD(db_init) {
1185
+ Database* database = new Database();
1186
+ napi_add_env_cleanup_hook(env, env_cleanup_hook, database);
1187
+
1188
+ napi_value result;
1189
+ NAPI_STATUS_THROWS(napi_create_external(env, database,
1190
+ FinalizeDatabase,
1191
+ NULL, &result));
1192
+
1193
+ // Prevent GC of database before close()
1194
+ NAPI_STATUS_THROWS(napi_create_reference(env, result, 1, &database->ref_));
1195
+
1196
+ return result;
1197
+ }
1198
+
1199
+ /**
1200
+ * Worker class for opening a database.
1201
+ * TODO: shouldn't this be a PriorityWorker?
1202
+ */
1203
+ struct OpenWorker final : public BaseWorker {
1204
+ OpenWorker (napi_env env,
1205
+ Database* database,
1206
+ napi_deferred deferred,
1207
+ const std::string& location,
1208
+ const bool createIfMissing,
1209
+ const bool errorIfExists,
1210
+ const bool compression,
1211
+ const bool multithreading,
1212
+ const uint32_t writeBufferSize,
1213
+ const uint32_t blockSize,
1214
+ const uint32_t maxOpenFiles,
1215
+ const uint32_t blockRestartInterval,
1216
+ const uint32_t maxFileSize)
1217
+ : BaseWorker(env, database, deferred, "classic_level.db.open"),
1218
+ location_(location),
1219
+ multithreading_(multithreading) {
1220
+ options_.block_cache = database->blockCache_;
1221
+ options_.filter_policy = database->filterPolicy_;
1222
+ options_.create_if_missing = createIfMissing;
1223
+ options_.error_if_exists = errorIfExists;
1224
+ options_.compression = compression
1225
+ ? leveldb::kSnappyCompression
1226
+ : leveldb::kNoCompression;
1227
+ options_.write_buffer_size = writeBufferSize;
1228
+ options_.block_size = blockSize;
1229
+ options_.max_open_files = maxOpenFiles;
1230
+ options_.block_restart_interval = blockRestartInterval;
1231
+ options_.max_file_size = maxFileSize;
1232
+ }
1233
+
1234
+ ~OpenWorker () {}
1235
+
1236
+ void DoExecute () override {
1237
+ SetStatus(database_->Open(options_, location_, multithreading_));
1238
+ }
1239
+
1240
+ leveldb::Options options_;
1241
+ std::string location_;
1242
+ bool multithreading_;
1243
+ };
1244
+
1245
+ /**
1246
+ * Open a database.
1247
+ */
1248
+ NAPI_METHOD(db_open) {
1249
+ NAPI_ARGV(3);
1250
+ NAPI_DB_CONTEXT();
1251
+ NAPI_ARGV_UTF8_NEW(location, 1);
1252
+ NAPI_PROMISE();
1253
+
1254
+ napi_value options = argv[2];
1255
+ const bool createIfMissing = BooleanProperty(env, options, "createIfMissing", true);
1256
+ const bool errorIfExists = BooleanProperty(env, options, "errorIfExists", false);
1257
+ const bool compression = BooleanProperty(env, options, "compression", true);
1258
+ const bool multithreading = BooleanProperty(env, options, "multithreading", false);
1259
+
1260
+ const uint32_t cacheSize = Uint32Property(env, options, "cacheSize", 8 << 20);
1261
+ const uint32_t writeBufferSize = Uint32Property(env, options , "writeBufferSize" , 4 << 20);
1262
+ const uint32_t blockSize = Uint32Property(env, options, "blockSize", 4096);
1263
+ const uint32_t maxOpenFiles = Uint32Property(env, options, "maxOpenFiles", 1000);
1264
+ const uint32_t blockRestartInterval = Uint32Property(env, options,
1265
+ "blockRestartInterval", 16);
1266
+ const uint32_t maxFileSize = Uint32Property(env, options, "maxFileSize", 2 << 20);
1267
+
1268
+ database->blockCache_ = leveldb::NewLRUCache(cacheSize);
1269
+
1270
+ OpenWorker* worker = new OpenWorker(
1271
+ env, database, deferred, location,
1272
+ createIfMissing, errorIfExists,
1273
+ compression, multithreading,
1274
+ writeBufferSize, blockSize,
1275
+ maxOpenFiles, blockRestartInterval,
1276
+ maxFileSize
1277
+ );
1278
+
1279
+ worker->Queue(env);
1280
+ delete [] location;
1281
+
1282
+ return promise;
1283
+ }
1284
+
1285
+ /**
1286
+ * Worker class for closing a database
1287
+ *
1288
+ * TODO: once we've moved the PriorityWork logic to AbstractLevel, check if
1289
+ * CloseDatabase is fast enough to be done synchronously.
1290
+ */
1291
+ struct CloseWorker final : public BaseWorker {
1292
+ CloseWorker (napi_env env, Database* database, napi_deferred deferred)
1293
+ : BaseWorker(env, database, deferred, "classic_level.db.close") {}
1294
+
1295
+ ~CloseWorker () {}
1296
+
1297
+ void DoExecute () override {
1298
+ database_->CloseDatabase();
1299
+ }
1300
+
1301
+ void DoFinally (napi_env env) override {
1302
+ database_->ReleaseReferences(env);
1303
+ BaseWorker::DoFinally(env);
1304
+ }
1305
+ };
1306
+
1307
+ napi_value noop_callback (napi_env env, napi_callback_info info) {
1308
+ return 0;
1309
+ }
1310
+
1311
+ /**
1312
+ * Close a database.
1313
+ */
1314
+ NAPI_METHOD(db_close) {
1315
+ NAPI_ARGV(1);
1316
+ NAPI_DB_CONTEXT();
1317
+ NAPI_PROMISE();
1318
+
1319
+ // AbstractLevel should not call _close() before resources are closed
1320
+ assert(database->resources_.size() == 0);
1321
+
1322
+ CloseWorker* worker = new CloseWorker(env, database, deferred);
1323
+
1324
+ if (!database->HasPriorityWork()) {
1325
+ worker->Queue(env);
1326
+ } else {
1327
+ database->pendingCloseWorker_ = worker;
1328
+ }
1329
+
1330
+ return promise;
1331
+ }
1332
+
1333
+ /**
1334
+ * Worker class for putting key/value to the database
1335
+ */
1336
+ struct PutWorker final : public PriorityWorker {
1337
+ PutWorker (napi_env env,
1338
+ Database* database,
1339
+ napi_deferred deferred,
1340
+ leveldb::Slice key,
1341
+ leveldb::Slice value,
1342
+ bool sync)
1343
+ : PriorityWorker(env, database, deferred, "classic_level.db.put"),
1344
+ key_(key), value_(value) {
1345
+ options_.sync = sync;
1346
+ }
1347
+
1348
+ ~PutWorker () {
1349
+ DisposeSliceBuffer(key_);
1350
+ DisposeSliceBuffer(value_);
1351
+ }
1352
+
1353
+ void DoExecute () override {
1354
+ SetStatus(database_->Put(options_, key_, value_));
1355
+ }
1356
+
1357
+ leveldb::WriteOptions options_;
1358
+ leveldb::Slice key_;
1359
+ leveldb::Slice value_;
1360
+ };
1361
+
1362
+ /**
1363
+ * Puts a key and a value to a database.
1364
+ */
1365
+ NAPI_METHOD(db_put) {
1366
+ NAPI_ARGV(4);
1367
+ NAPI_DB_CONTEXT();
1368
+ NAPI_PROMISE();
1369
+
1370
+ leveldb::Slice key = ToSlice(env, argv[1]);
1371
+ leveldb::Slice value = ToSlice(env, argv[2]);
1372
+ bool sync = BooleanProperty(env, argv[3], "sync", false);
1373
+
1374
+ PutWorker* worker = new PutWorker(env, database, deferred, key, value, sync);
1375
+ worker->Queue(env);
1376
+
1377
+ return promise;
1378
+ }
1379
+
1380
+ /**
1381
+ * Worker class for getting a value from a database.
1382
+ */
1383
+ struct GetWorker final : public PriorityWorker {
1384
+ GetWorker (napi_env env,
1385
+ Database* database,
1386
+ napi_deferred deferred,
1387
+ uint32_t flags,
1388
+ leveldb::Slice key,
1389
+ napi_ref keyRef,
1390
+ ExplicitSnapshot* snapshot)
1391
+ : PriorityWorker(env, database, deferred, "classic_level.db.get"),
1392
+ flags_(flags),
1393
+ key_(key),
1394
+ keyRef_(keyRef) {
1395
+ options_.fill_cache = (flags & Flags::FILL_CACHE) != 0;
1396
+
1397
+ if (snapshot == NULL) {
1398
+ implicitSnapshot_ = database->NewSnapshot();
1399
+ options_.snapshot = implicitSnapshot_;
1400
+ } else {
1401
+ implicitSnapshot_ = NULL;
1402
+ options_.snapshot = snapshot->nut;
1403
+ }
1404
+ }
1405
+
1406
+ ~GetWorker () {
1407
+ if (!keyRef_) DisposeSliceBuffer(key_);
1408
+ }
1409
+
1410
+ void DoExecute () override {
1411
+ leveldb::StringValueSink wrapped(&value_);
1412
+ SetStatus(database_->Get(options_, key_, wrapped));
1413
+
1414
+ if (implicitSnapshot_) {
1415
+ database_->ReleaseSnapshot(implicitSnapshot_);
1416
+ }
1417
+ }
1418
+
1419
+ void DoFinally (napi_env env) override {
1420
+ if (keyRef_) napi_delete_reference(env, keyRef_);
1421
+ PriorityWorker::DoFinally(env);
1422
+ }
1423
+
1424
+ void HandleOKCallback (napi_env env, napi_deferred deferred) override {
1425
+ napi_value argv;
1426
+
1427
+ if ((flags_ & Flags::VALUE_AS_BUFFER) != 0) {
1428
+ napi_create_buffer_copy(env, value_.size(), value_.data(), NULL, &argv);
1429
+ } else {
1430
+ napi_create_string_utf8(env, value_.data(), value_.size(), &argv);
1431
+ }
1432
+
1433
+ napi_resolve_deferred(env, deferred, argv);
1434
+ }
1435
+
1436
+ private:
1437
+ leveldb::ReadOptions options_;
1438
+ uint32_t flags_;
1439
+ leveldb::Slice key_;
1440
+ napi_ref keyRef_;
1441
+ std::string value_;
1442
+ const leveldb::Snapshot* implicitSnapshot_;
1443
+ };
1444
+
1445
+ /**
1446
+ * Gets a value from a database.
1447
+ */
1448
+ NAPI_METHOD(db_get) {
1449
+ NAPI_ARGV(4);
1450
+ NAPI_DB_CONTEXT();
1451
+ NAPI_PROMISE();
1452
+
1453
+ uint32_t flags;
1454
+ NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &flags));
1455
+
1456
+ ExplicitSnapshot* snapshot = NULL;
1457
+ napi_get_value_external(env, argv[3], (void**)&snapshot);
1458
+
1459
+ char* keyBuffer;
1460
+ size_t keySize;
1461
+ GetWorker* worker;
1462
+
1463
+ if ((flags & Flags::KEY_AS_BUFFER) != 0) {
1464
+ // Instead of copying the memory, create a reference so that it stays valid
1465
+ napi_ref keyRef;
1466
+ NAPI_STATUS_THROWS(napi_create_reference(env, argv[2], 1, &keyRef));
1467
+ NAPI_STATUS_THROWS(napi_get_typedarray_info(env, argv[2], NULL, &keySize, (void**)&keyBuffer, NULL, NULL));
1468
+ leveldb::Slice keySlice(keyBuffer, keySize);
1469
+ worker = new GetWorker(env, database, deferred, flags, keySlice, keyRef, snapshot);
1470
+ } else {
1471
+ NAPI_STATUS_THROWS(napi_get_value_string_utf8(env, argv[2], NULL, 0, &keySize));
1472
+ keyBuffer = new char[keySize + 1];
1473
+ NAPI_STATUS_THROWS(napi_get_value_string_utf8(env, argv[2], keyBuffer, keySize + 1, NULL));
1474
+ keyBuffer[keySize] = '\0';
1475
+ leveldb::Slice keySlice(keyBuffer, keySize);
1476
+
1477
+ // A null keyRef implies that keyBuffer needs to be deleted after the read
1478
+ // TODO: solve in a more obvious way like a subclass
1479
+ worker = new GetWorker(env, database, deferred, flags, keySlice, NULL, snapshot);
1480
+ }
1481
+
1482
+ worker->Queue(env);
1483
+ return promise;
1484
+ }
1485
+
1486
+ struct NapiValueSink : public leveldb::ValueSink {
1487
+ NapiValueSink (napi_env env)
1488
+ : leveldb::ValueSink(),
1489
+ result(NULL),
1490
+ env_(env),
1491
+ status_(napi_generic_failure) {}
1492
+
1493
+ virtual ~NapiValueSink() = default;
1494
+
1495
+ const bool valid() {
1496
+ return status_ == napi_ok;
1497
+ }
1498
+
1499
+ napi_value result;
1500
+
1501
+ protected:
1502
+ napi_env env_;
1503
+ napi_status status_;
1504
+ };
1505
+
1506
+ struct NapiStringValueSink : public NapiValueSink {
1507
+ NapiStringValueSink (napi_env env)
1508
+ : NapiValueSink(env) {}
1509
+
1510
+ public:
1511
+ void assign(const char* data, size_t size) override {
1512
+ status_ = napi_create_string_utf8(env_, data, size, &result);
1513
+ }
1514
+ };
1515
+
1516
+ struct NapiBufferValueSink : public NapiValueSink {
1517
+ NapiBufferValueSink (napi_env env)
1518
+ : NapiValueSink(env) {}
1519
+
1520
+ public:
1521
+ void assign(const char* data, size_t size) override {
1522
+ status_ = napi_create_buffer_copy(env_, size, data, NULL, &result);
1523
+ }
1524
+ };
1525
+
1526
+ /**
1527
+ * Get a value from a database synchronously.
1528
+ */
1529
+ NAPI_METHOD(db_get_sync) {
1530
+ NAPI_ARGV(4);
1531
+ NAPI_DB_CONTEXT();
1532
+
1533
+ uint32_t flags;
1534
+ NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &flags));
1535
+
1536
+ std::optional<leveldb::Slice> keySlice;
1537
+
1538
+ if ((flags & Flags::SHARED_KEY) != 0) {
1539
+ uint32_t keySize;
1540
+ NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[2], &keySize));
1541
+ keySlice.emplace(database->sharedBuffer_, keySize);
1542
+ } else {
1543
+ char* keyBuffer;
1544
+ size_t keySize;
1545
+ NAPI_STATUS_THROWS(napi_get_typedarray_info(env, argv[2], NULL, &keySize, (void**)&keyBuffer, NULL, NULL));
1546
+ keySlice.emplace(keyBuffer, keySize);
1547
+ }
1548
+
1549
+ ExplicitSnapshot* snapshot = NULL;
1550
+ napi_get_value_external(env, argv[3], (void**)&snapshot);
1551
+
1552
+ leveldb::ReadOptions options;
1553
+ options.fill_cache = (flags & Flags::FILL_CACHE) != 0;
1554
+ options.snapshot = snapshot != NULL ? snapshot->nut : NULL;
1555
+
1556
+ if ((flags & Flags::VALUE_AS_BUFFER) != 0) {
1557
+ NapiBufferValueSink valueSink(env);
1558
+ leveldb::Status status = database->Get(options, *keySlice, valueSink);
1559
+ return status.ok() && valueSink.valid() ? valueSink.result : ErrorOrNotFound(env, status);
1560
+ } else {
1561
+ NapiStringValueSink valueSink(env);
1562
+ leveldb::Status status = database->Get(options, *keySlice, valueSink);
1563
+ return status.ok() && valueSink.valid() ? valueSink.result : ErrorOrNotFound(env, status);
1564
+ }
1565
+ }
1566
+
1567
+ NAPI_METHOD(db_set_shared_buffer) {
1568
+ NAPI_ARGV(2);
1569
+ NAPI_DB_CONTEXT();
1570
+
1571
+ if (!database->SetSharedBuffer(env, argv[1])) {
1572
+ napi_throw_error(env, NULL, "SetSharedBuffer failed");
1573
+ return undefined;
1574
+ }
1575
+
1576
+ return undefined;
1577
+ }
1578
+
1579
+ /**
1580
+ * Worker class for db.has().
1581
+ */
1582
+ struct HasWorker final : public PriorityWorker {
1583
+ HasWorker(
1584
+ napi_env env,
1585
+ Database* database,
1586
+ napi_deferred deferred,
1587
+ leveldb::Slice key,
1588
+ const bool fillCache,
1589
+ ExplicitSnapshot* snapshot
1590
+ ) : PriorityWorker(env, database, deferred, "classic_level.db.has"),
1591
+ key_(key) {
1592
+ iterator_ = new BaseIterator(
1593
+ database,
1594
+ // Range options (not relevant)
1595
+ false, NULL, NULL, NULL, NULL, -1,
1596
+ fillCache,
1597
+ snapshot
1598
+ );
1599
+ }
1600
+
1601
+ ~HasWorker () {
1602
+ DisposeSliceBuffer(key_);
1603
+ delete iterator_;
1604
+ }
1605
+
1606
+ void DoExecute () override {
1607
+ // LevelDB has no Has() method so use an iterator
1608
+ result_ = iterator_->SeekExact(key_);
1609
+ SetStatus(iterator_->Status());
1610
+ iterator_->CloseIterator();
1611
+ }
1612
+
1613
+ void HandleOKCallback (napi_env env, napi_deferred deferred) override {
1614
+ napi_value resultBoolean;
1615
+ napi_get_boolean(env, result_, &resultBoolean);
1616
+ napi_resolve_deferred(env, deferred, resultBoolean);
1617
+ }
1618
+
1619
+ private:
1620
+ leveldb::Slice key_;
1621
+ BaseIterator* iterator_;
1622
+ bool result_;
1623
+ };
1624
+
1625
+ /**
1626
+ * Check if the database has an entry with the given key.
1627
+ */
1628
+ NAPI_METHOD(db_has) {
1629
+ NAPI_ARGV(4);
1630
+ NAPI_DB_CONTEXT();
1631
+ NAPI_PROMISE();
1632
+
1633
+ leveldb::Slice key = ToSlice(env, argv[1]);
1634
+ const bool fillCache = BooleanValue(env, argv[2], true);
1635
+
1636
+ ExplicitSnapshot* snapshot = NULL;
1637
+ napi_get_value_external(env, argv[3], (void**)&snapshot);
1638
+
1639
+ HasWorker* worker = new HasWorker(
1640
+ env, database, deferred, key, fillCache, snapshot
1641
+ );
1642
+
1643
+ worker->Queue(env);
1644
+ return promise;
1645
+ }
1646
+
1647
+ /**
1648
+ * Worker class for getting many values.
1649
+ */
1650
+ struct GetManyWorker final : public PriorityWorker {
1651
+ GetManyWorker (napi_env env,
1652
+ Database* database,
1653
+ std::vector<std::string> keys,
1654
+ napi_deferred deferred,
1655
+ const Encoding valueEncoding,
1656
+ const bool fillCache,
1657
+ ExplicitSnapshot* snapshot)
1658
+ : PriorityWorker(env, database, deferred, "classic_level.get.many"),
1659
+ keys_(std::move(keys)), valueEncoding_(valueEncoding) {
1660
+ options_.fill_cache = fillCache;
1661
+
1662
+ if (snapshot == NULL) {
1663
+ implicitSnapshot_ = database->NewSnapshot();
1664
+ options_.snapshot = implicitSnapshot_;
1665
+ } else {
1666
+ implicitSnapshot_ = NULL;
1667
+ options_.snapshot = snapshot->nut;
1668
+ }
1669
+ }
1670
+
1671
+ void DoExecute () override {
1672
+ cache_.reserve(keys_.size());
1673
+
1674
+ for (const std::string& key: keys_) {
1675
+ std::string* value = new std::string();
1676
+ leveldb::StringValueSink wrapped(value);
1677
+ leveldb::Status status = database_->Get(options_, key, wrapped);
1678
+
1679
+ if (status.ok()) {
1680
+ cache_.push_back(value);
1681
+ } else if (status.IsNotFound()) {
1682
+ delete value;
1683
+ cache_.push_back(NULL);
1684
+ } else {
1685
+ delete value;
1686
+ for (const std::string* value: cache_) {
1687
+ if (value != NULL) delete value;
1688
+ }
1689
+ SetStatus(status);
1690
+ break;
1691
+ }
1692
+ }
1693
+
1694
+ if (implicitSnapshot_) {
1695
+ database_->ReleaseSnapshot(implicitSnapshot_);
1696
+ }
1697
+ }
1698
+
1699
+ void HandleOKCallback (napi_env env, napi_deferred deferred) override {
1700
+ size_t size = cache_.size();
1701
+ napi_value array;
1702
+ napi_create_array_with_length(env, size, &array);
1703
+
1704
+ for (size_t idx = 0; idx < size; idx++) {
1705
+ std::string* value = cache_[idx];
1706
+ napi_value element;
1707
+ Entry::Convert(env, value, valueEncoding_, element);
1708
+ napi_set_element(env, array, static_cast<uint32_t>(idx), element);
1709
+ if (value != NULL) delete value;
1710
+ }
1711
+
1712
+ napi_resolve_deferred(env, deferred, array);
1713
+ }
1714
+
1715
+ private:
1716
+ leveldb::ReadOptions options_;
1717
+ const std::vector<std::string> keys_;
1718
+ const Encoding valueEncoding_;
1719
+ std::vector<std::string*> cache_;
1720
+ const leveldb::Snapshot* implicitSnapshot_;
1721
+ };
1722
+
1723
+ /**
1724
+ * Gets many values from a database.
1725
+ */
1726
+ NAPI_METHOD(db_get_many) {
1727
+ NAPI_ARGV(4);
1728
+ NAPI_DB_CONTEXT();
1729
+ NAPI_PROMISE();
1730
+
1731
+ const auto keys = KeyArray(env, argv[1]);
1732
+ napi_value options = argv[2];
1733
+ const Encoding valueEncoding = GetEncoding(env, options, "valueEncoding");
1734
+ const bool fillCache = BooleanProperty(env, options, "fillCache", true);
1735
+
1736
+ ExplicitSnapshot* snapshot = NULL;
1737
+ napi_get_value_external(env, argv[3], (void**)&snapshot);
1738
+
1739
+ GetManyWorker* worker = new GetManyWorker(
1740
+ env,
1741
+ database,
1742
+ keys,
1743
+ deferred,
1744
+ valueEncoding,
1745
+ fillCache,
1746
+ snapshot
1747
+ );
1748
+
1749
+ worker->Queue(env);
1750
+ return promise;
1751
+ }
1752
+
1753
+ /**
1754
+ * Worker class for db.hasMany().
1755
+ */
1756
+ struct HasManyWorker final : public PriorityWorker {
1757
+ HasManyWorker(
1758
+ napi_env env,
1759
+ Database* database,
1760
+ std::vector<std::string> keys,
1761
+ napi_deferred deferred,
1762
+ uint32_t* bitset,
1763
+ const bool fillCache,
1764
+ ExplicitSnapshot* snapshot
1765
+ ) : PriorityWorker(env, database, deferred, "classic_level.has.many"),
1766
+ keys_(std::move(keys)),
1767
+ bitset_(bitset) {
1768
+ iterator_ = new BaseIterator(
1769
+ database,
1770
+ // Range options (not relevant)
1771
+ false, NULL, NULL, NULL, NULL, -1,
1772
+ fillCache,
1773
+ snapshot
1774
+ );
1775
+ }
1776
+
1777
+ ~HasManyWorker () {
1778
+ delete iterator_;
1779
+ }
1780
+
1781
+ void DoExecute () override {
1782
+ for (size_t i = 0; i != keys_.size(); i++) {
1783
+ leveldb::Slice target = leveldb::Slice(keys_[i]);
1784
+
1785
+ if (iterator_->SeekExact(target)) {
1786
+ bitset_[i >> 5] |= 1 << (i & 31); // Set bit
1787
+ }
1788
+ }
1789
+
1790
+ SetStatus(iterator_->Status());
1791
+ iterator_->CloseIterator();
1792
+ }
1793
+
1794
+ private:
1795
+ const std::vector<std::string> keys_;
1796
+ uint32_t* bitset_;
1797
+ BaseIterator* iterator_;
1798
+ };
1799
+
1800
+ /**
1801
+ * Check if the database has entries with the given keys.
1802
+ */
1803
+ NAPI_METHOD(db_has_many) {
1804
+ NAPI_ARGV(5);
1805
+ NAPI_DB_CONTEXT();
1806
+ NAPI_PROMISE();
1807
+
1808
+ const auto keys = KeyArray(env, argv[1]);
1809
+ const bool fillCache = BooleanValue(env, argv[2], true);
1810
+
1811
+ ExplicitSnapshot* snapshot = NULL;
1812
+ napi_get_value_external(env, argv[3], (void**)&snapshot);
1813
+
1814
+ uint32_t* bitset = NULL;
1815
+ NAPI_STATUS_THROWS(napi_get_arraybuffer_info(env, argv[4], (void**)&bitset, NULL));
1816
+
1817
+ HasManyWorker* worker = new HasManyWorker(
1818
+ env, database, keys, deferred, bitset, fillCache, snapshot
1819
+ );
1820
+
1821
+ worker->Queue(env);
1822
+ return promise;
1823
+ }
1824
+
1825
+ /**
1826
+ * Worker class for deleting a value from a database.
1827
+ */
1828
+ struct DelWorker final : public PriorityWorker {
1829
+ DelWorker (napi_env env,
1830
+ Database* database,
1831
+ napi_deferred deferred,
1832
+ leveldb::Slice key,
1833
+ bool sync)
1834
+ : PriorityWorker(env, database, deferred, "classic_level.db.del"),
1835
+ key_(key) {
1836
+ options_.sync = sync;
1837
+ }
1838
+
1839
+ ~DelWorker () {
1840
+ DisposeSliceBuffer(key_);
1841
+ }
1842
+
1843
+ void DoExecute () override {
1844
+ SetStatus(database_->Del(options_, key_));
1845
+ }
1846
+
1847
+ leveldb::WriteOptions options_;
1848
+ leveldb::Slice key_;
1849
+ };
1850
+
1851
+ /**
1852
+ * Delete a value from a database.
1853
+ */
1854
+ NAPI_METHOD(db_del) {
1855
+ NAPI_ARGV(3);
1856
+ NAPI_DB_CONTEXT();
1857
+ NAPI_PROMISE();
1858
+
1859
+ leveldb::Slice key = ToSlice(env, argv[1]);
1860
+ bool sync = BooleanProperty(env, argv[2], "sync", false);
1861
+
1862
+ DelWorker* worker = new DelWorker(env, database, deferred, key, sync);
1863
+ worker->Queue(env);
1864
+
1865
+ return promise;
1866
+ }
1867
+
1868
+ /**
1869
+ * Worker class for deleting a range from a database.
1870
+ */
1871
+ struct ClearWorker final : public PriorityWorker {
1872
+ ClearWorker (napi_env env,
1873
+ Database* database,
1874
+ napi_deferred deferred,
1875
+ const bool reverse,
1876
+ const int limit,
1877
+ std::string* lt,
1878
+ std::string* lte,
1879
+ std::string* gt,
1880
+ std::string* gte,
1881
+ ExplicitSnapshot* snapshot)
1882
+ : PriorityWorker(env, database, deferred, "classic_level.db.clear") {
1883
+ iterator_ = new BaseIterator(database, reverse, lt, lte, gt, gte, limit, false, snapshot);
1884
+ writeOptions_ = new leveldb::WriteOptions();
1885
+ writeOptions_->sync = false;
1886
+ }
1887
+
1888
+ ~ClearWorker () {
1889
+ delete iterator_;
1890
+ delete writeOptions_;
1891
+ }
1892
+
1893
+ void DoExecute () override {
1894
+ iterator_->SeekToRange();
1895
+
1896
+ // TODO: add option
1897
+ uint32_t hwm = 16 * 1024;
1898
+ leveldb::WriteBatch batch;
1899
+
1900
+ while (true) {
1901
+ size_t bytesRead = 0;
1902
+
1903
+ while (bytesRead <= hwm && iterator_->Valid() && iterator_->Increment()) {
1904
+ leveldb::Slice key = iterator_->CurrentKey();
1905
+ batch.Delete(key);
1906
+ bytesRead += key.size();
1907
+ iterator_->Next();
1908
+ }
1909
+
1910
+ if (!SetStatus(iterator_->Status()) || bytesRead == 0) {
1911
+ break;
1912
+ }
1913
+
1914
+ if (!SetStatus(database_->WriteBatch(*writeOptions_, &batch))) {
1915
+ break;
1916
+ }
1917
+
1918
+ batch.Clear();
1919
+ }
1920
+
1921
+ iterator_->CloseIterator();
1922
+ }
1923
+
1924
+ private:
1925
+ BaseIterator* iterator_;
1926
+ leveldb::WriteOptions* writeOptions_;
1927
+ };
1928
+
1929
+ /**
1930
+ * Delete a range from a database.
1931
+ */
1932
+ NAPI_METHOD(db_clear) {
1933
+ NAPI_ARGV(3);
1934
+ NAPI_DB_CONTEXT();
1935
+ NAPI_PROMISE();
1936
+
1937
+ napi_value options = argv[1];
1938
+
1939
+ const bool reverse = BooleanProperty(env, options, "reverse", false);
1940
+ const int limit = Int32Property(env, options, "limit", -1);
1941
+
1942
+ std::string* lt = RangeOption(env, options, "lt");
1943
+ std::string* lte = RangeOption(env, options, "lte");
1944
+ std::string* gt = RangeOption(env, options, "gt");
1945
+ std::string* gte = RangeOption(env, options, "gte");
1946
+
1947
+ ExplicitSnapshot* snapshot = NULL;
1948
+ napi_get_value_external(env, argv[2], (void**)&snapshot);
1949
+
1950
+ ClearWorker* worker = new ClearWorker(
1951
+ env, database, deferred, reverse, limit, lt, lte, gt, gte, snapshot
1952
+ );
1953
+
1954
+ worker->Queue(env);
1955
+ return promise;
1956
+ }
1957
+
1958
+ /**
1959
+ * Worker class for calculating the size of a range.
1960
+ */
1961
+ struct ApproximateSizeWorker final : public PriorityWorker {
1962
+ ApproximateSizeWorker (napi_env env,
1963
+ Database* database,
1964
+ napi_deferred deferred,
1965
+ leveldb::Slice start,
1966
+ leveldb::Slice end)
1967
+ : PriorityWorker(env, database, deferred, "classic_level.db.approximate_size"),
1968
+ start_(start), end_(end) {}
1969
+
1970
+ ~ApproximateSizeWorker () {
1971
+ DisposeSliceBuffer(start_);
1972
+ DisposeSliceBuffer(end_);
1973
+ }
1974
+
1975
+ void DoExecute () override {
1976
+ leveldb::Range range(start_, end_);
1977
+ size_ = database_->ApproximateSize(&range);
1978
+ }
1979
+
1980
+ void HandleOKCallback (napi_env env, napi_deferred deferred) override {
1981
+ napi_value argv;
1982
+ napi_create_int64(env, (uint64_t)size_, &argv);
1983
+ napi_resolve_deferred(env, deferred, argv);
1984
+ }
1985
+
1986
+ leveldb::Slice start_;
1987
+ leveldb::Slice end_;
1988
+ uint64_t size_;
1989
+ };
1990
+
1991
+ /**
1992
+ * Calculates the approximate size of a range in a database.
1993
+ */
1994
+ NAPI_METHOD(db_approximate_size) {
1995
+ NAPI_ARGV(3);
1996
+ NAPI_DB_CONTEXT();
1997
+ NAPI_PROMISE();
1998
+
1999
+ leveldb::Slice start = ToSlice(env, argv[1]);
2000
+ leveldb::Slice end = ToSlice(env, argv[2]);
2001
+
2002
+ ApproximateSizeWorker* worker = new ApproximateSizeWorker(
2003
+ env, database, deferred, start, end
2004
+ );
2005
+
2006
+ worker->Queue(env);
2007
+ return promise;
2008
+ }
2009
+
2010
+ /**
2011
+ * Worker class for compacting a range in a database.
2012
+ */
2013
+ struct CompactRangeWorker final : public PriorityWorker {
2014
+ CompactRangeWorker (napi_env env,
2015
+ Database* database,
2016
+ napi_deferred deferred,
2017
+ leveldb::Slice start,
2018
+ leveldb::Slice end)
2019
+ : PriorityWorker(env, database, deferred, "classic_level.db.compact_range"),
2020
+ start_(start), end_(end) {}
2021
+
2022
+ ~CompactRangeWorker () {
2023
+ DisposeSliceBuffer(start_);
2024
+ DisposeSliceBuffer(end_);
2025
+ }
2026
+
2027
+ void DoExecute () override {
2028
+ database_->CompactRange(&start_, &end_);
2029
+ }
2030
+
2031
+ leveldb::Slice start_;
2032
+ leveldb::Slice end_;
2033
+ };
2034
+
2035
+ /**
2036
+ * Compacts a range in a database.
2037
+ */
2038
+ NAPI_METHOD(db_compact_range) {
2039
+ NAPI_ARGV(3);
2040
+ NAPI_DB_CONTEXT();
2041
+ NAPI_PROMISE();
2042
+
2043
+ leveldb::Slice start = ToSlice(env, argv[1]);
2044
+ leveldb::Slice end = ToSlice(env, argv[2]);
2045
+
2046
+ CompactRangeWorker* worker = new CompactRangeWorker(
2047
+ env, database, deferred, start, end
2048
+ );
2049
+
2050
+ worker->Queue(env);
2051
+ return promise;
2052
+ }
2053
+
2054
+ /**
2055
+ * Get a property from a database.
2056
+ */
2057
+ NAPI_METHOD(db_get_property) {
2058
+ NAPI_ARGV(2);
2059
+ NAPI_DB_CONTEXT();
2060
+
2061
+ leveldb::Slice property = ToSlice(env, argv[1]);
2062
+
2063
+ std::string value;
2064
+ database->GetProperty(property, &value);
2065
+
2066
+ napi_value result;
2067
+ napi_create_string_utf8(env, value.data(), value.size(), &result);
2068
+
2069
+ DisposeSliceBuffer(property);
2070
+
2071
+ return result;
2072
+ }
2073
+
2074
+ /**
2075
+ * Worker class for destroying a database.
2076
+ */
2077
+ struct DestroyWorker final : public BaseWorker {
2078
+ DestroyWorker (napi_env env, const std::string& location, napi_deferred deferred)
2079
+ : BaseWorker(env, NULL, deferred, "classic_level.destroy_db"),
2080
+ location_(location) {}
2081
+
2082
+ ~DestroyWorker () {}
2083
+
2084
+ void DoExecute () override {
2085
+ leveldb::Options options;
2086
+ SetStatus(leveldb::DestroyDB(location_, options));
2087
+ }
2088
+
2089
+ std::string location_;
2090
+ };
2091
+
2092
+ /**
2093
+ * Destroys a database.
2094
+ */
2095
+ NAPI_METHOD(destroy_db) {
2096
+ NAPI_ARGV(1);
2097
+ NAPI_ARGV_UTF8_NEW(location, 0);
2098
+ NAPI_PROMISE();
2099
+
2100
+ DestroyWorker* worker = new DestroyWorker(env, location, deferred);
2101
+ worker->Queue(env);
2102
+
2103
+ delete [] location;
2104
+ return promise;
2105
+ }
2106
+
2107
+ /**
2108
+ * Worker class for repairing a database.
2109
+ */
2110
+ struct RepairWorker final : public BaseWorker {
2111
+ RepairWorker (napi_env env, const std::string& location, napi_deferred deferred)
2112
+ : BaseWorker(env, NULL, deferred, "classic_level.repair_db"),
2113
+ location_(location) {}
2114
+
2115
+ ~RepairWorker () {}
2116
+
2117
+ void DoExecute () override {
2118
+ leveldb::Options options;
2119
+ SetStatus(leveldb::RepairDB(location_, options));
2120
+ }
2121
+
2122
+ std::string location_;
2123
+ };
2124
+
2125
+ /**
2126
+ * Repairs a database.
2127
+ */
2128
+ NAPI_METHOD(repair_db) {
2129
+ NAPI_ARGV(1);
2130
+ NAPI_ARGV_UTF8_NEW(location, 0);
2131
+ NAPI_PROMISE();
2132
+
2133
+ RepairWorker* worker = new RepairWorker(env, location, deferred);
2134
+ worker->Queue(env);
2135
+
2136
+ delete [] location;
2137
+
2138
+ return promise;
2139
+ }
2140
+
2141
+ /**
2142
+ * Create an iterator.
2143
+ */
2144
+ NAPI_METHOD(iterator_init) {
2145
+ NAPI_ARGV(4);
2146
+ NAPI_DB_CONTEXT();
2147
+
2148
+ unsigned char* state = 0;
2149
+ size_t stateLength;
2150
+ NAPI_STATUS_THROWS(napi_get_typedarray_info(env, argv[1], NULL, &stateLength, (void**)&state, NULL, NULL));
2151
+ assert(stateLength == 1);
2152
+
2153
+ napi_value options = argv[2];
2154
+ const bool reverse = BooleanProperty(env, options, "reverse", false);
2155
+ const bool keys = BooleanProperty(env, options, "keys", true);
2156
+ const bool values = BooleanProperty(env, options, "values", true);
2157
+ const bool fillCache = BooleanProperty(env, options, "fillCache", false);
2158
+ const Encoding keyEncoding = GetEncoding(env, options, "keyEncoding");
2159
+ const Encoding valueEncoding = GetEncoding(env, options, "valueEncoding");
2160
+ const int limit = Int32Property(env, options, "limit", -1);
2161
+ const uint32_t highWaterMarkBytes = Uint32Property(env, options, "highWaterMarkBytes", 16 * 1024);
2162
+
2163
+ std::string* lt = RangeOption(env, options, "lt");
2164
+ std::string* lte = RangeOption(env, options, "lte");
2165
+ std::string* gt = RangeOption(env, options, "gt");
2166
+ std::string* gte = RangeOption(env, options, "gte");
2167
+
2168
+ ExplicitSnapshot* snapshot = NULL;
2169
+ napi_get_value_external(env, argv[3], (void**)&snapshot);
2170
+
2171
+ Iterator* iterator = new Iterator(
2172
+ database,
2173
+ reverse,
2174
+ keys, values,
2175
+ limit,
2176
+ lt, lte, gt, gte,
2177
+ fillCache,
2178
+ keyEncoding, valueEncoding,
2179
+ highWaterMarkBytes,
2180
+ state,
2181
+ snapshot
2182
+ );
2183
+
2184
+ napi_value result;
2185
+ NAPI_STATUS_THROWS(napi_create_external(env, iterator,
2186
+ Resource::CollectGarbage,
2187
+ NULL, &result));
2188
+
2189
+ iterator->Attach(env, result);
2190
+
2191
+ return result;
2192
+ }
2193
+
2194
+ /**
2195
+ * Seeks an iterator.
2196
+ */
2197
+ NAPI_METHOD(iterator_seek) {
2198
+ NAPI_ARGV(2);
2199
+ NAPI_ITERATOR_CONTEXT();
2200
+
2201
+ // AbstractIterator should not call _seek() after _close()
2202
+ assert(!iterator->hasClosed_);
2203
+
2204
+ leveldb::Slice target = ToSlice(env, argv[1]);
2205
+ iterator->first_ = true;
2206
+ iterator->ended_ = false;
2207
+ iterator->Seek(target);
2208
+
2209
+ DisposeSliceBuffer(target);
2210
+ NAPI_RETURN_UNDEFINED();
2211
+ }
2212
+
2213
+ /**
2214
+ * Closes an iterator.
2215
+ */
2216
+ NAPI_METHOD(iterator_close) {
2217
+ NAPI_ARGV(1);
2218
+ NAPI_ITERATOR_CONTEXT();
2219
+
2220
+ // AbstractIterator should not call _close() more than once or while nexting
2221
+ assert(!iterator->hasClosed_);
2222
+ assert(!iterator->nexting_);
2223
+
2224
+ iterator->CloseResource();
2225
+ iterator->Detach(env);
2226
+
2227
+ NAPI_RETURN_UNDEFINED();
2228
+ }
2229
+
2230
+ /**
2231
+ * Aborts a NextWorker (if any, eventually).
2232
+ */
2233
+ NAPI_METHOD(iterator_abort) {
2234
+ NAPI_ARGV(1);
2235
+ NAPI_ITERATOR_CONTEXT();
2236
+ iterator->aborted_ = true;
2237
+ NAPI_RETURN_UNDEFINED();
2238
+ }
2239
+
2240
+ /**
2241
+ * Worker class for nexting an iterator.
2242
+ */
2243
+ struct NextWorker final : public BaseWorker {
2244
+ NextWorker (napi_env env, Iterator* iterator, uint32_t size, napi_deferred deferred)
2245
+ : BaseWorker(env, iterator->database, deferred, "classic_level.iterator.next"),
2246
+ iterator_(iterator), size_(size), ok_() {}
2247
+
2248
+ ~NextWorker () {}
2249
+
2250
+ void DoExecute () override {
2251
+ if (!iterator_->DidSeek()) {
2252
+ iterator_->SeekToRange();
2253
+ }
2254
+
2255
+ ok_ = iterator_->ReadMany(size_);
2256
+
2257
+ if (!ok_) {
2258
+ SetStatus(iterator_->Status());
2259
+ }
2260
+ }
2261
+
2262
+ void HandleOKCallback (napi_env env, napi_deferred deferred) override {
2263
+ if (iterator_->aborted_) {
2264
+ napi_value err = CreateCodeError(env, "LEVEL_ABORTED", "Operation has been aborted");
2265
+ napi_value name;
2266
+ napi_create_string_utf8(env, "AbortError", NAPI_AUTO_LENGTH, &name);
2267
+ napi_set_named_property(env, err, "name", name);
2268
+ napi_reject_deferred(env, deferred, err);
2269
+ return;
2270
+ }
2271
+
2272
+ size_t size = iterator_->cache_.size();
2273
+ napi_value jsArray;
2274
+ napi_create_array_with_length(env, size, &jsArray);
2275
+
2276
+ const Encoding ke = iterator_->keyEncoding_;
2277
+ const Encoding ve = iterator_->valueEncoding_;
2278
+
2279
+ for (uint32_t idx = 0; idx < size; idx++) {
2280
+ napi_value element;
2281
+ iterator_->cache_[idx].ConvertByMode(env, Mode::entries, ke, ve, element);
2282
+ napi_set_element(env, jsArray, idx, element);
2283
+ }
2284
+
2285
+ // TODO: use state_ internally too, replacing ended_?
2286
+ if (iterator_->ended_) {
2287
+ *iterator_->state_ |= STATE_ENDED;
2288
+ }
2289
+
2290
+ napi_resolve_deferred(env, deferred, jsArray);
2291
+ }
2292
+
2293
+ void DoFinally (napi_env env) override {
2294
+ iterator_->nexting_ = false;
2295
+ BaseWorker::DoFinally(env);
2296
+ }
2297
+
2298
+ private:
2299
+ Iterator* iterator_;
2300
+ uint32_t size_;
2301
+ bool ok_;
2302
+ };
2303
+
2304
+ /**
2305
+ * Advance repeatedly and get multiple entries at once.
2306
+ */
2307
+ NAPI_METHOD(iterator_nextv) {
2308
+ NAPI_ARGV(2);
2309
+ NAPI_ITERATOR_CONTEXT();
2310
+ NAPI_PROMISE();
2311
+
2312
+ uint32_t size;
2313
+ NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &size));
2314
+ if (size == 0) size = 1;
2315
+
2316
+ // AbstractIterator should not call _next() or _nextv() after _close()
2317
+ assert(!iterator->hasClosed_);
2318
+
2319
+ if (iterator->ended_) {
2320
+ napi_value empty;
2321
+ napi_create_array_with_length(env, 0, &empty);
2322
+ napi_resolve_deferred(env, deferred, empty);
2323
+ } else {
2324
+ NextWorker* worker = new NextWorker(env, iterator, size, deferred);
2325
+ iterator->nexting_ = true;
2326
+ worker->Queue(env);
2327
+ }
2328
+
2329
+ return promise;
2330
+ }
2331
+
2332
+ /**
2333
+ * Worker class for batch write operation.
2334
+ */
2335
+ struct BatchWorker final : public PriorityWorker {
2336
+ BatchWorker (napi_env env,
2337
+ Database* database,
2338
+ napi_deferred deferred,
2339
+ leveldb::WriteBatch* batch,
2340
+ const bool sync,
2341
+ const bool hasData)
2342
+ : PriorityWorker(env, database, deferred, "classic_level.batch.do"),
2343
+ batch_(batch), hasData_(hasData) {
2344
+ options_.sync = sync;
2345
+ }
2346
+
2347
+ ~BatchWorker () {
2348
+ delete batch_;
2349
+ }
2350
+
2351
+ void DoExecute () override {
2352
+ if (hasData_) {
2353
+ SetStatus(database_->WriteBatch(options_, batch_));
2354
+ }
2355
+ }
2356
+
2357
+ private:
2358
+ leveldb::WriteOptions options_;
2359
+ leveldb::WriteBatch* batch_;
2360
+ const bool hasData_;
2361
+ };
2362
+
2363
+ /**
2364
+ * Does a batch write operation on a database.
2365
+ */
2366
+ NAPI_METHOD(batch_do) {
2367
+ NAPI_ARGV(3);
2368
+ NAPI_DB_CONTEXT();
2369
+ NAPI_PROMISE();
2370
+
2371
+ napi_value array = argv[1];
2372
+ const bool sync = BooleanProperty(env, argv[2], "sync", false);
2373
+
2374
+ uint32_t length;
2375
+ napi_get_array_length(env, array, &length);
2376
+
2377
+ leveldb::WriteBatch* batch = new leveldb::WriteBatch();
2378
+ bool hasData = false;
2379
+
2380
+ for (uint32_t i = 0; i < length; i++) {
2381
+ napi_value element;
2382
+ napi_get_element(env, array, i, &element);
2383
+
2384
+ if (!IsObject(env, element)) continue;
2385
+
2386
+ std::string type = StringProperty(env, element, "type");
2387
+
2388
+ if (type == "del") {
2389
+ if (!HasProperty(env, element, "key")) continue;
2390
+ leveldb::Slice key = ToSlice(env, GetProperty(env, element, "key"));
2391
+
2392
+ batch->Delete(key);
2393
+ if (!hasData) hasData = true;
2394
+
2395
+ DisposeSliceBuffer(key);
2396
+ } else if (type == "put") {
2397
+ if (!HasProperty(env, element, "key")) continue;
2398
+ if (!HasProperty(env, element, "value")) continue;
2399
+
2400
+ leveldb::Slice key = ToSlice(env, GetProperty(env, element, "key"));
2401
+ leveldb::Slice value = ToSlice(env, GetProperty(env, element, "value"));
2402
+
2403
+ batch->Put(key, value);
2404
+ if (!hasData) hasData = true;
2405
+
2406
+ DisposeSliceBuffer(key);
2407
+ DisposeSliceBuffer(value);
2408
+ }
2409
+ }
2410
+
2411
+ BatchWorker* worker = new BatchWorker(
2412
+ env, database, deferred, batch, sync, hasData
2413
+ );
2414
+
2415
+ worker->Queue(env);
2416
+ return promise;
2417
+ }
2418
+
2419
+ /**
2420
+ * Owns a WriteBatch.
2421
+ */
2422
+ struct Batch {
2423
+ Batch (Database* database)
2424
+ : database_(database),
2425
+ batch_(new leveldb::WriteBatch()),
2426
+ hasData_(false) {}
2427
+
2428
+ ~Batch () {
2429
+ delete batch_;
2430
+ }
2431
+
2432
+ void Put (leveldb::Slice key, leveldb::Slice value) {
2433
+ batch_->Put(key, value);
2434
+ hasData_ = true;
2435
+ }
2436
+
2437
+ void Del (leveldb::Slice key) {
2438
+ batch_->Delete(key);
2439
+ hasData_ = true;
2440
+ }
2441
+
2442
+ void Clear () {
2443
+ batch_->Clear();
2444
+ hasData_ = false;
2445
+ }
2446
+
2447
+ leveldb::Status Write (bool sync) {
2448
+ leveldb::WriteOptions options;
2449
+ options.sync = sync;
2450
+ return database_->WriteBatch(options, batch_);
2451
+ }
2452
+
2453
+ Database* database_;
2454
+ leveldb::WriteBatch* batch_;
2455
+ bool hasData_;
2456
+ };
2457
+
2458
+ /**
2459
+ * Runs when a Batch is garbage collected.
2460
+ */
2461
+ static void FinalizeBatch (napi_env env, void* data, void* hint) {
2462
+ if (data) {
2463
+ delete (Batch*)data;
2464
+ }
2465
+ }
2466
+
2467
+ /**
2468
+ * Return a batch object.
2469
+ */
2470
+ NAPI_METHOD(batch_init) {
2471
+ NAPI_ARGV(1);
2472
+ NAPI_DB_CONTEXT();
2473
+
2474
+ Batch* batch = new Batch(database);
2475
+
2476
+ napi_value result;
2477
+ NAPI_STATUS_THROWS(napi_create_external(env, batch,
2478
+ FinalizeBatch,
2479
+ NULL, &result));
2480
+ return result;
2481
+ }
2482
+
2483
+ /**
2484
+ * Adds a put instruction to a batch object.
2485
+ */
2486
+ NAPI_METHOD(batch_put) {
2487
+ NAPI_ARGV(3);
2488
+ NAPI_BATCH_CONTEXT();
2489
+
2490
+ leveldb::Slice key = ToSlice(env, argv[1]);
2491
+ leveldb::Slice value = ToSlice(env, argv[2]);
2492
+ batch->Put(key, value);
2493
+ DisposeSliceBuffer(key);
2494
+ DisposeSliceBuffer(value);
2495
+
2496
+ NAPI_RETURN_UNDEFINED();
2497
+ }
2498
+
2499
+ /**
2500
+ * Adds a delete instruction to a batch object.
2501
+ */
2502
+ NAPI_METHOD(batch_del) {
2503
+ NAPI_ARGV(2);
2504
+ NAPI_BATCH_CONTEXT();
2505
+
2506
+ leveldb::Slice key = ToSlice(env, argv[1]);
2507
+ batch->Del(key);
2508
+ DisposeSliceBuffer(key);
2509
+
2510
+ NAPI_RETURN_UNDEFINED();
2511
+ }
2512
+
2513
+ /**
2514
+ * Clears a batch object.
2515
+ */
2516
+ NAPI_METHOD(batch_clear) {
2517
+ NAPI_ARGV(1);
2518
+ NAPI_BATCH_CONTEXT();
2519
+
2520
+ batch->Clear();
2521
+
2522
+ NAPI_RETURN_UNDEFINED();
2523
+ }
2524
+
2525
+ /**
2526
+ * Worker class for batch write operation.
2527
+ */
2528
+ struct BatchWriteWorker final : public PriorityWorker {
2529
+ BatchWriteWorker (napi_env env,
2530
+ napi_value context,
2531
+ Batch* batch,
2532
+ napi_deferred deferred,
2533
+ const bool sync)
2534
+ : PriorityWorker(env, batch->database_, deferred, "classic_level.batch.write"),
2535
+ batch_(batch),
2536
+ sync_(sync) {
2537
+ // Prevent GC of batch object before we execute
2538
+ NAPI_STATUS_THROWS_VOID(napi_create_reference(env, context, 1, &contextRef_));
2539
+ }
2540
+
2541
+ ~BatchWriteWorker () {}
2542
+
2543
+ void DoExecute () override {
2544
+ if (batch_->hasData_) {
2545
+ SetStatus(batch_->Write(sync_));
2546
+ }
2547
+ }
2548
+
2549
+ void DoFinally (napi_env env) override {
2550
+ napi_delete_reference(env, contextRef_);
2551
+ PriorityWorker::DoFinally(env);
2552
+ }
2553
+
2554
+ private:
2555
+ Batch* batch_;
2556
+ const bool sync_;
2557
+ napi_ref contextRef_;
2558
+ };
2559
+
2560
+ /**
2561
+ * Writes a batch object.
2562
+ */
2563
+ NAPI_METHOD(batch_write) {
2564
+ NAPI_ARGV(2);
2565
+ NAPI_BATCH_CONTEXT();
2566
+ NAPI_PROMISE();
2567
+
2568
+ napi_value options = argv[1];
2569
+ const bool sync = BooleanProperty(env, options, "sync", false);
2570
+
2571
+ BatchWriteWorker* worker = new BatchWriteWorker(
2572
+ env, argv[0], batch, deferred, sync
2573
+ );
2574
+
2575
+ worker->Queue(env);
2576
+ return promise;
2577
+ }
2578
+
2579
+ /**
2580
+ * Create a snapshot context.
2581
+ */
2582
+ NAPI_METHOD(snapshot_init) {
2583
+ NAPI_ARGV(1);
2584
+ NAPI_DB_CONTEXT();
2585
+
2586
+ ExplicitSnapshot* snapshot = new ExplicitSnapshot(database);
2587
+
2588
+ napi_value context;
2589
+ NAPI_STATUS_THROWS(napi_create_external(
2590
+ env,
2591
+ snapshot,
2592
+ Resource::CollectGarbage,
2593
+ NULL,
2594
+ &context
2595
+ ));
2596
+
2597
+ snapshot->Attach(env, context);
2598
+ return context;
2599
+ }
2600
+
2601
+ /**
2602
+ * Closes the snapshot.
2603
+ */
2604
+ NAPI_METHOD(snapshot_close) {
2605
+ NAPI_ARGV(1);
2606
+ NAPI_SNAPSHOT_CONTEXT();
2607
+
2608
+ snapshot->CloseResource();
2609
+ snapshot->Detach(env);
2610
+
2611
+ NAPI_RETURN_UNDEFINED();
2612
+ }
2613
+
2614
+ /**
2615
+ * All exported functions.
2616
+ */
2617
+ NAPI_INIT() {
2618
+ NAPI_EXPORT_FUNCTION(db_init);
2619
+ NAPI_EXPORT_FUNCTION(db_set_shared_buffer)
2620
+ NAPI_EXPORT_FUNCTION(db_open);
2621
+ NAPI_EXPORT_FUNCTION(db_close);
2622
+ NAPI_EXPORT_FUNCTION(db_put);
2623
+ NAPI_EXPORT_FUNCTION(db_get);
2624
+ NAPI_EXPORT_FUNCTION(db_get_sync);
2625
+ NAPI_EXPORT_FUNCTION(db_get_many);
2626
+ NAPI_EXPORT_FUNCTION(db_has);
2627
+ NAPI_EXPORT_FUNCTION(db_has_many);
2628
+ NAPI_EXPORT_FUNCTION(db_del);
2629
+ NAPI_EXPORT_FUNCTION(db_clear);
2630
+ NAPI_EXPORT_FUNCTION(db_approximate_size);
2631
+ NAPI_EXPORT_FUNCTION(db_compact_range);
2632
+ NAPI_EXPORT_FUNCTION(db_get_property);
2633
+
2634
+ NAPI_EXPORT_FUNCTION(destroy_db);
2635
+ NAPI_EXPORT_FUNCTION(repair_db);
2636
+
2637
+ NAPI_EXPORT_FUNCTION(iterator_init);
2638
+ NAPI_EXPORT_FUNCTION(iterator_seek);
2639
+ NAPI_EXPORT_FUNCTION(iterator_close);
2640
+ NAPI_EXPORT_FUNCTION(iterator_nextv);
2641
+ NAPI_EXPORT_FUNCTION(iterator_abort);
2642
+
2643
+ NAPI_EXPORT_FUNCTION(batch_do);
2644
+ NAPI_EXPORT_FUNCTION(batch_init);
2645
+ NAPI_EXPORT_FUNCTION(batch_put);
2646
+ NAPI_EXPORT_FUNCTION(batch_del);
2647
+ NAPI_EXPORT_FUNCTION(batch_clear);
2648
+ NAPI_EXPORT_FUNCTION(batch_write);
2649
+
2650
+ NAPI_EXPORT_FUNCTION(snapshot_init);
2651
+ NAPI_EXPORT_FUNCTION(snapshot_close);
2652
+ }