Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
volar committed Nov 16, 2023
1 parent 9e81c05 commit 517be98
Show file tree
Hide file tree
Showing 8 changed files with 512 additions and 14 deletions.
11 changes: 11 additions & 0 deletions src/components/dam/uploadQueue/api/damAssetApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { AxiosInstance } from 'axios'
import type { DocId } from '@/types/common'
import { SYSTEM_CORE_DAM } from '@/services/api/coreDam/assetApi'
import type { AssetDetailItemDto } from '@/types/coreDam/Asset'
import { apiFetchOne } from '@/services/api/apiFetchOne'

const END_POINT = '/adm/v1/asset'
const ENTITY = 'asset'

export const fetchAsset = (client: () => AxiosInstance, id: DocId) =>
apiFetchOne<AssetDetailItemDto>(client, END_POINT + '/:id', { id }, SYSTEM_CORE_DAM, ENTITY)
109 changes: 109 additions & 0 deletions src/components/dam/uploadQueue/api/damImageApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import type { AxiosInstance } from 'axios'
import { type UploadQueueItem, UploadQueueItemType } from '@/types/coreDam/UploadQueue'
import type { DocId } from '@/types/common'
import { HTTP_STATUS_CREATED, HTTP_STATUS_OK } from '@/composables/statusCodes'
import { damFileTypeFix } from '@/components/file/composables/fileType'

const END_POINT = '/adm/v1/image'
const CHUNK_UPLOAD_TIMEOUT = 420

export const imageUploadStart = (client: () => AxiosInstance, item: UploadQueueItem) => {
return new Promise((resolve, reject) => {
let url = END_POINT + '/licence/' + item.licenceId
if (item.type === UploadQueueItemType.SlotFile && item.slotName && item.assetId) {
url = END_POINT + '/asset/' + item.assetId + '/slot-name/' + item.slotName
}
client()
.post(
url,
JSON.stringify({
mimeType: damFileTypeFix(item.file),
size: item.file?.size,
})
)
.then((res) => {
if (res.status === HTTP_STATUS_CREATED) {
resolve(res.data)
} else {
//
reject()
}
})
.catch((err) => {
//
reject(err)
})
})
}

export const imageUploadChunk = (
client: (timeout?: number) => AxiosInstance,
item: UploadQueueItem,
imageId: DocId,
buffer: string,
size: number,
offset: number,
onUploadProgressCallback: ((progressEvent: any) => void) | undefined = undefined
) => {
return new Promise((resolve, reject) => {
const formData = new FormData()
const url = END_POINT + '/' + imageId + '/chunk'
formData.append('file', buffer)
formData.append(
'chunk',
JSON.stringify({
offset: offset,
size: size,
})
)

client(CHUNK_UPLOAD_TIMEOUT)
.post(url, formData, {
cancelToken:
item.chunks[item.currentChunkIndex] && item.chunks[item.currentChunkIndex].cancelTokenSource
? item.chunks[item.currentChunkIndex].cancelTokenSource.token
: undefined,
headers: {
'Content-Type': 'multipart/form-data',
},
onUploadProgress: onUploadProgressCallback,
})
.then((res) => {
if (res.status === HTTP_STATUS_CREATED) {
resolve(res.data)
} else {
//
reject()
}
})
.catch((err) => {
//
reject(err)
})
})
}

export const imageUploadFinish = (client: () => AxiosInstance, item: UploadQueueItem, sha: string) => {
return new Promise((resolve, reject) => {
const url = END_POINT + '/' + item.fileId + '/uploaded'
client()
.patch(
url,
JSON.stringify({
checksum: sha,
})
)
.then((res) => {
if (res.status === HTTP_STATUS_OK) {
resolve(res.data)
} else {
//
reject()
}
})
.catch((err) => {
//
reject(err)
})
})
}
107 changes: 107 additions & 0 deletions src/components/dam/uploadQueue/api/uploadApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { DamAssetType } from '@/types/coreDam/Asset'
import { type DamUploadStartResponse, type UploadQueueItem, UploadQueueItemStatus } from '@/types/coreDam/UploadQueue'
import { imageUploadChunk, imageUploadFinish, imageUploadStart } from '@/components/dam/uploadQueue/api/damImageApi'
import type { AxiosInstance } from 'axios'
import type { DocId } from '@/types/common'
import { AssetFileProcessStatus } from '@/types/coreDam/AssetFile'
import { fetchAsset } from '@/components/dam/uploadQueue/api/damAssetApi'
import { useUploadQueuesStore } from '@/components/dam/uploadQueue/uploadQueuesStore'

const NOTIFICATION_FALLBACK_TIMER_CHECK_SECONDS = 10
const NOTIFICATION_FALLBACK_MAX_TRIES = 3

export const damUploadStart: (client: () => AxiosInstance, item: UploadQueueItem) => Promise<DamUploadStartResponse> = (
client: () => AxiosInstance,
item: UploadQueueItem
) => {
return new Promise((resolve, reject) => {
if (item.assetType !== DamAssetType.Image) {
reject()
return
}
imageUploadStart(client, item)
.then((res) => {
resolve(res as DamUploadStartResponse)
return
})
.catch((err) => reject(err))
})
}

export const damUploadChunk = (
client: () => AxiosInstance,
item: UploadQueueItem,
imageId: DocId,
buffer: string,
size: number,
offset: number,
onUploadProgressCallback: any
) => {
return new Promise((resolve, reject) => {
if (item.assetType !== DamAssetType.Image) {
reject()
return
}
imageUploadChunk(client, item, imageId, buffer, size, offset, onUploadProgressCallback)
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
})
}

export const damUploadFinish = (
client: () => AxiosInstance,
item: UploadQueueItem,
sha: string,
uploadStatusFallback: boolean
) => {
return new Promise((resolve, reject) => {
if (item.assetType !== DamAssetType.Image) {
reject()
return
}
imageUploadFinish(client, item, sha)
.then((res) => {
item.status = UploadQueueItemStatus.Processing
if (uploadStatusFallback) {
item.notificationFallbackTimer = setTimeout(function () {
notificationFallbackCallback(client, item)
}, calculateFallbackTime(item))
}
resolve(res)
})
.catch((err) => reject(err))
})
}

function calculateFallbackTime(item: UploadQueueItem) {
return NOTIFICATION_FALLBACK_TIMER_CHECK_SECONDS * 1000 * item.notificationFallbackTry * item.notificationFallbackTry
}

async function notificationFallbackCallback(client: () => AxiosInstance, item: UploadQueueItem) {
clearTimeout(item.notificationFallbackTimer)
if (item.status === UploadQueueItemStatus.Uploaded) return
if (item.notificationFallbackTry > NOTIFICATION_FALLBACK_MAX_TRIES) return
if (!item.assetId) return
const asset = await fetchAsset(client, item.assetId)
if (asset && asset.mainFile && asset.mainFile.fileAttributes) {
const uploadQueuesStore = useUploadQueuesStore()
if (asset.mainFile.fileAttributes.status === AssetFileProcessStatus.Processed) {
uploadQueuesStore.queueItemProcessed(asset.id)
return
} else if (asset.mainFile.fileAttributes.status === AssetFileProcessStatus.Duplicate) {
uploadQueuesStore.queueItemDuplicate(asset.id)
return
} else if (asset.mainFile.fileAttributes.status === AssetFileProcessStatus.Failed) {
uploadQueuesStore.queueItemFailed(asset.id, asset.mainFile.fileAttributes.failReason)
return
}
}
item.notificationFallbackTry++
item.notificationFallbackTimer = setTimeout(function () {
notificationFallbackCallback(client, item)
}, calculateFallbackTime(item))
}
37 changes: 23 additions & 14 deletions src/components/dam/uploadQueue/uploadQueuesStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
import { useUploadQueueItemFactory } from '@/components/dam/uploadQueue/UploadQueueItemFactory'
import { getAssetTypeByMimeType } from '@/components/dam/uploadQueue/mimeTypeHelper'
import { useDamConfigState } from '@/components/dam/uploadQueue/damConfigState'
import { useUpload } from '@/components/dam/uploadQueue/uploadService'
import { DamAssetType } from '@/types/coreDam/Asset'

const QUEUE_MAX_PARALLEL_UPLOADS = 2
const QUEUE_CHUNK_SIZE = 10485760
Expand Down Expand Up @@ -39,7 +41,7 @@ export const useUploadQueuesStore = defineStore('commonUploadQueuesStore', () =>
const { damConfigExtSystem } = useDamConfigState()
for await (const file of files) {
const type = getAssetTypeByMimeType(damFileTypeFix(file), damConfigExtSystem.value)
if (!type) continue
if (!type || type !== DamAssetType.Image) continue // only image now
const queueItem = createDefault(
'file_' + file.name,
UploadQueueItemType.File,
Expand Down Expand Up @@ -107,19 +109,19 @@ export const useUploadQueuesStore = defineStore('commonUploadQueuesStore', () =>
}

async function queueItemUploadStart(item: UploadQueueItem, queueId: string) {
// const { upload, uploadInit } = useUpload(item, (progress: number, speed: number, estimate: number) => {
// setUploadSpeed(item, progress, speed, estimate)
// })
// try {
// await uploadInit()
// await upload()
// processUpload(queueId)
// } catch (e) {
// item.error.hasError = true
// item.status = UploadQueueItemStatus.Failed
// recalculateQueueCounts(queueId)
// processUpload(queueId)
// }
const { upload, uploadInit } = useUpload(item, (progress: number, speed: number, estimate: number) => {
setUploadSpeed(item, progress, speed, estimate)
})
try {
await uploadInit()
await upload()
processUpload(queueId)
} catch (e) {
item.error.hasError = true
item.status = UploadQueueItemStatus.Failed
recalculateQueueCounts(queueId)
processUpload(queueId)
}
}

function setUploadSpeed(item: UploadQueueItem, progress: number, speed: number, estimate: number) {
Expand All @@ -128,9 +130,16 @@ export const useUploadQueuesStore = defineStore('commonUploadQueuesStore', () =>
item.progress.speed = speed
}

function queueItemProcessed () {}
function queueItemDuplicate () {}
function queueItemFailed () {}

return {
getQueue,
getQueueItems,
addByFiles,
queueItemProcessed,
queueItemDuplicate,
queueItemFailed,
}
})
Loading

0 comments on commit 517be98

Please sign in to comment.