From ee84754cfb998101283c48e2230e008aa4667e7e Mon Sep 17 00:00:00 2001 From: Convly Date: Tue, 30 May 2023 14:32:41 +0200 Subject: [PATCH] Revert mistakes for dts changes --- .../core/data-transfer/src/engine/index.ts | 96 ++++++++++++++----- .../strapi/providers/remote-source/index.ts | 59 ++---------- .../core/data-transfer/src/utils/index.ts | 1 + 3 files changed, 83 insertions(+), 73 deletions(-) diff --git a/packages/core/data-transfer/src/engine/index.ts b/packages/core/data-transfer/src/engine/index.ts index 54f7a6fee6..be9e54f20b 100644 --- a/packages/core/data-transfer/src/engine/index.ts +++ b/packages/core/data-transfer/src/engine/index.ts @@ -4,8 +4,8 @@ import { extname } from 'path'; import { EOL } from 'os'; import { isEmpty, uniq, last, isNumber, difference, set, omit } from 'lodash/fp'; import { diff as semverDiff } from 'semver'; -import type { Schema, Utils } from '@strapi/strapi'; +import type { Schema, Utils } from '@strapi/strapi'; import type { IAsset, IDestinationProvider, @@ -23,11 +23,12 @@ import type { TransferFilters, TransferFilterPreset, StreamItem, + SchemaDiffHandler, + SchemaDiffHandlerContext, } from '../../types'; import type { Diff } from '../utils/json'; import { compareSchemas, validateProvider } from './validation'; -import { filter, map } from '../utils/stream'; import { TransferEngineError, TransferEngineValidationError } from './errors'; import { @@ -36,6 +37,7 @@ import { ErrorDiagnosticSeverity, } from './diagnostic'; import { DataTransferError } from '../errors'; +import * as utils from '../utils'; export const TRANSFER_STAGES: ReadonlyArray = Object.freeze([ 'entities', @@ -103,6 +105,16 @@ class TransferEngine< diagnostics: IDiagnosticReporter; + #handlers: { + schemaDiff: SchemaDiffHandler[]; + } = { + schemaDiff: [], + }; + + onSchemaDiff(handler: SchemaDiffHandler) { + this.#handlers?.schemaDiff?.push(handler); + } + // Save the currently open stream so that we can access it at any time #currentStream?: Writable; @@ -122,8 +134,8 @@ class TransferEngine< /** * Report a fatal error and throw it */ - #panic(error: Error) { - this.#reportError(error, 'fatal'); + panic(error: Error) { + this.reportError(error, 'fatal'); throw error; } @@ -131,7 +143,7 @@ class TransferEngine< /** * Report an error diagnostic */ - #reportError(error: Error, severity: ErrorDiagnosticSeverity) { + reportError(error: Error, severity: ErrorDiagnosticSeverity) { this.diagnostics.report({ kind: 'error', details: { @@ -147,7 +159,7 @@ class TransferEngine< /** * Report a warning diagnostic */ - #reportWarning(message: string, origin?: string) { + reportWarning(message: string, origin?: string) { this.diagnostics.report({ kind: 'warning', details: { createdAt: new Date(), message, origin }, @@ -157,7 +169,7 @@ class TransferEngine< /** * Report an info diagnostic */ - #reportInfo(message: string, params?: unknown) { + reportInfo(message: string, params?: unknown) { this.diagnostics.report({ kind: 'info', details: { createdAt: new Date(), message, params }, @@ -183,11 +195,11 @@ class TransferEngine< const chainTransforms: StreamItem[] = []; for (const transform of transforms) { if ('filter' in transform) { - chainTransforms.push(filter(transform.filter)); + chainTransforms.push(utils.stream.filter(transform.filter)); } if ('map' in transform) { - chainTransforms.push(map(transform.map)); + chainTransforms.push(utils.stream.map(transform.map)); } } if (chainTransforms.length) { @@ -397,11 +409,11 @@ class TransferEngine< const path = diff.path.join('.'); if (diff.kind === 'added') { - return `${path} exists in destination schema but not in source schema`; + return `${path} exists in destination schema but not in source schema and the data will not be transferred.`; } if (diff.kind === 'deleted') { - return `${path} exists in source schema but not in destination schema`; + return `${path} exists in source schema but not in destination schema and the data will not be transferred.`; } if (diff.kind === 'modified') { @@ -496,7 +508,7 @@ class TransferEngine< results.forEach((state) => { if (state.status === 'rejected') { - this.#reportWarning(state.reason, `transfer(${stage})`); + this.reportWarning(state.reason, `transfer(${stage})`); } }); @@ -523,7 +535,7 @@ class TransferEngine< .on('error', (e) => { updateEndTime(); this.#emitStageUpdate('error', stage); - this.#reportError(e, 'error'); + this.reportError(e, 'error'); destination.destroy(e); reject(e); }) @@ -539,7 +551,11 @@ class TransferEngine< // Cause an ongoing transfer to abort gracefully async abortTransfer(): Promise { - this.#currentStream?.destroy(new TransferEngineError('fatal', 'Transfer aborted.')); + const err = new TransferEngineError('fatal', 'Transfer aborted.'); + if (!this.#currentStream) { + throw err; + } + this.#currentStream.destroy(err); } async init(): Promise { @@ -566,7 +582,7 @@ class TransferEngine< results.forEach((result) => { if (result.status === 'rejected') { - this.#panic(result.reason); + this.panic(result.reason); } }); } @@ -582,7 +598,7 @@ class TransferEngine< results.forEach((result) => { if (result.status === 'rejected') { - this.#panic(result.reason); + this.panic(result.reason); } }); } @@ -626,15 +642,47 @@ class TransferEngine< ); } - const { sourceSchema, destinationSchema } = await this.#getSchemas(); + const sourceSchemas = (await this.sourceProvider.getSchemas?.()) as SchemaMap; + const destinationSchemas = (await this.destinationProvider.getSchemas?.()) as SchemaMap; try { - if (sourceSchema && destinationSchema) { - this.#assertSchemasMatching(sourceSchema, destinationSchema); + if (sourceSchemas && destinationSchemas) { + this.#assertSchemasMatching(sourceSchemas, destinationSchemas); } } catch (error) { - if (error instanceof Error) { - this.#panic(error); + // if this is a schema matching error, allow handlers to resolve it + if (error instanceof TransferEngineValidationError && error.details?.details?.diffs) { + const schemaDiffs = error.details?.details?.diffs as Record; + + const context: SchemaDiffHandlerContext = { + ignoredDiffs: {}, + diffs: schemaDiffs, + source: this.sourceProvider, + destination: this.destinationProvider, + }; + + // if we don't have any handlers, throw the original error + if (isEmpty(this.#handlers.schemaDiff)) { + throw error; + } + + await utils.middleware.runMiddleware( + context, + this.#handlers.schemaDiff + ); + + // if there are any remaining diffs that weren't ignored + const unresolvedDiffs = utils.json.diff(context.diffs, context.ignoredDiffs); + if (unresolvedDiffs.length) { + this.panic( + new TransferEngineValidationError('Unresolved differences in schema', { + check: 'schema.changes', + unresolvedDiffs, + }) + ); + } + + return; } throw error; @@ -675,7 +723,7 @@ class TransferEngine< e instanceof Error && (!lastDiagnostic || lastDiagnostic.kind !== 'error' || lastDiagnostic.details.error !== e) ) { - this.#reportError(e, (e as DataTransferError).severity || 'fatal'); + this.reportError(e, (e as DataTransferError).severity || 'fatal'); } // Rollback the destination provider if an exception is thrown during the transfer @@ -699,9 +747,9 @@ class TransferEngine< } catch (error) { // Error happening during the before transfer step should be considered fatal errors if (error instanceof Error) { - this.#panic(error); + this.panic(error); } else { - this.#panic( + this.panic( new Error(`Unknwon error when executing "beforeTransfer" on the ${origin} provider`) ); } diff --git a/packages/core/data-transfer/src/strapi/providers/remote-source/index.ts b/packages/core/data-transfer/src/strapi/providers/remote-source/index.ts index 4d21811f7a..50d6a3e562 100644 --- a/packages/core/data-transfer/src/strapi/providers/remote-source/index.ts +++ b/packages/core/data-transfer/src/strapi/providers/remote-source/index.ts @@ -171,56 +171,17 @@ class RemoteStrapiSourceProvider implements ISourceProvider { } async initTransfer(): Promise { - return new Promise((resolve, reject) => { - this.ws - ?.on('unexpected-response', (_req, res) => { - if (res.statusCode === 401) { - return reject( - new ProviderInitializationError( - 'Failed to initialize the connection: Authentication Error' - ) - ); - } - - if (res.statusCode === 403) { - return reject( - new ProviderInitializationError( - 'Failed to initialize the connection: Authorization Error' - ) - ); - } - - if (res.statusCode === 404) { - return reject( - new ProviderInitializationError( - 'Failed to initialize the connection: Data transfer is not enabled on the remote host' - ) - ); - } - - return reject( - new ProviderInitializationError( - `Failed to initialize the connection: Unexpected server response ${res.statusCode}` - ) - ); - }) - ?.once('open', async () => { - const query = this.dispatcher?.dispatchCommand({ - command: 'init', - }); - - const res = (await query) as Server.Payload; - - if (!res?.transferID) { - return reject( - new ProviderTransferError('Init failed, invalid response from the server') - ); - } - - resolve(res.transferID); - }) - .once('error', reject); + const query = this.dispatcher?.dispatchCommand({ + command: 'init', }); + + const res = (await query) as Server.Payload; + + if (!res?.transferID) { + throw new ProviderTransferError('Init failed, invalid response from the server'); + } + + return res.transferID; } async bootstrap(): Promise { diff --git a/packages/core/data-transfer/src/utils/index.ts b/packages/core/data-transfer/src/utils/index.ts index 133de63aa9..c729abb69d 100644 --- a/packages/core/data-transfer/src/utils/index.ts +++ b/packages/core/data-transfer/src/utils/index.ts @@ -3,3 +3,4 @@ export * as stream from './stream'; export * as json from './json'; export * as schema from './schema'; export * as transaction from './transaction'; +export * as middleware from './middleware';