2022-08-31 06:33:37 +05:00
/ *
This file is part of the Notesnook project ( https : //notesnook.com/)
2023-01-16 13:44:52 +05:00
Copyright ( C ) 2023 Streetwriters ( Private ) Limited
2022-08-31 06:33:37 +05:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
* /
2022-08-30 16:13:11 +05:00
2022-09-09 19:09:22 +05:00
import NetInfo from "@react-native-community/netinfo" ;
2023-05-19 11:05:16 +05:00
import RNFetchBlob from "react-native-blob-util" ;
2023-08-29 20:42:45 +05:00
import { ToastManager } from "../../services/event-manager" ;
2022-08-29 16:19:17 +05:00
import { useAttachmentStore } from "../../stores/use-attachment-store" ;
2024-05-04 23:02:07 +05:00
import { DatabaseLogger , db } from "../database" ;
2023-09-21 11:47:35 +05:00
import { createCacheDir , exists } from "./io" ;
2024-08-08 12:19:21 +05:00
import { ABYTES , cacheDir , getUploadedFileSize , parseS3Error } from "./utils" ;
2022-02-28 13:48:59 +05:00
2024-08-08 12:19:21 +05:00
export async function downloadFile ( filename , requestOptions , cancelToken ) {
if ( ! requestOptions ) {
DatabaseLogger . log (
` Error downloading file: ${ filename } , reason: No requestOptions `
) ;
2024-05-04 00:31:02 +05:00
return false ;
}
2023-09-21 13:18:12 +05:00
2024-05-04 00:31:02 +05:00
DatabaseLogger . log ( ` Downloading ${ filename } ` ) ;
2023-09-21 13:18:12 +05:00
await createCacheDir ( ) ;
2024-08-08 12:19:21 +05:00
let { url , headers , chunkSize } = requestOptions ;
2024-08-07 11:17:05 +05:00
let tempFilePath = ` ${ cacheDir } / ${ filename } _temp ` ;
let originalFilePath = ` ${ cacheDir } / ${ filename } ` ;
2022-02-28 13:48:59 +05:00
try {
2023-09-21 11:47:35 +05:00
if ( await exists ( filename ) ) {
2024-05-04 00:31:02 +05:00
DatabaseLogger . log ( ` File Exists already: ${ filename } ` ) ;
2022-02-28 13:48:59 +05:00
return true ;
}
2024-09-20 12:01:33 +05:00
2024-08-08 12:19:21 +05:00
const attachment = await db . attachments . attachment ( filename ) ;
const size = await getUploadedFileSize ( filename ) ;
if ( size === - 1 ) {
const error = ` Uploaded file verification failed. (File hash: ${ filename } ) ` ;
throw new Error ( error ) ;
}
if ( size === 0 ) {
const error = ` File length is 0. Please upload this file again from the attachment manager. (File hash: ${ filename } ) ` ;
await db . attachments . markAsFailed ( attachment . id , error ) ;
throw new Error ( error ) ;
}
const totalChunks = Math . ceil ( size / chunkSize ) ;
const decryptedLength = size - totalChunks * ABYTES ;
if ( attachment && attachment . size !== decryptedLength ) {
const error = ` File length mismatch. Expected ${ attachment . size } but got ${ decryptedLength } bytes. Please upload this file again from the attachment manager. (File hash: ${ filename } ) ` ;
await db . attachments . markAsFailed ( attachment . id , error ) ;
throw new Error ( error ) ;
}
2022-02-28 13:48:59 +05:00
let res = await fetch ( url , {
2022-08-26 16:19:39 +05:00
method : "GET" ,
2022-02-28 13:48:59 +05:00
headers
} ) ;
2024-05-04 00:31:02 +05:00
if ( ! res . ok ) {
DatabaseLogger . log (
` Error downloading file: ${ filename } , ${ res . status } , ${ res . statusText } , reason: Unable to resolve download url `
) ;
2022-08-26 16:19:39 +05:00
throw new Error ( ` ${ res . status } : Unable to resolve download url ` ) ;
2024-05-04 00:31:02 +05:00
}
2022-02-28 13:48:59 +05:00
const downloadUrl = await res . text ( ) ;
2024-05-04 00:31:02 +05:00
if ( ! downloadUrl ) {
DatabaseLogger . log (
` Error downloading file: ${ filename } , reason: Unable to resolve download url `
) ;
throw new Error ( "Unable to resolve download url" ) ;
}
2024-08-08 12:19:21 +05:00
2024-05-04 00:31:02 +05:00
DatabaseLogger . log ( ` Download starting: ${ filename } ` ) ;
2022-02-28 13:48:59 +05:00
let request = RNFetchBlob . config ( {
2024-08-07 11:17:05 +05:00
path : tempFilePath ,
2024-09-20 12:01:33 +05:00
IOSBackgroundTask : true ,
overwrite : true
2022-02-28 13:48:59 +05:00
} )
2022-08-26 16:19:39 +05:00
. fetch ( "GET" , downloadUrl , null )
2024-08-08 12:19:21 +05:00
. progress ( async ( recieved , total ) => {
2022-08-26 16:19:39 +05:00
useAttachmentStore
. getState ( )
. setProgress ( 0 , total , filename , recieved , "download" ) ;
2024-08-08 12:19:21 +05:00
2024-05-04 00:31:02 +05:00
DatabaseLogger . log ( ` Downloading: ${ filename } , ${ recieved } / ${ total } ` ) ;
2022-02-28 13:48:59 +05:00
} ) ;
2023-09-20 10:03:42 +05:00
cancelToken . cancel = ( ) => {
useAttachmentStore . getState ( ) . remove ( filename ) ;
request . cancel ( ) ;
2024-08-07 11:17:05 +05:00
RNFetchBlob . fs . unlink ( tempFilePath ) . catch ( console . log ) ;
2024-05-04 00:31:02 +05:00
DatabaseLogger . log ( ` Download cancelled: ${ filename } ` ) ;
2023-09-20 10:03:42 +05:00
} ;
2024-05-04 00:31:02 +05:00
2022-02-28 13:48:59 +05:00
let response = await request ;
2024-08-08 12:19:21 +05:00
console . log ( response . info ( ) . headers ) ;
const contentType =
response . info ( ) . headers ? . [ "content-type" ] ||
response . info ( ) . headers ? . [ "Content-Type" ] ;
if ( contentType === "application/xml" ) {
const error = parseS3Error ( await response . text ( ) ) ;
throw new Error ( ` [ ${ error . Code } ] ${ error . Message } ` ) ;
}
2024-08-07 11:17:05 +05:00
2022-02-28 13:48:59 +05:00
let status = response . info ( ) . status ;
useAttachmentStore . getState ( ) . remove ( filename ) ;
2024-09-20 12:01:33 +05:00
if ( exists ( originalFilePath ) ) {
await RNFetchBlob . fs . unlink ( originalFilePath ) . catch ( console . log ) ;
}
2024-08-07 11:17:05 +05:00
await RNFetchBlob . fs . mv ( tempFilePath , originalFilePath ) ;
if ( ! ( await exists ( filename ) ) ) {
throw new Error ( "File size mismatch" ) ;
}
2022-02-28 13:48:59 +05:00
return status >= 200 && status < 300 ;
} catch ( e ) {
2024-07-31 15:44:18 +05:00
if ( e . message !== "canceled" && ! e . message . includes ( "NoSuchKey" ) ) {
2023-08-29 20:42:45 +05:00
ToastManager . show ( {
2023-09-20 19:45:57 +05:00
heading : "Error downloading file" ,
message : e . message ,
type : "error" ,
context : "global"
} ) ;
2023-08-29 20:42:45 +05:00
ToastManager . show ( {
2023-09-20 19:45:57 +05:00
heading : "Error downloading file" ,
message : e . message ,
type : "error" ,
context : "local"
} ) ;
}
2022-02-28 13:48:59 +05:00
useAttachmentStore . getState ( ) . remove ( filename ) ;
2024-08-07 11:17:05 +05:00
RNFetchBlob . fs . unlink ( tempFilePath ) . catch ( console . log ) ;
RNFetchBlob . fs . unlink ( originalFilePath ) . catch ( console . log ) ;
2024-05-04 00:31:02 +05:00
DatabaseLogger . error ( e , {
url ,
headers
} ) ;
2022-02-28 13:48:59 +05:00
return false ;
}
}
2022-03-07 15:19:07 +05:00
export async function checkAttachment ( hash ) {
2022-04-19 16:35:11 +05:00
const internetState = await NetInfo . fetch ( ) ;
2022-08-26 16:19:39 +05:00
const isInternetReachable =
internetState . isConnected && internetState . isInternetReachable ;
2024-08-16 16:29:05 +05:00
if ( ! isInternetReachable ) return ;
2023-12-27 09:40:15 +05:00
const attachment = await db . attachments . attachment ( hash ) ;
2022-08-26 16:19:39 +05:00
if ( ! attachment ) return { failed : "Attachment not found." } ;
2022-03-07 15:19:07 +05:00
try {
const size = await getUploadedFileSize ( hash ) ;
2024-08-16 16:29:05 +05:00
console . log ( "File Size" , size ) ;
2024-05-04 23:02:07 +05:00
if ( size === - 1 ) return { success : true } ;
2024-08-16 16:29:05 +05:00
if ( size === 0 )
return {
failed : ` File length is 0. Please upload this file again from the attachment manager. (File hash: ${ hash } ) `
} ;
2022-03-07 15:19:07 +05:00
} catch ( e ) {
2022-04-19 16:35:11 +05:00
return { failed : e ? . message } ;
2022-03-07 15:19:07 +05:00
}
return { success : true } ;
}