@hxa-rn/rn-fetch-blob 0.12.0
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.
- package/LICENSE +21 -0
- package/README.md +290 -0
- package/harmony/fetch_blob/LICENSE +21 -0
- package/harmony/fetch_blob/NOTICE +33 -0
- package/harmony/fetch_blob/OAT.xml +38 -0
- package/harmony/fetch_blob/build-profile.json5 +16 -0
- package/harmony/fetch_blob/hvigorfile.ts +2 -0
- package/harmony/fetch_blob/index.ets +1 -0
- package/harmony/fetch_blob/oh-package.json5 +14 -0
- package/harmony/fetch_blob/src/main/cpp/CMakeLists.txt +15 -0
- package/harmony/fetch_blob/src/main/cpp/FetchBlobPackage.h +13 -0
- package/harmony/fetch_blob/src/main/cpp/generated/RNOH/generated/BaseFetchBlobPackage.h +72 -0
- package/harmony/fetch_blob/src/main/cpp/generated/RNOH/generated/turbo_modules/RNFetchBlob.cpp +55 -0
- package/harmony/fetch_blob/src/main/cpp/generated/RNOH/generated/turbo_modules/RNFetchBlob.h +16 -0
- package/harmony/fetch_blob/src/main/ets/FetchBlobTurboModulesFactory.ets +18 -0
- package/harmony/fetch_blob/src/main/ets/Logger.ts +40 -0
- package/harmony/fetch_blob/src/main/ets/RNFetchBlobConfig.ts +45 -0
- package/harmony/fetch_blob/src/main/ets/RNFetchBlobFS.ts +673 -0
- package/harmony/fetch_blob/src/main/ets/RNFetchBlobImpl.ts +246 -0
- package/harmony/fetch_blob/src/main/ets/RNFetchBlobReq.ts +530 -0
- package/harmony/fetch_blob/src/main/ets/RNFetchBlobStream.ts +169 -0
- package/harmony/fetch_blob/src/main/ets/RNFetchBlobTurboModule.ts +192 -0
- package/harmony/fetch_blob/src/main/ets/generated/index.ets +5 -0
- package/harmony/fetch_blob/src/main/ets/generated/ts.ts +5 -0
- package/harmony/fetch_blob/src/main/ets/generated/turboModules/RNFetchBlob.ts +92 -0
- package/harmony/fetch_blob/src/main/ets/generated/turboModules/ts.ts +5 -0
- package/harmony/fetch_blob/src/main/module.json5 +22 -0
- package/harmony/fetch_blob/src/main/resources/base/element/string.json +8 -0
- package/harmony/fetch_blob/src/main/resources/en_US/element/string.json +8 -0
- package/harmony/fetch_blob/src/main/resources/zh_CN/element/string.json +8 -0
- package/harmony/fetch_blob.har +0 -0
- package/package.json +59 -0
- package/src/android.js +62 -0
- package/src/class/RNFetchBlobFile.js +17 -0
- package/src/class/RNFetchBlobReadStream.js +82 -0
- package/src/class/RNFetchBlobSession.js +74 -0
- package/src/class/RNFetchBlobWriteStream.js +57 -0
- package/src/class/StatefulPromise.js +7 -0
- package/src/fs.js +432 -0
- package/src/index.d.ts +690 -0
- package/src/index.js +577 -0
- package/src/ios.js +54 -0
- package/src/json-stream.js +45 -0
- package/src/lib/oboe-browser.min.js +1 -0
- package/src/polyfill/Blob.js +362 -0
- package/src/polyfill/Event.js +11 -0
- package/src/polyfill/EventTarget.js +79 -0
- package/src/polyfill/Fetch.js +213 -0
- package/src/polyfill/File.js +27 -0
- package/src/polyfill/FileReader.js +90 -0
- package/src/polyfill/ProgressEvent.js +32 -0
- package/src/polyfill/XMLHttpRequest.js +446 -0
- package/src/polyfill/XMLHttpRequestEventTarget.js +118 -0
- package/src/polyfill/index.js +11 -0
- package/src/specs/v1/NativeRNFetchBlob.ts +85 -0
- package/src/types.js +64 -0
- package/src/utils/log.js +40 -0
- package/src/utils/unicode.js +7 -0
- package/src/utils/uri.js +28 -0
- package/src/utils/uuid.js +4 -0
|
@@ -0,0 +1,673 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2026. All rights reserved.
|
|
3
|
+
* HarmonyOS adaptation of rn-fetch-blob (RNFetchBlob TurboModule).
|
|
4
|
+
*
|
|
5
|
+
* File system operations aligned with the original library's FS module.
|
|
6
|
+
* All file APIs use @ohos.file.fs (Core File Kit) with sandbox paths.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import common from '@ohos.app.ability.common';
|
|
10
|
+
import fs from '@ohos.file.fs';
|
|
11
|
+
import { BusinessError } from '@ohos.base';
|
|
12
|
+
import buffer from '@ohos.buffer';
|
|
13
|
+
import hash from '@ohos.file.hash';
|
|
14
|
+
import statvfs from '@ohos.file.statvfs';
|
|
15
|
+
import { filePreview } from '@kit.PreviewKit';
|
|
16
|
+
import fileUri from '@ohos.file.fileuri';
|
|
17
|
+
import Logger from './Logger';
|
|
18
|
+
import hilog from '@ohos.hilog';
|
|
19
|
+
|
|
20
|
+
const DOMAIN: number = 0xFF00;
|
|
21
|
+
const TAG: string = 'RNFetchBlob';
|
|
22
|
+
|
|
23
|
+
const FILE_OR_DIR_NOT_EXIST: number = 13900002;
|
|
24
|
+
const FOLDER_EXISTS: number = 13900015;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Callback types used across FS methods. `err` is a human readable message or
|
|
28
|
+
* null; `data` is the result object (stat / dir entries / df result).
|
|
29
|
+
*/
|
|
30
|
+
export type ErrorCallback = (err: string | null) => void;
|
|
31
|
+
export type DataErrorCallback = (err: string | null, data?: Object | null) => void;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Stat object shape expected by the JS side (RNFetchBlobStat in fs.js).
|
|
35
|
+
*/
|
|
36
|
+
export class RNFetchBlobStat {
|
|
37
|
+
filename: string = '';
|
|
38
|
+
path: string = '';
|
|
39
|
+
type: string = '';
|
|
40
|
+
size: number = 0;
|
|
41
|
+
lastModified: number = 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default class RNFetchBlobFS {
|
|
45
|
+
private context: common.UIAbilityContext;
|
|
46
|
+
|
|
47
|
+
constructor(context: common.UIAbilityContext) {
|
|
48
|
+
this.context = context;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getSystemFolders(): Object {
|
|
52
|
+
let res: Record<string, Object> = {};
|
|
53
|
+
res['CacheDir'] = this.context.cacheDir;
|
|
54
|
+
res['DocumentDir'] = this.context.filesDir;
|
|
55
|
+
res['DownloadDir'] = this.context.filesDir;
|
|
56
|
+
res['MainBundleDir'] = this.context.bundleCodeDir;
|
|
57
|
+
// Align with Android getExternalFilesDir(type): return typed sandbox
|
|
58
|
+
// subdirs and create them if missing (string concat alone does not).
|
|
59
|
+
let movieDir: string = this.context.filesDir + '/movie';
|
|
60
|
+
let musicDir: string = this.context.filesDir + '/music';
|
|
61
|
+
let pictureDir: string = this.context.filesDir + '/picture';
|
|
62
|
+
this.ensureDirExists(movieDir);
|
|
63
|
+
this.ensureDirExists(musicDir);
|
|
64
|
+
this.ensureDirExists(pictureDir);
|
|
65
|
+
res['MovieDir'] = movieDir;
|
|
66
|
+
res['MusicDir'] = musicDir;
|
|
67
|
+
res['PictureDir'] = pictureDir;
|
|
68
|
+
// Android-only / iOS-only constants have no sandbox equivalent on HarmonyOS.
|
|
69
|
+
res['DCIMDir'] = '';
|
|
70
|
+
res['SDCardDir'] = '';
|
|
71
|
+
res['SDCardApplicationDir'] = '';
|
|
72
|
+
res['LibraryDir'] = '';
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private ensureDirExists(path: string): void {
|
|
77
|
+
try {
|
|
78
|
+
if (fs.accessSync(path)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
} catch (accessErr) {
|
|
82
|
+
// path does not exist yet
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
fs.mkdirSync(path, true);
|
|
86
|
+
} catch (mkdirErr) {
|
|
87
|
+
let e: BusinessError = mkdirErr as BusinessError;
|
|
88
|
+
if (e.code !== FOLDER_EXISTS) {
|
|
89
|
+
hilog.error(DOMAIN, TAG, '%{public}s',
|
|
90
|
+
`ensureDirExists failed: ${e.message}, code ${e.code}, path ${path}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
createFile(path: string, data: string, encoding: string): Promise<string> {
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
let file: fs.File | undefined = undefined;
|
|
98
|
+
try {
|
|
99
|
+
if (encoding.toLowerCase() !== 'utf8' && encoding.toLowerCase() !== 'utf-8') {
|
|
100
|
+
reject(null);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Align with Android File.createNewFile / EEXIST: createFile must not overwrite.
|
|
104
|
+
let exists: boolean = false;
|
|
105
|
+
try {
|
|
106
|
+
exists = fs.accessSync(path);
|
|
107
|
+
} catch (e) {
|
|
108
|
+
exists = false;
|
|
109
|
+
}
|
|
110
|
+
if (exists) {
|
|
111
|
+
reject(`File \`${path}\` already exists`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
file = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
|
|
115
|
+
fs.writeSync(file.fd, data, { encoding: 'utf-8' });
|
|
116
|
+
resolve(path);
|
|
117
|
+
} catch (err) {
|
|
118
|
+
let e: BusinessError = err as BusinessError;
|
|
119
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `createFile failed with error message: ${e.message}, error code: ${e.code}`);
|
|
120
|
+
reject(e.message);
|
|
121
|
+
} finally {
|
|
122
|
+
if (file !== undefined) {
|
|
123
|
+
try {
|
|
124
|
+
fs.closeSync(file);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
let ce: BusinessError = e as BusinessError;
|
|
127
|
+
hilog.error(DOMAIN, TAG, '%{public}s', 'close failed: ' + ce.message);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
createFileASCII(path: string, data: number[]): Promise<void> {
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
let file: fs.File | undefined = undefined;
|
|
137
|
+
try {
|
|
138
|
+
// Align with Android createFileASCII: refuse if destination already exists.
|
|
139
|
+
let exists: boolean = false;
|
|
140
|
+
try {
|
|
141
|
+
exists = fs.accessSync(path);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
exists = false;
|
|
144
|
+
}
|
|
145
|
+
if (exists) {
|
|
146
|
+
reject(`create file error: failed to create file at path \`${path}\`, file already exists.`);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
file = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
|
|
150
|
+
let buf = buffer.from(data);
|
|
151
|
+
let writeLen: number = fs.writeSync(file.fd, buf.toString('utf-8'), { encoding: 'utf-8' });
|
|
152
|
+
if (writeLen < 0) {
|
|
153
|
+
reject('write failed');
|
|
154
|
+
} else {
|
|
155
|
+
Logger.info(`createFileASCII write data to file succeed and size is: ${writeLen}`);
|
|
156
|
+
resolve();
|
|
157
|
+
}
|
|
158
|
+
} catch (err) {
|
|
159
|
+
let e: BusinessError = err as BusinessError;
|
|
160
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `createFileASCII failed with error message: ${e.message}, error code: ${e.code}`);
|
|
161
|
+
reject(e.message);
|
|
162
|
+
} finally {
|
|
163
|
+
if (file !== undefined) {
|
|
164
|
+
try {
|
|
165
|
+
fs.closeSync(file);
|
|
166
|
+
} catch (e) {
|
|
167
|
+
let ce: BusinessError = e as BusinessError;
|
|
168
|
+
hilog.error(DOMAIN, TAG, '%{public}s', 'close failed: ' + ce.message);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
writeFile(path: string, encoding: string, data: string, append: boolean): Promise<number> {
|
|
176
|
+
return new Promise((resolve, reject) => {
|
|
177
|
+
let file: fs.File | undefined = undefined;
|
|
178
|
+
try {
|
|
179
|
+
if (append) {
|
|
180
|
+
file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.APPEND);
|
|
181
|
+
} else {
|
|
182
|
+
// Align with Android FileOutputStream(path, false): truncate then write.
|
|
183
|
+
file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE | fs.OpenMode.TRUNC);
|
|
184
|
+
}
|
|
185
|
+
let writeLen: number = -1;
|
|
186
|
+
if (encoding.toLowerCase() === 'base64') {
|
|
187
|
+
let base64Reg = new RegExp('data:image/\\w+;base64,');
|
|
188
|
+
let base64Data = data.replace(base64Reg, '');
|
|
189
|
+
let dataBuffer = buffer.from(base64Data, 'base64');
|
|
190
|
+
writeLen = fs.writeSync(file.fd, dataBuffer.buffer);
|
|
191
|
+
} else {
|
|
192
|
+
writeLen = fs.writeSync(file.fd, data, { encoding: encoding === 'utf8' ? 'utf-8' : encoding });
|
|
193
|
+
}
|
|
194
|
+
Logger.info(`writeFile succeed and size is: ${writeLen}`);
|
|
195
|
+
resolve(writeLen);
|
|
196
|
+
} catch (err) {
|
|
197
|
+
let e: BusinessError = err as BusinessError;
|
|
198
|
+
if (e.code === FILE_OR_DIR_NOT_EXIST) {
|
|
199
|
+
try {
|
|
200
|
+
let dir = path.substring(0, path.lastIndexOf('/'));
|
|
201
|
+
fs.mkdirSync(dir, true);
|
|
202
|
+
this.writeFile(path, encoding, data, append).then((len: number) => {
|
|
203
|
+
resolve(len);
|
|
204
|
+
}).catch((e2: Object) => {
|
|
205
|
+
reject(e2);
|
|
206
|
+
});
|
|
207
|
+
} catch (e3) {
|
|
208
|
+
let e4: BusinessError = e3 as BusinessError;
|
|
209
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `writeFile mkdir failed: ${e4.message}, code ${e4.code}`);
|
|
210
|
+
reject(`writeFile failed with error message: ${e4.message}, error code: ${e4.code}`);
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `writeFile failed with error message: ${e.message}, error code: ${e.code}`);
|
|
214
|
+
reject(`writeFile failed with error message: ${e.message}, error code: ${e.code}`);
|
|
215
|
+
}
|
|
216
|
+
} finally {
|
|
217
|
+
if (file !== undefined) {
|
|
218
|
+
try {
|
|
219
|
+
fs.closeSync(file);
|
|
220
|
+
} catch (e) {
|
|
221
|
+
let ce: BusinessError = e as BusinessError;
|
|
222
|
+
hilog.error(DOMAIN, TAG, '%{public}s', 'close failed: ' + ce.message);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
writeFileArray(path: string, data: number[], append: boolean): Promise<number> {
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
231
|
+
let file: fs.File | undefined = undefined;
|
|
232
|
+
try {
|
|
233
|
+
let buf = buffer.from(data);
|
|
234
|
+
if (append) {
|
|
235
|
+
file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.APPEND);
|
|
236
|
+
} else {
|
|
237
|
+
// Align with Android FileOutputStream(path, false): truncate then write.
|
|
238
|
+
file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE | fs.OpenMode.TRUNC);
|
|
239
|
+
}
|
|
240
|
+
let writeLen: number = fs.writeSync(file.fd, buf.toString('utf-8'), { encoding: 'utf-8' });
|
|
241
|
+
Logger.info(`writeFileArray succeed and size is: ${writeLen}`);
|
|
242
|
+
resolve(writeLen);
|
|
243
|
+
} catch (err) {
|
|
244
|
+
let e: BusinessError = err as BusinessError;
|
|
245
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `writeFileArray failed with error message: ${e.message}, error code: ${e.code}`);
|
|
246
|
+
reject(`writeFileArray failed with error message: ${e.message}, error code: ${e.code}`);
|
|
247
|
+
} finally {
|
|
248
|
+
if (file !== undefined) {
|
|
249
|
+
try {
|
|
250
|
+
fs.closeSync(file);
|
|
251
|
+
} catch (e) {
|
|
252
|
+
let ce: BusinessError = e as BusinessError;
|
|
253
|
+
hilog.error(DOMAIN, TAG, '%{public}s', 'close failed: ' + ce.message);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
readFile(path: string, encoding: string): Promise<Object> {
|
|
261
|
+
return new Promise((resolve, reject) => {
|
|
262
|
+
let file: fs.File | undefined = undefined;
|
|
263
|
+
try {
|
|
264
|
+
let fileInfo = fs.statSync(path);
|
|
265
|
+
file = fs.openSync(path, fs.OpenMode.READ_ONLY);
|
|
266
|
+
let buf = new ArrayBuffer(fileInfo.size);
|
|
267
|
+
let readLen: number = fs.readSync(file.fd, buf);
|
|
268
|
+
let bytes = buffer.from(buf, 0, readLen);
|
|
269
|
+
let enc: string = encoding.toLowerCase();
|
|
270
|
+
if (enc === 'base64') {
|
|
271
|
+
resolve(bytes.toString('base64'));
|
|
272
|
+
} else if (enc === 'ascii') {
|
|
273
|
+
let ascUInt8Array: Uint8Array = new Uint8Array(bytes.buffer);
|
|
274
|
+
let ascArr: number[] = Array.from(ascUInt8Array);
|
|
275
|
+
resolve(ascArr);
|
|
276
|
+
} else {
|
|
277
|
+
resolve(bytes.toString('utf-8'));
|
|
278
|
+
}
|
|
279
|
+
} catch (err) {
|
|
280
|
+
let e: BusinessError = err as BusinessError;
|
|
281
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `readFile failed with error message: ${e.message}, error code: ${e.code}`);
|
|
282
|
+
reject(`readFile failed with error message: ${e.message}, error code: ${e.code}`);
|
|
283
|
+
} finally {
|
|
284
|
+
if (file !== undefined) {
|
|
285
|
+
try {
|
|
286
|
+
fs.closeSync(file);
|
|
287
|
+
} catch (e) {
|
|
288
|
+
let ce: BusinessError = e as BusinessError;
|
|
289
|
+
hilog.error(DOMAIN, TAG, '%{public}s', 'close failed: ' + ce.message);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
unlink(path: string, callback: ErrorCallback): void {
|
|
297
|
+
try {
|
|
298
|
+
fs.unlink(path, (err: BusinessError) => {
|
|
299
|
+
if (err) {
|
|
300
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `remove file failed with error message: ${err.message}`);
|
|
301
|
+
callback(`remove file failed with error message: ${err.message}`);
|
|
302
|
+
} else {
|
|
303
|
+
Logger.info('remove file succeed');
|
|
304
|
+
callback(null);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
} catch (err) {
|
|
308
|
+
let e: BusinessError = err as BusinessError;
|
|
309
|
+
let errMsg = `unlink failed with error message: ${e.message}, error code: ${e.code}`;
|
|
310
|
+
hilog.error(DOMAIN, TAG, '%{public}s', errMsg);
|
|
311
|
+
callback(errMsg);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
removeSession(paths: string[], callback: ErrorCallback): void {
|
|
316
|
+
// Align with Android removeSession: skip missing paths; only fail when an
|
|
317
|
+
// existing file cannot be deleted.
|
|
318
|
+
try {
|
|
319
|
+
let failuresToDelete: string[] = [];
|
|
320
|
+
for (let i = 0; i < paths.length; i++) {
|
|
321
|
+
let p: string = paths[i];
|
|
322
|
+
let exists: boolean = false;
|
|
323
|
+
try {
|
|
324
|
+
exists = fs.accessSync(p);
|
|
325
|
+
} catch (accessErr) {
|
|
326
|
+
exists = false;
|
|
327
|
+
}
|
|
328
|
+
if (!exists) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
fs.unlinkSync(p);
|
|
333
|
+
} catch (unlinkErr) {
|
|
334
|
+
let e: BusinessError = unlinkErr as BusinessError;
|
|
335
|
+
if (e.code === FILE_OR_DIR_NOT_EXIST) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
hilog.error(DOMAIN, TAG, '%{public}s',
|
|
339
|
+
`removeSession unlink failed: ${e.message}, code ${e.code}`);
|
|
340
|
+
failuresToDelete.push(p);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (failuresToDelete.length === 0) {
|
|
344
|
+
callback(null);
|
|
345
|
+
} else {
|
|
346
|
+
callback('Failed to delete: ' + failuresToDelete.join(', '));
|
|
347
|
+
}
|
|
348
|
+
} catch (err) {
|
|
349
|
+
let e: BusinessError = err as BusinessError;
|
|
350
|
+
callback(e.message);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
cp(path: string, dest: string, callback: DataErrorCallback): void {
|
|
355
|
+
try {
|
|
356
|
+
if (fs.accessSync(path)) {
|
|
357
|
+
fs.copyFileSync(path, dest);
|
|
358
|
+
callback(null, '');
|
|
359
|
+
} else {
|
|
360
|
+
callback('file is not exist', null);
|
|
361
|
+
}
|
|
362
|
+
} catch (err) {
|
|
363
|
+
hilog.error(DOMAIN, TAG, '%{public}s', 'cp failed');
|
|
364
|
+
callback('cp failed', null);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
mv(path: string, dest: string, callback: DataErrorCallback): void {
|
|
369
|
+
try {
|
|
370
|
+
fs.moveFileSync(path, dest);
|
|
371
|
+
callback(null, '');
|
|
372
|
+
} catch (err) {
|
|
373
|
+
let e: BusinessError = err as BusinessError;
|
|
374
|
+
let errMsg = `move file failed with error message: ${e.message}, error code: ${e.code}`;
|
|
375
|
+
hilog.error(DOMAIN, TAG, '%{public}s', errMsg);
|
|
376
|
+
callback(errMsg, null);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
mkdir(path: string): Promise<void> {
|
|
381
|
+
return new Promise((resolve, reject) => {
|
|
382
|
+
try {
|
|
383
|
+
fs.mkdir(path, true, (err: BusinessError) => {
|
|
384
|
+
if (err) {
|
|
385
|
+
if (err.code === FOLDER_EXISTS) {
|
|
386
|
+
reject('floder exists');
|
|
387
|
+
} else {
|
|
388
|
+
reject(`Directory could not be created ${err.message} ${err.code}`);
|
|
389
|
+
}
|
|
390
|
+
} else {
|
|
391
|
+
resolve();
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
} catch (err) {
|
|
395
|
+
let e: BusinessError = err as BusinessError;
|
|
396
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `mkdir failed: ${e.message}, code ${e.code}`);
|
|
397
|
+
reject(`Directory could not be created ${e.message} ${e.code}`);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
ls(path: string): Promise<string[]> {
|
|
403
|
+
return new Promise((resolve, reject) => {
|
|
404
|
+
try {
|
|
405
|
+
let exists: boolean = false;
|
|
406
|
+
try {
|
|
407
|
+
exists = fs.accessSync(path);
|
|
408
|
+
} catch (e) {
|
|
409
|
+
exists = false;
|
|
410
|
+
}
|
|
411
|
+
if (!exists) {
|
|
412
|
+
reject('file not exists');
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (!fs.statSync(path).isDirectory()) {
|
|
416
|
+
reject('directory not exists');
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
let filenames: string[] = fs.listFileSync(path);
|
|
420
|
+
resolve(filenames);
|
|
421
|
+
} catch (err) {
|
|
422
|
+
let e: BusinessError = err as BusinessError;
|
|
423
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `ls failed: ${e.message}, code ${e.code}`);
|
|
424
|
+
reject(`ls failed with error message: ${e.message}, error code: ${e.code}`);
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
exists(path: string, callback: (value: boolean, isDir?: boolean) => void): void {
|
|
430
|
+
try {
|
|
431
|
+
fs.stat(path, (err: BusinessError, res: fs.Stat) => {
|
|
432
|
+
if (err) {
|
|
433
|
+
callback(false, false);
|
|
434
|
+
} else {
|
|
435
|
+
fs.access(path, (accessErr: BusinessError, result: boolean) => {
|
|
436
|
+
if (accessErr) {
|
|
437
|
+
callback(false, false);
|
|
438
|
+
} else {
|
|
439
|
+
callback(result, res.isDirectory());
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
} catch (err) {
|
|
445
|
+
let e: BusinessError = err as BusinessError;
|
|
446
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `exists failed: ${e.message}, code ${e.code}`);
|
|
447
|
+
callback(false, false);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
stat(path: string, callback: DataErrorCallback): void {
|
|
452
|
+
try {
|
|
453
|
+
fs.stat(path, (err: BusinessError, stat: fs.Stat) => {
|
|
454
|
+
if (err) {
|
|
455
|
+
callback(`failed to stat path \`${path}\` because it does not exist or it is not a folder`, null);
|
|
456
|
+
} else {
|
|
457
|
+
let statObj = new RNFetchBlobStat();
|
|
458
|
+
statObj.filename = path.substring(path.lastIndexOf('/') + 1);
|
|
459
|
+
statObj.path = path;
|
|
460
|
+
statObj.type = stat.isDirectory() ? 'dir' : 'file';
|
|
461
|
+
statObj.size = stat.size;
|
|
462
|
+
statObj.lastModified = stat.mtime;
|
|
463
|
+
callback(null, statObj);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
} catch (err) {
|
|
467
|
+
let e: BusinessError = err as BusinessError;
|
|
468
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `stat failed: ${e.message}, code ${e.code}`);
|
|
469
|
+
callback(`stat failed with error message: ${e.message}, error code: ${e.code}`, null);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
lstat(path: string, callback: DataErrorCallback): void {
|
|
474
|
+
try {
|
|
475
|
+
fs.lstat(path, (err: BusinessError, stat: fs.Stat) => {
|
|
476
|
+
if (err) {
|
|
477
|
+
let errMsg = `lstat failed with error message: ${err.message}, error code: ${err.code}`;
|
|
478
|
+
hilog.error(DOMAIN, TAG, '%{public}s', errMsg);
|
|
479
|
+
callback(errMsg, null);
|
|
480
|
+
} else {
|
|
481
|
+
let statObj = new RNFetchBlobStat();
|
|
482
|
+
statObj.filename = path.substring(path.lastIndexOf('/') + 1);
|
|
483
|
+
statObj.path = path;
|
|
484
|
+
statObj.type = stat.isDirectory() ? 'dir' : 'file';
|
|
485
|
+
statObj.size = stat.size;
|
|
486
|
+
statObj.lastModified = stat.mtime;
|
|
487
|
+
callback(null, statObj);
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
} catch (err) {
|
|
491
|
+
let e: BusinessError = err as BusinessError;
|
|
492
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `lstat failed: ${e.message}, code ${e.code}`);
|
|
493
|
+
callback(`lstat failed with error message: ${e.message}, error code: ${e.code}`, null);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
hash(path: string, algorithm: string): Promise<string> {
|
|
498
|
+
return new Promise((resolve, reject) => {
|
|
499
|
+
try {
|
|
500
|
+
let alg: string = algorithm.toLowerCase();
|
|
501
|
+
if (alg !== 'md5' && alg !== 'sha1' && alg !== 'sha256') {
|
|
502
|
+
reject('Invalid hash algorithm');
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
if (fs.statSync(path).isDirectory()) {
|
|
506
|
+
reject('file IsDirectory');
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
let exists: boolean = false;
|
|
510
|
+
try {
|
|
511
|
+
exists = fs.accessSync(path);
|
|
512
|
+
} catch (e) {
|
|
513
|
+
exists = false;
|
|
514
|
+
}
|
|
515
|
+
if (!exists) {
|
|
516
|
+
reject('file not exists');
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
hash.hash(path, alg, (err: BusinessError, str: string) => {
|
|
520
|
+
if (err) {
|
|
521
|
+
reject(`calculate file hash failed with error message: ${err.message}, error code: ${err.code}`);
|
|
522
|
+
} else {
|
|
523
|
+
resolve(str);
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
} catch (err) {
|
|
527
|
+
let e: BusinessError = err as BusinessError;
|
|
528
|
+
let errMsg = `hash failed with error message: ${e.message}, error code: ${e.code}`;
|
|
529
|
+
hilog.error(DOMAIN, TAG, '%{public}s', errMsg);
|
|
530
|
+
reject(errMsg);
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
slice(path: string, dest: string, start: number, end: number): Promise<string> {
|
|
536
|
+
return new Promise((resolve, reject) => {
|
|
537
|
+
let readFile: fs.File | undefined = undefined;
|
|
538
|
+
let writeFile: fs.File | undefined = undefined;
|
|
539
|
+
try {
|
|
540
|
+
let fileInfo = fs.statSync(path);
|
|
541
|
+
readFile = fs.openSync(path, fs.OpenMode.READ_ONLY);
|
|
542
|
+
writeFile = fs.openSync(dest, fs.OpenMode.WRITE_ONLY | fs.OpenMode.CREATE);
|
|
543
|
+
let buf = new ArrayBuffer(fileInfo.size);
|
|
544
|
+
let readLen: number = fs.readSync(readFile.fd, buf);
|
|
545
|
+
let max = end < readLen ? end : readLen;
|
|
546
|
+
let bytes = buf.slice(start, max);
|
|
547
|
+
let writeLen: number = fs.writeSync(writeFile.fd, bytes);
|
|
548
|
+
if (writeLen < 0) {
|
|
549
|
+
reject('write failed');
|
|
550
|
+
} else {
|
|
551
|
+
resolve(bytes.toString());
|
|
552
|
+
}
|
|
553
|
+
} catch (err) {
|
|
554
|
+
let e: BusinessError = err as BusinessError;
|
|
555
|
+
let errMsg = `slice failed with error message: ${e.message}, error code: ${e.code}`;
|
|
556
|
+
hilog.error(DOMAIN, TAG, '%{public}s', errMsg);
|
|
557
|
+
reject(errMsg);
|
|
558
|
+
} finally {
|
|
559
|
+
if (readFile !== undefined) {
|
|
560
|
+
try {
|
|
561
|
+
fs.closeSync(readFile);
|
|
562
|
+
} catch (e) {
|
|
563
|
+
let ce: BusinessError = e as BusinessError;
|
|
564
|
+
hilog.error(DOMAIN, TAG, '%{public}s', 'close failed: ' + ce.message);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (writeFile !== undefined) {
|
|
568
|
+
try {
|
|
569
|
+
fs.closeSync(writeFile);
|
|
570
|
+
} catch (e) {
|
|
571
|
+
let ce: BusinessError = e as BusinessError;
|
|
572
|
+
hilog.error(DOMAIN, TAG, '%{public}s', 'close failed: ' + ce.message);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
df(callback: (err: string | null, stat?: Object | null) => void): void {
|
|
580
|
+
try {
|
|
581
|
+
let totalSize: number = statvfs.getTotalSizeSync(this.context.filesDir);
|
|
582
|
+
let freeSize: number = statvfs.getFreeSizeSync(this.context.filesDir);
|
|
583
|
+
let res: Record<string, Object> = {};
|
|
584
|
+
res['free'] = freeSize;
|
|
585
|
+
res['total'] = totalSize;
|
|
586
|
+
callback(null, res);
|
|
587
|
+
} catch (err) {
|
|
588
|
+
let e: BusinessError = err as BusinessError;
|
|
589
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `df failed: ${e.message}, code ${e.code}`);
|
|
590
|
+
callback(`df failed with error message: ${e.message}, error code: ${e.code}`, null);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* File preview (mapped from Android actionViewIntent). Uses Preview Kit.
|
|
596
|
+
* Non-media paths are copied into the sandbox first, then converted to a uri.
|
|
597
|
+
*/
|
|
598
|
+
presentPreview(path: string): Promise<string> {
|
|
599
|
+
return new Promise((resolve, reject) => {
|
|
600
|
+
try {
|
|
601
|
+
let uiContext = this.context;
|
|
602
|
+
let previewPath: string = path;
|
|
603
|
+
if (!path.startsWith('file://media')) {
|
|
604
|
+
let srcPath = path;
|
|
605
|
+
let dstPath = uiContext.filesDir + '/' + path.substring(path.lastIndexOf('/') + 1);
|
|
606
|
+
try {
|
|
607
|
+
fs.copyFileSync(srcPath.replace('file://', ''), dstPath);
|
|
608
|
+
} catch (e) {
|
|
609
|
+
// source may already be a sandbox path; ignore copy error
|
|
610
|
+
}
|
|
611
|
+
previewPath = fileUri.getUriFromPath(dstPath);
|
|
612
|
+
}
|
|
613
|
+
filePreview.canPreview(uiContext, previewPath).then((result: boolean) => {
|
|
614
|
+
if (result) {
|
|
615
|
+
let fileInfo: filePreview.PreviewInfo = {
|
|
616
|
+
title: previewPath.substring(previewPath.lastIndexOf('/') + 1),
|
|
617
|
+
uri: previewPath,
|
|
618
|
+
mimeType: this.getMainType(previewPath.substring(previewPath.lastIndexOf('.') + 1)),
|
|
619
|
+
};
|
|
620
|
+
filePreview.openPreview(uiContext, fileInfo).then(() => {
|
|
621
|
+
Logger.info('success to openpreview');
|
|
622
|
+
resolve('succeeded in opening preview');
|
|
623
|
+
}).catch((err: BusinessError) => {
|
|
624
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
|
|
625
|
+
reject(`failed to open preview, err.code = ${err.code}, err.message = ${err.message}`);
|
|
626
|
+
});
|
|
627
|
+
} else {
|
|
628
|
+
reject('path can not Preview, please check');
|
|
629
|
+
}
|
|
630
|
+
}).catch((err: BusinessError) => {
|
|
631
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `failed to preview, err.code = ${err.code}, err.message = ${err.message}`);
|
|
632
|
+
reject(`failed to preview, err.code = ${err.code}, err.message = ${err.message}`);
|
|
633
|
+
});
|
|
634
|
+
} catch (err) {
|
|
635
|
+
let e: BusinessError = err as BusinessError;
|
|
636
|
+
hilog.error(DOMAIN, TAG, '%{public}s', `presentPreview failed, err.code = ${e.code}, err.message = ${e.message}`);
|
|
637
|
+
reject(`presentPreview failed, err.code = ${e.code}, err.message = ${e.message}`);
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
getMainType(value: string): string {
|
|
643
|
+
let mainType: string = '';
|
|
644
|
+
let objType: Record<string, string> = {
|
|
645
|
+
'txt': 'text/plain',
|
|
646
|
+
'cpp': 'text/x-c++src',
|
|
647
|
+
'c': 'text/x-csrc',
|
|
648
|
+
'h': 'text/x-chdr',
|
|
649
|
+
'java': 'text/x-java',
|
|
650
|
+
'xhtml': 'application/xhtml+xml',
|
|
651
|
+
'xml': 'text/xml',
|
|
652
|
+
'html': 'text/html',
|
|
653
|
+
'htm': 'text/html',
|
|
654
|
+
'jpg': 'image/jpeg',
|
|
655
|
+
'jpeg': 'image/jpeg',
|
|
656
|
+
'png': 'image/png',
|
|
657
|
+
'gif': 'image/gif',
|
|
658
|
+
'webp': 'image/webp',
|
|
659
|
+
'bmp': 'image/bmp',
|
|
660
|
+
'svg': 'image/svg+xml',
|
|
661
|
+
'm4a': 'audio/mp4a-latm',
|
|
662
|
+
'aac': 'audio/aac',
|
|
663
|
+
'mp3': 'audio/mpeg',
|
|
664
|
+
'ogg': 'audio/ogg',
|
|
665
|
+
'wav': 'audio/x-wav',
|
|
666
|
+
'mp4': 'video/mp4',
|
|
667
|
+
'mkv': 'video/x-matroska',
|
|
668
|
+
'ts': 'video/mp2ts',
|
|
669
|
+
};
|
|
670
|
+
mainType = objType[value];
|
|
671
|
+
return mainType;
|
|
672
|
+
}
|
|
673
|
+
}
|