Skip to content

Commit

Permalink
feat: Handle files that are too large
Browse files Browse the repository at this point in the history
  • Loading branch information
acezard committed Mar 8, 2024
1 parent 0011549 commit b6473d8
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 17 deletions.
2 changes: 2 additions & 0 deletions src/constants/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ export const TRASH_DIR_PATH = '/.cozy_trash'
export const KONNECTORS_DIR_PATH = '/.cozy_konnectors'
export const FILES_FETCH_LIMIT = 100
export const HOME_LINK_HREF = 'https://manager.cozycloud.cc/cozy/create'
export const MAX_PAYLOAD_SIZE_IN_GB = 5
export const MAX_PAYLOAD_SIZE = MAX_PAYLOAD_SIZE_IN_GB * 1024 * 1024 * 1024
3 changes: 2 additions & 1 deletion src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,8 @@
"updated": "%{smart_count} %{type} updated. |||| %{smart_count} %{type} updated.",
"updated_conflicts": "%{smart_count} %{type} updated with %{conflictCount} conflict(s). |||| %{smart_count} %{type}s updated with %{conflictCount} conflict(s).",
"errors": "Errors occurred during the %{type} upload.",
"network": "You are currenly offline. Please try again once you're connected."
"network": "You are currenly offline. Please try again once you're connected.",
"fileTooLargeErrors": "File too large. Maximum file size: %{max_size_value} GB"
}
},
"intents": {
Expand Down
3 changes: 2 additions & 1 deletion src/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,8 @@
"updated": "%{smart_count} %{type} mis à jour. |||| %{smart_count} %{type}s mis à jour.",
"updated_conflicts": "%{smart_count} %{type} mis à jour avec %{conflictCount} conflit(s). |||| %{smart_count} %{type}s mis à jour avec %{conflictCount} conflit(s).",
"errors": "Une erreur est survenue lors de l’import du %{type}, merci de réessayer plus tard.",
"network": "Vous ne disposez pas d'une connexion internet. Merci de réessayer quand ce sera le cas."
"network": "Vous ne disposez pas d'une connexion internet. Merci de réessayer quand ce sera le cas.",
"fileTooLargeErrors": "Fichier trop volumineux. Taille maximale autorisée par fichier : %{max_size_value} Go"
}
},
"intents": {
Expand Down
29 changes: 26 additions & 3 deletions src/modules/navigation/duck/actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { showModal } from 'react-cozy-helpers'
import { isDirectory } from 'cozy-client/dist/models/file'
import Alerter from 'cozy-ui/transpiled/react/deprecated/Alerter'

import { MAX_PAYLOAD_SIZE_IN_GB } from 'constants/config'
import { createEncryptedDir } from 'lib/encryption'
import { getEntriesTypeTranslated } from 'lib/entries'
import logger from 'lib/logger'
Expand Down Expand Up @@ -48,7 +49,15 @@ export const uploadFiles =
dirId,
sharingState, // used to know if files are shared for conflicts management
fileUploadedCallback,
(loaded, quotas, conflicts, networkErrors, errors, updated) =>
(
loaded,
quotas,
conflicts,
networkErrors,
errors,
updated,
fileTooLargeErrors
) =>
dispatch(
uploadQueueProcessed(
loaded,
Expand All @@ -57,7 +66,8 @@ export const uploadFiles =
networkErrors,
errors,
updated,
t
t,
fileTooLargeErrors
)
),
{ client, vaultClient }
Expand All @@ -66,7 +76,16 @@ export const uploadFiles =
}

const uploadQueueProcessed =
(created, quotas, conflicts, networkErrors, errors, updated, t) =>
(
created,
quotas,
conflicts,
networkErrors,
errors,
updated,
t,
fileTooLargeErrors
) =>
dispatch => {
const conflictCount = conflicts.length
const createdCount = created.length
Expand Down Expand Up @@ -119,6 +138,10 @@ const uploadQueueProcessed =
smart_count: updatedCount,
type
})
} else if (fileTooLargeErrors.length > 0) {
Alerter.error('upload.alert.fileTooLargeErrors', {
max_size_value: MAX_PAYLOAD_SIZE_IN_GB
})
} else {
Alerter.success('upload.alert.success', {
smart_count: createdCount,
Expand Down
66 changes: 54 additions & 12 deletions src/modules/upload/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { models } from 'cozy-client'
import flag from 'cozy-flags'

import UploadQueue from './UploadQueue'
import { MAX_PAYLOAD_SIZE } from 'constants/config'
import { DOCTYPE_FILES } from 'lib/doctypes'
import {
encryptAndUploadNewFile,
Expand Down Expand Up @@ -36,6 +37,7 @@ const FAILED = 'failed'
const CONFLICT = 'conflict'
const QUOTA = 'quota'
const NETWORK = 'network'
const FILE_TOO_LARGE_ERROR = 'Request Entity Too Large'
const DONE_STATUSES = [CREATED, UPDATED]
const ERROR_STATUSES = [CONFLICT, NETWORK, QUOTA]

Expand All @@ -50,7 +52,8 @@ export const status = {
QUOTA,
NETWORK,
DONE_STATUSES,
ERROR_STATUSES
ERROR_STATUSES,
FILE_TOO_LARGE_ERROR
}

const CONFLICT_ERROR = 409
Expand Down Expand Up @@ -233,19 +236,33 @@ export const processNextFile =
}
if (error) {
logger.warn(error)

logException(
`Upload module catches an error when executing processNextFile(): ${error}`
)

// Define mapping for specific status codes to our constants
const statusError = {
409: CONFLICT,
413: QUOTA
}

const status =
statusError[error.status] ||
(/Failed to fetch$/.exec(error.toString()) && NETWORK) ||
FAILED
// Determine the status based on the error details
let status
if (
error.title === FILE_TOO_LARGE_ERROR ||
error.message === FILE_TOO_LARGE_ERROR
) {
status = FILE_TOO_LARGE_ERROR // File size exceeded maximum size allowed by the server
} else if (error.status in statusError) {
status = statusError[error.status]
} else if (/Failed to fetch$/.exec(error.toString())) {
status = NETWORK
} else {
status = FAILED
}

// Dispatch an action to handle the upload error with the determined status
dispatch({ type: RECEIVE_UPLOAD_ERROR, file, status })
}
}
Expand Down Expand Up @@ -314,16 +331,30 @@ const uploadFile = async (client, file, dirID, options = {}) => {
* We don't need to do that work on other browser (window.chrome
* should be available on new Edge, Chrome, Chromium, Brave, Opera...)
*/

// Check if running in a Chrome browser
if (window.chrome) {
// Convert file size to integer for comparison
const fileSize = parseInt(file.size, 10)

// Check if the file size exceeds the server's maximum payload size
if (fileSize > MAX_PAYLOAD_SIZE) {
// Create a new error for exceeding the maximum payload size
const error = new Error(FILE_TOO_LARGE_ERROR)
throw error
}

// Proceed to check disk usage
const { data: diskUsage } = await client
.getStackClient()
.fetchJSON('GET', '/settings/disk-usage')
if (diskUsage.attributes.quota) {
if (
parseInt(diskUsage.attributes.used) + parseInt(file.size) >
parseInt(diskUsage.attributes.quota)
) {
const error = new Error('Payload Too Large')
const usedSpace = parseInt(diskUsage.attributes.used, 10)
const totalQuota = parseInt(diskUsage.attributes.quota, 10)
const availableSpace = totalQuota - usedSpace

if (fileSize > availableSpace) {
const error = new Error('Insufficient Disk Space')
error.status = 413
throw error
}
Expand Down Expand Up @@ -456,8 +487,17 @@ export const onQueueEmpty = callback => (dispatch, getState) => {
const updated = getUpdated(queue)
const networkErrors = getNetworkErrors(queue)
const errors = getErrors(queue)

return callback(created, quotas, conflicts, networkErrors, errors, updated)
const fileTooLargeErrors = getfileTooLargeErrors(queue)

return callback(
created,
quotas,
conflicts,
networkErrors,
errors,
updated,
fileTooLargeErrors
)
}

// selectors
Expand All @@ -468,6 +508,8 @@ const getQuotaErrors = queue => filterByStatus(queue, QUOTA)
const getNetworkErrors = queue => filterByStatus(queue, NETWORK)
const getCreated = queue => filterByStatus(queue, CREATED)
const getUpdated = queue => filterByStatus(queue, UPDATED)
const getfileTooLargeErrors = queue =>
filterByStatus(queue, FILE_TOO_LARGE_ERROR)

export const getUploadQueue = state => state[SLUG].queue

Expand Down
1 change: 1 addition & 0 deletions src/modules/upload/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ describe('processNextFile function', () => {
[],
[],
[],
[],
[]
)
})
Expand Down

0 comments on commit b6473d8

Please sign in to comment.