UNPKG

react-native-cloud-store

Version:
320 lines (275 loc) 8.17 kB
import { Platform } from 'react-native' import CloudStore, { eventEmitter } from './module'; import { PathUtils } from './path'; function getConstants(): { defaultICloudContainerPath?: string; } { // TODO: android not implement getConstants method, so here just return an empty object return Platform.OS === 'ios' ? CloudStore.getConstants() : {}; } export const defaultICloudContainerPath = getConstants().defaultICloudContainerPath export async function getDefaultICloudContainerPath(): Promise<string | undefined> { return Platform.OS === 'ios' ? CloudStore.getDefaultICloudContainerPath() : undefined; } // https://developer.apple.com/documentation/foundation/filemanager/1411653-url export async function getICloudURL(containerIdentifier?: string): Promise<string> { return CloudStore.getICloudURL(containerIdentifier); } export async function isICloudAvailable(): Promise<boolean> { return CloudStore.isICloudAvailable(); } export async function writeFile( path: string, content: string, options?: { override?: boolean onProgress?: (data: {progress: number;}) => void } ): Promise<void> { let canProgress = false; if(options?.onProgress) { if(!calledGlobalUploadEvent) { console.error(`You didn't call registerGlobalUploadEvent(), onProgress will not be triggered `) } else { uploadId++ uploadId2CallbackDataMap[uploadId] = { path: path, callback: options.onProgress } canProgress = true; } } return CloudStore.writeFile(path, content, { ...options, id: canProgress ? uploadId.toString() : undefined }); } export async function readFile(path: string): Promise<string> { return CloudStore.readFile(path); } // if returned filename format is .[file-full-name-with-ext].icloud, means this file is not yet downloaded to local device export async function readDir(path: string): Promise<string[]> { return CloudStore.readDir(path); } export async function createDir(path: string): Promise<void> { return CloudStore.createDir(path); } export async function moveDir( pathFrom: string, pathTo: string ): Promise<void> { return CloudStore.moveDir(pathFrom, pathTo); } export async function copy( pathFrom: string, pathTo: string, options?: { override?: boolean } ): Promise<void> { return CloudStore.copy(pathFrom, pathTo, { ...options, }); } export async function unlink(path: string): Promise<void> { return CloudStore.unlink(path); } export async function exist(path: string): Promise<boolean> { return CloudStore.exist(path); } export interface ICloudStat { isInICloud?: boolean; containerDisplayName?: string; isDownloading?: boolean; hasCalledDownload?: boolean; // https://developer.apple.com/documentation/foundation/urlubiquitousitemdownloadingstatus downloadStatus?: | 'NSURLUbiquitousItemDownloadingStatusNotDownloaded' | 'NSURLUbiquitousItemDownloadingStatusCurrent' | 'NSURLUbiquitousItemDownloadingStatusDownloaded'; downloadError?: string; isUploaded?: boolean; isUploading?: boolean; uploadError?: string; hasUnresolvedConflicts?: boolean; modifyTimestamp?: number; createTimestamp?: number; name?: string; localizedName?: string; fileSize?: number; isDirectory?: boolean; } export async function stat(path: string): Promise<ICloudStat> { return CloudStore.stat(path); } let calledGlobalUploadEvent = false let uploadId = 0; const uploadId2CallbackDataMap: Record<string, { path: string callback: (data: {progress: number}) => void }> = {} let calledGlobalDownloadEvent = false let downloadId = 0; const downloadId2CallbackDataMap: Record<string, { path: string callback: (data: {progress: number}) => void }> = {} export async function upload( localPath: string, path: string, options?: { onProgress: (data: {progress: number;}) => void } ): Promise<void> { uploadId++ if(options?.onProgress) { if(!calledGlobalUploadEvent) { console.error(`You didn't call registerGlobalUploadEvent(), onProgress will not be triggered `) } uploadId2CallbackDataMap[uploadId] = { path: path, callback: options.onProgress } } return CloudStore.upload(u(localPath), path, { id: uploadId.toString() }); } export async function download( path: string, options?: { onProgress: (data: {progress: number;}) => void } ): Promise<void> { downloadId++ const fileInfo = await CloudStore.stat(path); if ( fileInfo.downloadStatus === "NSURLUbiquitousItemDownloadingStatusCurrent" ) { options?.onProgress({progress: 100}) return Promise.resolve() } const pathWithoutDot = PathUtils.iCloudRemoveDotExt(path); if(options?.onProgress) { if(!calledGlobalDownloadEvent) { console.error(`You didn't call registerGlobalDownloadEvent(), onProgress will not be triggered `) } downloadId2CallbackDataMap[downloadId] = { path: pathWithoutDot, callback: options.onProgress } } return CloudStore.download(pathWithoutDot, { id: downloadId.toString() }); } export function registerGlobalUploadEvent() { if(calledGlobalUploadEvent) { return } const subscription = onICloudDocumentsUpdateGathering((data) => { const callbackData = uploadId2CallbackDataMap[data.id] if(!callbackData) return const {path, callback} = callbackData const uploadTarget = data.detail.find( (i) => i.type === "upload" && i.path === path ); if (uploadTarget) { const progress = uploadTarget.progress??0 if(progress === 100) { delete uploadId2CallbackDataMap[uploadId] } callback({progress: progress}) } }) calledGlobalUploadEvent = true // TODO: directly return the unsubscribe function in next version return { remove() { subscription.remove(); calledGlobalUploadEvent = false } } } export function registerGlobalDownloadEvent() { if(calledGlobalDownloadEvent) { return } calledGlobalDownloadEvent = true const subscription = onICloudDocumentsUpdateGathering((data) => { const callbackData = downloadId2CallbackDataMap[data.id] if(!callbackData) return const {path, callback} = callbackData const downloadTarget = data.detail.find( (i) => i.type === "download" && i.path === path ); if (downloadTarget) { const progress = downloadTarget.progress??0 if(progress === 100) { delete downloadId2CallbackDataMap[uploadId] } callback({progress: progress}) } }) calledGlobalDownloadEvent = true // TODO: directly return the unsubscribe function in next version return { remove() { subscription.remove(); calledGlobalDownloadEvent = false } } } export function onICloudIdentityDidChange( fn: (data: {tokenChanged: boolean}) => void ) { return eventEmitter.addListener('onICloudIdentityDidChange', fn); } export type DocumentsGatheringData = { id: string info: { added: string[]; changed: string[]; removed: string[]; }; detail: Array<{ type: 'upload' | 'download'; path: string; progress: number | null; isDir: boolean | null; }>; }; type DocumentsGatheringEventHandler = (data: DocumentsGatheringData) => void; export function onICloudDocumentsStartGathering( fn: DocumentsGatheringEventHandler ) { return eventEmitter.addListener( 'onICloudDocumentsStartGathering', (nativeData: any) => { fn(nativeData); } ); } export function onICloudDocumentsGathering(fn: DocumentsGatheringEventHandler) { return eventEmitter.addListener('onICloudDocumentsGathering', fn); } export function onICloudDocumentsFinishGathering( fn: DocumentsGatheringEventHandler ) { return eventEmitter.addListener('onICloudDocumentsFinishGathering', fn); } export function onICloudDocumentsUpdateGathering( fn: DocumentsGatheringEventHandler ) { return eventEmitter.addListener('onICloudDocumentsUpdateGathering', fn); } function u(path: string): string { let prefix = "file://" if(path.startsWith(prefix)) { path = path.slice(prefix.length) } return path }