From 4a58e66d9999e4dbc5cb66a27d99756017e03403 Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Mon, 23 Jun 2025 13:45:26 +0100 Subject: [PATCH] feat(file importer): send skp to rhino parser (#4973) --- package.json | 2 +- .../src/controller/filesApi.ts | 2 +- .../src/nextGen/jobProcessor.ts | 1 + .../fileimport-service/src/nextGen/main.ts | 28 +++++++++++-------- .../components/project/CardImportFileArea.vue | 5 +++- packages/frontend-2/composables/globals.ts | 7 +++++ .../lib/core/composables/fileImport.ts | 6 +++- packages/preview-service/src/main.ts | 4 +-- .../modules/fileuploads/queues/fileimports.ts | 2 +- tests/deployment/build-images.tiltfile | 6 ++-- 10 files changed, 41 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index b3ee798b6..e1717fb78 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "dev:docker:down": "docker compose -f ./docker-compose-deps.yml down", "dev:docker:down:volumes": "docker compose -f ./docker-compose-deps.yml down --volumes", "dev:docker:restart": "yarn dev:docker:down && yarn dev:docker:up", - "dev:kind:up": "ctlptl apply --filename ./.tests/deployment/helm/cluster-config.yaml", + "dev:kind:up": "ctlptl apply --filename ./tests/deployment/helm/cluster-config.yaml", "dev:kind:down": "ctlptl delete -f ./tests/deployment/helm/cluster-config.yaml", "dev:kind:helm:up": "yarn dev:kind:up && tilt up --file ./tests/deployment/helm/Tiltfile --context kind-speckle-server", "dev:kind:helm:down": "tilt down --file ./tests/deployment/helm/Tiltfile --context kind-speckle-server", diff --git a/packages/fileimport-service/src/controller/filesApi.ts b/packages/fileimport-service/src/controller/filesApi.ts index 4b3945453..0adf2174c 100644 --- a/packages/fileimport-service/src/controller/filesApi.ts +++ b/packages/fileimport-service/src/controller/filesApi.ts @@ -36,7 +36,7 @@ export async function downloadFile({ boundLogger.info( { destinationFile: destination, downloadUrl: downloadUrl.toString() }, - 'Downloading file {fileId} (project: {streamId}) from ${downloadUrl} to {destinationFile}' + 'Downloading file {fileId} (project: {streamId}) from {downloadUrl} to {destinationFile}' ) let response diff --git a/packages/fileimport-service/src/nextGen/jobProcessor.ts b/packages/fileimport-service/src/nextGen/jobProcessor.ts index 66d40d145..252d62eef 100644 --- a/packages/fileimport-service/src/nextGen/jobProcessor.ts +++ b/packages/fileimport-service/src/nextGen/jobProcessor.ts @@ -84,6 +84,7 @@ export const jobProcessor = async ({ break case 'stl': case 'obj': + case 'skp': await runProcessWithTimeout( taskLogger, RHINO_IMPORTER_PATH, diff --git a/packages/fileimport-service/src/nextGen/main.ts b/packages/fileimport-service/src/nextGen/main.ts index 2682d2c95..45759e901 100644 --- a/packages/fileimport-service/src/nextGen/main.ts +++ b/packages/fileimport-service/src/nextGen/main.ts @@ -76,9 +76,9 @@ export const main = async () => { } catch (err) { if (appState === AppState.SHUTTINGDOWN) { // likely that the job was cancelled due to the service shutting down - jobLogger.warn({ err }, 'Processing {jobId} failed') + jobLogger.warn({ err }, 'Processing job {jobId} failed') } else { - jobLogger.error({ err }, 'Processing {jobId} failed') + jobLogger.error({ err }, 'Processing job {jobId} failed') } if (err instanceof Error) { encounteredError = true @@ -121,19 +121,23 @@ const sendResult = async ({ token: string result: FileImportResultPayload }) => { - const response = await fetch( - `${serverUrl}/api/projects/${projectId}/fileimporter/jobs/${jobId}/results`, - { - method: 'POST', - headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, - - body: JSON.stringify(result) - } + const sendResultUrl = new URL( + `/api/projects/${projectId}/fileimporter/jobs/${jobId}/results`, + serverUrl ) + const response = await fetch(sendResultUrl.toString(), { + method: 'POST', + headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' }, + + body: JSON.stringify(result) + }) if (!response.ok) { const text = await response.text() - currentJob?.logger.error({ cause: text }, 'Failed to report job result') - throw new Error(`Failed to report job result: ${text}`) + currentJob?.logger.error( + { cause: text, sendResultUrl: sendResultUrl.toString() }, + 'Failed to report result for job {jobId} to {sendResultUrl}' + ) + throw new Error(`Failed to report result for job ${jobId}: ${text}`) } } diff --git a/packages/frontend-2/components/project/CardImportFileArea.vue b/packages/frontend-2/components/project/CardImportFileArea.vue index 9fc636d42..17c7ad51b 100644 --- a/packages/frontend-2/components/project/CardImportFileArea.vue +++ b/packages/frontend-2/components/project/CardImportFileArea.vue @@ -51,7 +51,7 @@ to publish a {{ modelName ? '' : 'new model' }} version to {{ modelName ? 'this model' : 'this project' }}, or drag and drop a - IFC/OBJ/STL file here. + IFC/OBJ/STL{{ isNextGenFileImporterEnabled ? '/SKP' : '' }} file here.

@@ -85,6 +85,7 @@ import type { ProjectPageLatestItemsModelItemFragment } from '~/lib/common/generated/gql/graphql' import type { FileAreaUploadingPayload } from '~/lib/form/helpers/fileUpload' +import { useIsNextGenFileImporterEnabled } from '~/composables/globals' type EmptyStateVariants = 'modelGrid' | 'modelList' | 'modelsSection' @@ -127,6 +128,8 @@ const props = defineProps<{ emptyStateVariant?: EmptyStateVariants }>() +const isNextGenFileImporterEnabled = useIsNextGenFileImporterEnabled() + const { maxSizeInBytes, onFilesSelected, diff --git a/packages/frontend-2/composables/globals.ts b/packages/frontend-2/composables/globals.ts index e08033a86..c65dc905c 100644 --- a/packages/frontend-2/composables/globals.ts +++ b/packages/frontend-2/composables/globals.ts @@ -68,4 +68,11 @@ export const useIsBillingIntegrationEnabled = () => { return ref(FF_BILLING_INTEGRATION_ENABLED) } +export const useIsNextGenFileImporterEnabled = () => { + const { + public: { FF_NEXT_GEN_FILE_IMPORTER_ENABLED } + } = useRuntimeConfig() + return ref(FF_NEXT_GEN_FILE_IMPORTER_ENABLED) +} + export { useGlobalToast, useActiveUser, usePageQueryStandardFetchPolicy } diff --git a/packages/frontend-2/lib/core/composables/fileImport.ts b/packages/frontend-2/lib/core/composables/fileImport.ts index d6c7356c3..c65b35597 100644 --- a/packages/frontend-2/lib/core/composables/fileImport.ts +++ b/packages/frontend-2/lib/core/composables/fileImport.ts @@ -11,6 +11,7 @@ import { useAuthCookie } from '~~/lib/auth/composables/auth' import { BlobUploadStatus, type BlobPostResultItem } from '~~/lib/core/api/blobStorage' import { useMixpanel } from '~~/lib/core/composables/mp' import { graphql } from '~/lib/common/generated/gql' +import { useIsNextGenFileImporterEnabled } from '~/composables/globals' import type { UseFileImport_ModelFragment, UseFileImport_ProjectFragment @@ -190,8 +191,11 @@ export function useFileImport(params: { const { maxSizeInBytes } = useServerFileUploadLimit() const authToken = useAuthCookie() const apiOrigin = useApiOrigin() + const isNextGenFileImporterEnabled = useIsNextGenFileImporterEnabled() - const accept = ref('.ifc,.stl,.obj') + const accept = computed( + () => `.ifc,.stl,.obj${isNextGenFileImporterEnabled.value ? ',.skp' : ''}` + ) const upload = ref(null as Nullable) const isUploading = ref(false) diff --git a/packages/preview-service/src/main.ts b/packages/preview-service/src/main.ts index 1392aae9c..c8490497e 100644 --- a/packages/preview-service/src/main.ts +++ b/packages/preview-service/src/main.ts @@ -140,9 +140,9 @@ const server = app.listen(port, host, async () => { } catch (err) { if (appState === AppState.SHUTTINGDOWN) { // likely that the job was cancelled due to the service shutting down - jobLogger.warn({ err }, 'Processing {jobId} failed') + jobLogger.warn({ err }, 'Processing job {jobId} failed') } else { - jobLogger.error({ err }, 'Processing {jobId} failed') + jobLogger.error({ err }, 'Processing job {jobId} failed') } if (err instanceof Error) { encounteredError = true diff --git a/packages/server/modules/fileuploads/queues/fileimports.ts b/packages/server/modules/fileuploads/queues/fileimports.ts index f76132538..4f8c430a6 100644 --- a/packages/server/modules/fileuploads/queues/fileimports.ts +++ b/packages/server/modules/fileuploads/queues/fileimports.ts @@ -78,7 +78,7 @@ export const initializeRhinoQueue = async () => label: 'Rhino File Import Queue', queueName: FILEIMPORT_SERVICE_RHINO_QUEUE_NAME, redisUrl: getFileImportServiceRhinoParserRedisUrl() ?? getRedisUrl(), - supportedFileTypes: ['obj'] + supportedFileTypes: ['obj', 'stl', 'skp'] }) export const initializeIfcQueue = async () => diff --git a/tests/deployment/build-images.tiltfile b/tests/deployment/build-images.tiltfile index 9331d71c5..7cd9db364 100644 --- a/tests/deployment/build-images.tiltfile +++ b/tests/deployment/build-images.tiltfile @@ -1,7 +1,7 @@ # Build each Dockerfile and reference resource for use in the primary Tiltfile # The referenced resources can then be deployed by the Helm Chart -def speckle_image(package,original_package_name=None): +def speckle_image(package,original_package_name=None,image_prefix='localhost:5000'): if not original_package_name: original_package_name = package @@ -9,8 +9,8 @@ def speckle_image(package,original_package_name=None): if package == 'test-deployment' or package == 'docker-compose-ingress': package_dir = 'utils/{}'.format(package) docker_build('speckle/speckle-{}'.format(package), - context='../..', - dockerfile='../../{}/Dockerfile'.format(package_dir), + context='../../..', + dockerfile='../../../{}/Dockerfile'.format(package_dir), platform='linux/amd64', ignore = ['**/node_modules', '**/dist', '**/build', '**/coverage', 'minio-data', 'postgres-data'] )