fs.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // Copyright 2019-2021 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. import { invokeTauriCommand } from './helpers/tauri'
  5. export enum BaseDirectory {
  6. Audio = 1,
  7. Cache,
  8. Config,
  9. Data,
  10. LocalData,
  11. Desktop,
  12. Document,
  13. Download,
  14. Executable,
  15. Font,
  16. Home,
  17. Picture,
  18. Public,
  19. Runtime,
  20. Template,
  21. Video,
  22. Resource,
  23. App,
  24. Current
  25. }
  26. export interface FsOptions {
  27. dir?: BaseDirectory
  28. }
  29. export interface FsDirOptions {
  30. dir?: BaseDirectory
  31. recursive?: boolean
  32. }
  33. export interface FsTextFileOption {
  34. path: string
  35. contents: string
  36. }
  37. export interface FsBinaryFileOption {
  38. path: string
  39. contents: ArrayBuffer
  40. }
  41. export interface FileEntry {
  42. path: string
  43. // name of the directory/file
  44. // can be null if the path terminates with `..`
  45. name?: string
  46. // children of this entry if it's a directory; null otherwise
  47. children?: FileEntry[]
  48. }
  49. /**
  50. * @name readTextFile
  51. * @description Reads a file as text
  52. * @param {string} filePath path to the file
  53. * @param {FsOptions} [options] configuration object
  54. * @param {BaseDirectory} [options.dir] base directory
  55. * @return {Promise<string>}
  56. */
  57. async function readTextFile(
  58. filePath: string,
  59. options: FsOptions = {}
  60. ): Promise<string> {
  61. return invokeTauriCommand<string>({
  62. __tauriModule: 'Fs',
  63. message: {
  64. cmd: 'readTextFile',
  65. path: filePath,
  66. options
  67. }
  68. })
  69. }
  70. /**
  71. * @name readBinaryFile
  72. * @description Reads a file as binary
  73. * @param {string} filePath path to the file
  74. * @param {FsOptions} [options] configuration object
  75. * @param {BaseDirectory} [options.dir] base directory
  76. * @return {Promise<number[]>}
  77. */
  78. async function readBinaryFile(
  79. filePath: string,
  80. options: FsOptions = {}
  81. ): Promise<number[]> {
  82. return invokeTauriCommand<number[]>({
  83. __tauriModule: 'Fs',
  84. message: {
  85. cmd: 'readBinaryFile',
  86. path: filePath,
  87. options
  88. }
  89. })
  90. }
  91. /**
  92. * writes a text file
  93. *
  94. * @param file
  95. * @param file.path path of the file
  96. * @param file.contents contents of the file
  97. * @param [options] configuration object
  98. * @param [options.dir] base directory
  99. * @return
  100. */
  101. async function writeFile(
  102. file: FsTextFileOption,
  103. options: FsOptions = {}
  104. ): Promise<void> {
  105. if (typeof options === 'object') {
  106. Object.freeze(options)
  107. }
  108. if (typeof file === 'object') {
  109. Object.freeze(file)
  110. }
  111. return invokeTauriCommand({
  112. __tauriModule: 'Fs',
  113. message: {
  114. cmd: 'writeFile',
  115. path: file.path,
  116. contents: file.contents,
  117. options
  118. }
  119. })
  120. }
  121. const CHUNK_SIZE = 65536
  122. /**
  123. * convert an Uint8Array to ascii string
  124. *
  125. * @param arr
  126. * @return ASCII string
  127. */
  128. function uint8ArrayToString(arr: Uint8Array): string {
  129. if (arr.length < CHUNK_SIZE) {
  130. return String.fromCharCode.apply(null, Array.from(arr))
  131. }
  132. let result = ''
  133. const arrLen = arr.length
  134. for (let i = 0; i < arrLen; i++) {
  135. const chunk = arr.subarray(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE)
  136. result += String.fromCharCode.apply(null, Array.from(chunk))
  137. }
  138. return result
  139. }
  140. /**
  141. * convert an ArrayBuffer to base64 encoded string
  142. *
  143. * @param buffer
  144. * @return base64 encoded string
  145. */
  146. function arrayBufferToBase64(buffer: ArrayBuffer): string {
  147. const str = uint8ArrayToString(new Uint8Array(buffer))
  148. return btoa(str)
  149. }
  150. /**
  151. * writes a binary file
  152. *
  153. * @param file
  154. * @param file.path path of the file
  155. * @param file.contents contents of the file
  156. * @param [options] configuration object
  157. * @param [options.dir] base directory
  158. * @return
  159. */
  160. async function writeBinaryFile(
  161. file: FsBinaryFileOption,
  162. options: FsOptions = {}
  163. ): Promise<void> {
  164. if (typeof options === 'object') {
  165. Object.freeze(options)
  166. }
  167. if (typeof file === 'object') {
  168. Object.freeze(file)
  169. }
  170. return invokeTauriCommand({
  171. __tauriModule: 'Fs',
  172. message: {
  173. cmd: 'writeBinaryFile',
  174. path: file.path,
  175. contents: arrayBufferToBase64(file.contents),
  176. options
  177. }
  178. })
  179. }
  180. /**
  181. * list directory files
  182. *
  183. * @param dir path to the directory to read
  184. * @param [options] configuration object
  185. * @param [options.recursive] whether to list dirs recursively or not
  186. * @param [options.dir] base directory
  187. * @return
  188. */
  189. async function readDir(
  190. dir: string,
  191. options: FsDirOptions = {}
  192. ): Promise<FileEntry[]> {
  193. return invokeTauriCommand({
  194. __tauriModule: 'Fs',
  195. message: {
  196. cmd: 'readDir',
  197. path: dir,
  198. options
  199. }
  200. })
  201. }
  202. /**
  203. * Creates a directory
  204. * If one of the path's parent components doesn't exist
  205. * and the `recursive` option isn't set to true, it will be rejected
  206. *
  207. * @param dir path to the directory to create
  208. * @param [options] configuration object
  209. * @param [options.recursive] whether to create the directory's parent components or not
  210. * @param [options.dir] base directory
  211. * @return
  212. */
  213. async function createDir(
  214. dir: string,
  215. options: FsDirOptions = {}
  216. ): Promise<void> {
  217. return invokeTauriCommand({
  218. __tauriModule: 'Fs',
  219. message: {
  220. cmd: 'createDir',
  221. path: dir,
  222. options
  223. }
  224. })
  225. }
  226. /**
  227. * Removes a directory
  228. * If the directory is not empty and the `recursive` option isn't set to true, it will be rejected
  229. *
  230. * @param dir path to the directory to remove
  231. * @param [options] configuration object
  232. * @param [options.recursive] whether to remove all of the directory's content or not
  233. * @param [options.dir] base directory
  234. * @return
  235. */
  236. async function removeDir(
  237. dir: string,
  238. options: FsDirOptions = {}
  239. ): Promise<void> {
  240. return invokeTauriCommand({
  241. __tauriModule: 'Fs',
  242. message: {
  243. cmd: 'removeDir',
  244. path: dir,
  245. options
  246. }
  247. })
  248. }
  249. /**
  250. * Copy file
  251. *
  252. * @param source
  253. * @param destination
  254. * @param [options] configuration object
  255. * @param [options.dir] base directory
  256. * @return
  257. */
  258. async function copyFile(
  259. source: string,
  260. destination: string,
  261. options: FsOptions = {}
  262. ): Promise<void> {
  263. return invokeTauriCommand({
  264. __tauriModule: 'Fs',
  265. message: {
  266. cmd: 'copyFile',
  267. source,
  268. destination,
  269. options
  270. }
  271. })
  272. }
  273. /**
  274. * Removes a file
  275. *
  276. * @param file path to the file to remove
  277. * @param [options] configuration object
  278. * @param [options.dir] base directory
  279. * @return
  280. */
  281. async function removeFile(
  282. file: string,
  283. options: FsOptions = {}
  284. ): Promise<void> {
  285. return invokeTauriCommand({
  286. __tauriModule: 'Fs',
  287. message: {
  288. cmd: 'removeFile',
  289. path: file,
  290. options: options
  291. }
  292. })
  293. }
  294. /**
  295. * Renames a file
  296. *
  297. * @param oldPath
  298. * @param newPath
  299. * @param [options] configuration object
  300. * @param [options.dir] base directory
  301. * @return
  302. */
  303. async function renameFile(
  304. oldPath: string,
  305. newPath: string,
  306. options: FsOptions = {}
  307. ): Promise<void> {
  308. return invokeTauriCommand({
  309. __tauriModule: 'Fs',
  310. message: {
  311. cmd: 'renameFile',
  312. oldPath,
  313. newPath,
  314. options
  315. }
  316. })
  317. }
  318. export {
  319. BaseDirectory as Dir,
  320. readTextFile,
  321. readBinaryFile,
  322. writeFile,
  323. writeBinaryFile,
  324. readDir,
  325. createDir,
  326. removeDir,
  327. copyFile,
  328. removeFile,
  329. renameFile
  330. }