Support async file conversions (#326)
* Support async file conversions Fixes #325 * Add loop * Add exit condition * More tweaks * Clean up * Fix large binary STL * Add error messages * Reduce timeout
This commit is contained in:
@ -22,7 +22,7 @@ describe('Function downloadFile', () => {
|
||||
'example.obj'
|
||||
)
|
||||
// TODO: add hash validation or something like that
|
||||
expect(response).toHaveLength(37077)
|
||||
expect(await response.text()).toHaveLength(37077)
|
||||
})
|
||||
|
||||
it('downloads a public LFS github file', async () => {
|
||||
@ -36,6 +36,6 @@ describe('Function downloadFile', () => {
|
||||
'Part1.SLDPRT'
|
||||
)
|
||||
// TODO: add hash validation or something like that
|
||||
expect(response).toHaveLength(70702)
|
||||
expect(await response.text()).toHaveLength(70702)
|
||||
})
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Octokit } from '@octokit/rest'
|
||||
import { Client, file } from '@kittycad/lib'
|
||||
import { api_calls, Client, file } from '@kittycad/lib'
|
||||
import { ContentFile, DiffEntry, FileBlob, FileDiff } from './types'
|
||||
import {
|
||||
FileExportFormat_type,
|
||||
@ -35,7 +35,7 @@ export async function downloadFile(
|
||||
repo: string,
|
||||
ref: string,
|
||||
path: string
|
||||
): Promise<string> {
|
||||
): Promise<Blob> {
|
||||
// First get some info on the blob with the Contents api
|
||||
const content = await octokit.rest.repos.getContent({
|
||||
owner,
|
||||
@ -54,15 +54,16 @@ export async function downloadFile(
|
||||
console.log(`Downloading ${contentFile.download_url}...`)
|
||||
const response = await fetch(contentFile.download_url)
|
||||
if (!response.ok) throw response
|
||||
return await response.text()
|
||||
return await response.blob()
|
||||
}
|
||||
|
||||
async function convert(
|
||||
client: Client,
|
||||
body: string,
|
||||
blob: Blob,
|
||||
extension: string,
|
||||
outputFormat = 'obj'
|
||||
) {
|
||||
const body = await blob.arrayBuffer()
|
||||
if (extension === outputFormat) {
|
||||
console.log(
|
||||
'Skipping conversion, as extension is equal to outputFormat'
|
||||
@ -76,9 +77,26 @@ async function convert(
|
||||
output_format: outputFormat as FileExportFormat_type,
|
||||
})
|
||||
const key = `source.${outputFormat}`
|
||||
if ('error_code' in response || !response.outputs[key]) throw response
|
||||
const { status, id, outputs } = response
|
||||
if ('error_code' in response) throw response
|
||||
const { id } = response
|
||||
let { status, outputs } = response
|
||||
console.log(`File conversion: ${id}, ${status}`)
|
||||
let retries = 0
|
||||
while (status !== 'completed' && status !== 'failed') {
|
||||
if (retries >= 60) {
|
||||
console.log('Async conversion took too long, aborting.')
|
||||
break
|
||||
}
|
||||
retries++
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
const response = await api_calls.get_async_operation({ client, id })
|
||||
if ('error_code' in response) throw response
|
||||
status = response.status
|
||||
console.log(`File conversion: ${id}, ${status} (retry #${retries})`)
|
||||
if ('outputs' in response) {
|
||||
outputs = response.outputs
|
||||
}
|
||||
}
|
||||
return outputs[key]
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { createPortal } from 'react-dom'
|
||||
import { Loading } from '../Loading'
|
||||
import { CadBlob } from './CadBlob'
|
||||
import { ColorModeWithAuto } from '@primer/react/lib/ThemeProvider'
|
||||
import { ErrorMessage } from './ErrorMessage'
|
||||
|
||||
function CadBlobPortal({
|
||||
element,
|
||||
@ -20,6 +21,7 @@ function CadBlobPortal({
|
||||
sha: string
|
||||
filename: string
|
||||
}): React.ReactElement {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [richBlob, setRichBlob] = useState<FileBlob>()
|
||||
const [richSelected, setRichSelected] = useState(true)
|
||||
const [toolbarContainer, setToolbarContainer] = useState<HTMLElement>()
|
||||
@ -65,14 +67,17 @@ function CadBlobPortal({
|
||||
|
||||
useEffect(() => {
|
||||
;(async () => {
|
||||
setLoading(true)
|
||||
const response = await chrome.runtime.sendMessage({
|
||||
id: MessageIds.GetFileBlob,
|
||||
data: { owner, repo, sha, filename },
|
||||
})
|
||||
if ('error' in response) {
|
||||
console.log(response.error)
|
||||
setLoading(false)
|
||||
} else {
|
||||
setRichBlob(response as FileBlob)
|
||||
setLoading(false)
|
||||
}
|
||||
})()
|
||||
}, [owner, repo, sha, filename])
|
||||
@ -115,10 +120,16 @@ function CadBlobPortal({
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{richBlob ? (
|
||||
<CadBlob blob={richBlob.blob} />
|
||||
) : (
|
||||
{loading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<>
|
||||
{richBlob ? (
|
||||
<CadBlob blob={richBlob.blob} />
|
||||
) : (
|
||||
<ErrorMessage />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Box>,
|
||||
blobContainer
|
||||
|
@ -7,6 +7,7 @@ import { Loading } from '../Loading'
|
||||
import { CadDiff } from './CadDiff'
|
||||
import { SourceRichToggle } from './SourceRichToggle'
|
||||
import { ColorModeWithAuto } from '@primer/react/lib/ThemeProvider'
|
||||
import { ErrorMessage } from './ErrorMessage'
|
||||
|
||||
function CadDiffPortal({
|
||||
element,
|
||||
@ -23,6 +24,7 @@ function CadDiffPortal({
|
||||
sha: string
|
||||
parentSha: string
|
||||
}): React.ReactElement {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [richDiff, setRichDiff] = useState<FileDiff>()
|
||||
const [richSelected, setRichSelected] = useState(true)
|
||||
const [toolbarContainer, setToolbarContainer] = useState<HTMLElement>()
|
||||
@ -54,14 +56,17 @@ function CadDiffPortal({
|
||||
|
||||
useEffect(() => {
|
||||
;(async () => {
|
||||
setLoading(true)
|
||||
const response = await chrome.runtime.sendMessage({
|
||||
id: MessageIds.GetFileDiff,
|
||||
data: { owner, repo, sha, parentSha, file },
|
||||
})
|
||||
if ('error' in response) {
|
||||
console.log(response.error)
|
||||
setLoading(false)
|
||||
} else {
|
||||
setRichDiff(response as FileDiff)
|
||||
setLoading(false)
|
||||
}
|
||||
})()
|
||||
}, [file, owner, repo, sha, parentSha])
|
||||
@ -87,13 +92,19 @@ function CadDiffPortal({
|
||||
{diffContainer &&
|
||||
createPortal(
|
||||
<Box sx={{ display: richSelected ? 'block' : 'none' }}>
|
||||
{richDiff ? (
|
||||
<CadDiff
|
||||
before={richDiff.before}
|
||||
after={richDiff.after}
|
||||
/>
|
||||
) : (
|
||||
{loading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<>
|
||||
{richDiff ? (
|
||||
<CadDiff
|
||||
before={richDiff.before}
|
||||
after={richDiff.after}
|
||||
/>
|
||||
) : (
|
||||
<ErrorMessage />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Box>,
|
||||
diffContainer
|
||||
|
Reference in New Issue
Block a user