UNPKG

8.07 kBPlain TextView Raw
1import { UnavailabilityError } from '@unimodules/core';
2import { EventEmitter, Subscription } from '@unimodules/core';
3import UUID from 'uuid-js';
4import ExponentFileSystem from './ExponentFileSystem';
5import { Platform } from 'react-native';
6
7import {
8 DownloadOptions,
9 DownloadResult,
10 DownloadProgressCallback,
11 DownloadProgressData,
12 DownloadPauseState,
13 FileInfo,
14 EncodingType,
15 ReadingOptions,
16 WritingOptions,
17 ProgressEvent,
18} from './FileSystem.types';
19
20if (!ExponentFileSystem) {
21 console.warn(
22 "No native ExponentFileSystem module found, are you sure the expo-file-system's module is linked properly?"
23 );
24}
25// Prevent webpack from pruning this.
26const _unused = new EventEmitter(ExponentFileSystem);
27
28export {
29 DownloadOptions,
30 DownloadResult,
31 DownloadProgressCallback,
32 DownloadProgressData,
33 DownloadPauseState,
34 FileInfo,
35 EncodingType,
36 ReadingOptions,
37 WritingOptions,
38 ProgressEvent,
39};
40
41function normalizeEndingSlash(p: string | null): string | null {
42 if (p != null) {
43 return p.replace(/\/*$/, '') + '/';
44 }
45 return null;
46}
47
48export const documentDirectory = normalizeEndingSlash(ExponentFileSystem.documentDirectory);
49export const cacheDirectory = normalizeEndingSlash(ExponentFileSystem.cacheDirectory);
50
51export const { bundledAssets, bundleDirectory } = ExponentFileSystem;
52
53export async function getInfoAsync(
54 fileUri: string,
55 options: { md5?: boolean; size?: boolean } = {}
56): Promise<FileInfo> {
57 if (!ExponentFileSystem.getInfoAsync) {
58 throw new UnavailabilityError('expo-file-system', 'getInfoAsync');
59 }
60 return await ExponentFileSystem.getInfoAsync(fileUri, options);
61}
62
63export async function readAsStringAsync(
64 fileUri: string,
65 options?: ReadingOptions
66): Promise<string> {
67 if (!ExponentFileSystem.readAsStringAsync) {
68 throw new UnavailabilityError('expo-file-system', 'readAsStringAsync');
69 }
70 return await ExponentFileSystem.readAsStringAsync(fileUri, options || {});
71}
72
73export async function getContentUriAsync(fileUri: string): Promise<string> {
74 if (Platform.OS === 'android') {
75 if (!ExponentFileSystem.getContentUriAsync) {
76 throw new UnavailabilityError('expo-file-system', 'getContentUriAsync');
77 }
78 return await ExponentFileSystem.getContentUriAsync(fileUri);
79 } else {
80 return new Promise(function(resolve, reject) {
81 resolve(fileUri);
82 });
83 }
84}
85
86export async function writeAsStringAsync(
87 fileUri: string,
88 contents: string,
89 options: WritingOptions = {}
90): Promise<void> {
91 if (!ExponentFileSystem.writeAsStringAsync) {
92 throw new UnavailabilityError('expo-file-system', 'writeAsStringAsync');
93 }
94 return await ExponentFileSystem.writeAsStringAsync(fileUri, contents, options);
95}
96
97export async function deleteAsync(
98 fileUri: string,
99 options: { idempotent?: boolean } = {}
100): Promise<void> {
101 if (!ExponentFileSystem.deleteAsync) {
102 throw new UnavailabilityError('expo-file-system', 'deleteAsync');
103 }
104 return await ExponentFileSystem.deleteAsync(fileUri, options);
105}
106
107export async function moveAsync(options: { from: string; to: string }): Promise<void> {
108 if (!ExponentFileSystem.moveAsync) {
109 throw new UnavailabilityError('expo-file-system', 'moveAsync');
110 }
111 return await ExponentFileSystem.moveAsync(options);
112}
113
114export async function copyAsync(options: { from: string; to: string }): Promise<void> {
115 if (!ExponentFileSystem.copyAsync) {
116 throw new UnavailabilityError('expo-file-system', 'copyAsync');
117 }
118 return await ExponentFileSystem.copyAsync(options);
119}
120
121export async function makeDirectoryAsync(
122 fileUri: string,
123 options: { intermediates?: boolean } = {}
124): Promise<void> {
125 if (!ExponentFileSystem.makeDirectoryAsync) {
126 throw new UnavailabilityError('expo-file-system', 'makeDirectoryAsync');
127 }
128 return await ExponentFileSystem.makeDirectoryAsync(fileUri, options);
129}
130
131export async function readDirectoryAsync(fileUri: string): Promise<string[]> {
132 if (!ExponentFileSystem.readDirectoryAsync) {
133 throw new UnavailabilityError('expo-file-system', 'readDirectoryAsync');
134 }
135 return await ExponentFileSystem.readDirectoryAsync(fileUri, {});
136}
137
138export async function getFreeDiskStorageAsync(): Promise<number> {
139 if (!ExponentFileSystem.getFreeDiskStorageAsync) {
140 throw new UnavailabilityError('expo-file-system', 'getFreeDiskStorageAsync');
141 }
142 return await ExponentFileSystem.getFreeDiskStorageAsync();
143}
144
145export async function getTotalDiskCapacityAsync(): Promise<number> {
146 if (!ExponentFileSystem.getTotalDiskCapacityAsync) {
147 throw new UnavailabilityError('expo-file-system', 'getTotalDiskCapacityAsync');
148 }
149 return await ExponentFileSystem.getTotalDiskCapacityAsync();
150}
151
152export async function downloadAsync(
153 uri: string,
154 fileUri: string,
155 options: DownloadOptions = {}
156): Promise<DownloadResult> {
157 if (!ExponentFileSystem.downloadAsync) {
158 throw new UnavailabilityError('expo-file-system', 'downloadAsync');
159 }
160 return await ExponentFileSystem.downloadAsync(uri, fileUri, options);
161}
162
163export function createDownloadResumable(
164 uri: string,
165 fileUri: string,
166 options?: DownloadOptions,
167 callback?: DownloadProgressCallback,
168 resumeData?: string
169): DownloadResumable {
170 return new DownloadResumable(uri, fileUri, options, callback, resumeData);
171}
172
173export class DownloadResumable {
174 _uuid: string;
175 _url: string;
176 _fileUri: string;
177 _options: DownloadOptions;
178 _resumeData?: string;
179 _callback?: DownloadProgressCallback;
180 _subscription?: Subscription | null;
181 _emitter: EventEmitter;
182
183 constructor(
184 url: string,
185 fileUri: string,
186 options: DownloadOptions = {},
187 callback?: DownloadProgressCallback,
188 resumeData?: string
189 ) {
190 this._uuid = UUID.create(4).toString();
191 this._url = url;
192 this._fileUri = fileUri;
193 this._options = options;
194 this._resumeData = resumeData;
195 this._callback = callback;
196 this._subscription = null;
197 this._emitter = new EventEmitter(ExponentFileSystem);
198 }
199
200 async downloadAsync(): Promise<DownloadResult | undefined> {
201 if (!ExponentFileSystem.downloadResumableStartAsync) {
202 throw new UnavailabilityError('expo-file-system', 'downloadResumableStartAsync');
203 }
204 this._addSubscription();
205 return await ExponentFileSystem.downloadResumableStartAsync(
206 this._url,
207 this._fileUri,
208 this._uuid,
209 this._options,
210 this._resumeData
211 );
212 }
213
214 async pauseAsync(): Promise<DownloadPauseState> {
215 if (!ExponentFileSystem.downloadResumablePauseAsync) {
216 throw new UnavailabilityError('expo-file-system', 'downloadResumablePauseAsync');
217 }
218 const pauseResult = await ExponentFileSystem.downloadResumablePauseAsync(this._uuid);
219 this._removeSubscription();
220 if (pauseResult) {
221 this._resumeData = pauseResult.resumeData;
222 return this.savable();
223 } else {
224 throw new Error('Unable to generate a savable pause state');
225 }
226 }
227
228 async resumeAsync(): Promise<DownloadResult | undefined> {
229 if (!ExponentFileSystem.downloadResumableStartAsync) {
230 throw new UnavailabilityError('expo-file-system', 'downloadResumableStartAsync');
231 }
232 this._addSubscription();
233 return await ExponentFileSystem.downloadResumableStartAsync(
234 this._url,
235 this._fileUri,
236 this._uuid,
237 this._options,
238 this._resumeData
239 );
240 }
241
242 savable(): DownloadPauseState {
243 return {
244 url: this._url,
245 fileUri: this._fileUri,
246 options: this._options,
247 resumeData: this._resumeData,
248 };
249 }
250
251 _addSubscription(): void {
252 if (this._subscription) {
253 return;
254 }
255 this._subscription = this._emitter.addListener(
256 'Exponent.downloadProgress',
257 (event: ProgressEvent) => {
258 if (event.uuid === this._uuid) {
259 const callback = this._callback;
260 if (callback) {
261 callback(event.data);
262 }
263 }
264 }
265 );
266 }
267
268 _removeSubscription(): void {
269 if (!this._subscription) {
270 return;
271 }
272 this._emitter.removeSubscription(this._subscription);
273 this._subscription = null;
274 }
275}