Skip to content

Commit

Permalink
spx-gui: implement batched object URL processing and optimize lazy lo…
Browse files Browse the repository at this point in the history
…ading

- Introduced `util.batchedMakeObjectUrls` to queue and merge object URL
  requests.
- Updated `cloud.universalUrlToWebUrl` to use batched processing.
- Refactored `cloud.getFiles` and file creation process to support lazy
  URL resolution, addressing potential URL expiry issues.

Fixes goplus#653
  • Loading branch information
aofei committed Jul 23, 2024
1 parent bae5459 commit cae7733
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 23 deletions.
38 changes: 37 additions & 1 deletion spx-gui/src/apis/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* @desc util-related APIs of spx-backend
*/

import Mutex from '@/utils/mutex'
import { client, type UniversalUrl, type UniversalToWebUrlMap } from './common'

export interface FormatError {
Expand Down Expand Up @@ -36,9 +37,44 @@ export function getUpInfo() {
return client.get('/util/upinfo') as Promise<UpInfo>
}

export async function makeObjectUrls(objects: UniversalUrl[]) {
export async function makeObjectUrls(objects: UniversalUrl[]): Promise<UniversalToWebUrlMap> {
const res = (await client.post('/util/fileurls', { objects: objects })) as {
objectUrls: UniversalToWebUrlMap
}
return res.objectUrls
}

export const batchedMakeObjectUrls = (() => {
const batch = new Set<UniversalUrl>()
let pendingPromise: Promise<UniversalToWebUrlMap> | null = null
const mutex = new Mutex()

const processBatch = async () => {
let currentBatch!: UniversalUrl[]
await mutex.runExclusive(() => {
currentBatch = Array.from(batch)
batch.clear()
pendingPromise = null
})

try {
return await makeObjectUrls(currentBatch)
} catch (e) {
throw Object.fromEntries(currentBatch.map((url) => [url, e]))
}
}

return async (objects: UniversalUrl[]): Promise<UniversalToWebUrlMap> => {
let promise!: Promise<UniversalToWebUrlMap>
await mutex.runExclusive(() => {
objects.forEach((url) => batch.add(url))
if (pendingPromise == null) {
pendingPromise = new Promise((resolve) => setTimeout(() => resolve(processBatch()), 1))
}
promise = pendingPromise
})

const objectUrls = await promise
return Object.fromEntries(objects.map((url) => [url, objectUrls[url]]))
}
})()
41 changes: 19 additions & 22 deletions spx-gui/src/models/common/cloud.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import * as qiniu from 'qiniu-js'
import { filename } from '@/utils/path'
import type { WebUrl, UniversalUrl, FileCollection, UniversalToWebUrlMap } from '@/apis/common'
import type { WebUrl, UniversalUrl, FileCollection } from '@/apis/common'
import type { ProjectData } from '@/apis/project'
import { IsPublic, addProject, getProject, updateProject } from '@/apis/project'
import { getUpInfo as getRawUpInfo, makeObjectUrls, type UpInfo as RawUpInfo } from '@/apis/util'
import {
batchedMakeObjectUrls,
getUpInfo as getRawUpInfo,
type UpInfo as RawUpInfo
} from '@/apis/util'
import { DefaultException } from '@/utils/exception'
import type { Metadata } from '../project'
import { File, toNativeFile, toText, type Files } from './file'
Expand Down Expand Up @@ -57,24 +61,10 @@ export async function saveFiles(
}

export async function getFiles(fileCollection: FileCollection): Promise<Files> {
const objectUniversalUrls = Object.values(fileCollection).filter(
(url) => new URL(url).protocol === fileUniversalUrlSchemes.kodo
)
const objectUrls: UniversalToWebUrlMap = objectUniversalUrls.length
? await makeObjectUrls(objectUniversalUrls)
: {}

const files: Files = {}
Object.keys(fileCollection).forEach((path) => {
Object.keys(fileCollection).forEach(async (path) => {
const universalUrl = fileCollection[path]
let webUrl = universalUrl

const objectUrl = objectUrls[universalUrl]
if (objectUrl) {
webUrl = objectUrl
}

const file = createFileWithWebUrl(webUrl, filename(path))
const file = createFileWithUniversalUrl(universalUrl, filename(path))
setUniversalUrl(file, universalUrl)
files[path] = file
})
Expand All @@ -92,11 +82,18 @@ function getUniversalUrl(file: File): UniversalUrl | null {
return file.meta.universalUrl ?? null
}

export function createFileWithWebUrl(webUrl: WebUrl, name = filename(webUrl)) {
function createFileWithUniversalUrl(url: UniversalUrl, name = filename(url)) {
return new File(name, async () => {
const webUrl = await universalUrlToWebUrl(url)
const resp = await fetch(webUrl)
const blob = await resp.blob()
return blob.arrayBuffer()
return resp.arrayBuffer()
})
}

export function createFileWithWebUrl(url: WebUrl, name = filename(url)) {
return new File(name, async () => {
const resp = await fetch(url)
return resp.arrayBuffer()
})
}

Expand All @@ -108,7 +105,7 @@ export async function getWebUrl(file: File) {
async function universalUrlToWebUrl(universalUrl: UniversalUrl) {
const { protocol } = new URL(universalUrl)
if (protocol !== fileUniversalUrlSchemes.kodo) return universalUrl
const map = await makeObjectUrls([universalUrl])
const map = await batchedMakeObjectUrls([universalUrl])
return map[universalUrl]
}

Expand Down

0 comments on commit cae7733

Please sign in to comment.