Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions unitylibs/core/workflow/workflow-acrobat/action-binder.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export default class ActionBinder {
pre_upload_error_create_asset: -55,
pre_upload_error_missing_verb_config: -56,
pre_upload_error_transition_screen: -57,
pre_upload_error_direct_upload: -58,
validation_error_validate_files: -100,
validation_error_unsupported_type: -101,
validation_error_empty_file: -102,
Expand Down Expand Up @@ -234,6 +235,7 @@ export default class ActionBinder {
createAsset: `${base}/asset`,
finalizeAsset: `${base}/asset/finalize`,
getMetadata: `${base}/asset/metadata`,
directUpload: `${base}/asset/upload`,
};
unityConfig.connectorApiEndPoint = `${base}/asset/connector`;
return unityConfig;
Expand Down
3 changes: 3 additions & 0 deletions unitylibs/core/workflow/workflow-acrobat/target-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
},
"sendSplunkAnalytics": true,
"verbsWithoutMfuToSfuFallback": ["compress-pdf"],
"awaitFinalizeVerbs": ["word-to-pdf"],
"directUploadVerbs": ["word-to-pdf"],
"directUploadMaxSize": 1048576,
"nonpdfMfuFeedbackScreenTypeNonpdf": ["combine-pdf"],
"nonpdfSfuProductScreen": ["word-to-pdf", "jpg-to-pdf", "ppt-to-pdf", "excel-to-pdf", "png-to-pdf", "createpdf", "chat-pdf", "chat-pdf-student", "summarize-pdf", "pdf-ai", "heic-to-pdf", "quiz-maker", "flashcard-maker", "mindmap-maker"],
"mfuUploadAllowed": ["combine-pdf", "rotate-pages", "chat-pdf", "chat-pdf-student", "summarize-pdf", "pdf-ai", "quiz-maker", "flashcard-maker", "mindmap-maker"],
Expand Down
94 changes: 93 additions & 1 deletion unitylibs/core/workflow/workflow-acrobat/upload-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,77 @@ export default class UploadHandler {
return feature === 'pdf-ai' ? 'chat-pdf-pdf-ai' : feature;
}

isDirectUpload(file) {
const verb = this.actionBinder.workflowCfg.enabledFeatures[0];
const directUploadVerbs = this.actionBinder.workflowCfg.targetCfg.directUploadVerbs || [];
const directUploadMaxSize = this.actionBinder.workflowCfg.targetCfg.directUploadMaxSize || 0;
return directUploadVerbs.includes(verb) && file.size <= directUploadMaxSize;
}

async directUploadAsset(file, signal, workflowId = null) {
const formData = new FormData();
formData.append('surfaceId', unityConfig.surfaceId);
formData.append('targetProduct', this.actionBinder.workflowCfg.productName);
formData.append('name', file.name);
formData.append('size', file.size);
formData.append('format', 'application/pdf');
formData.append('file', file);
if (workflowId) formData.append('workflowId', workflowId);
const opts = await getApiCallOptions(
'POST',
unityConfig.apiKey,
this.actionBinder.getAdditionalHeaders() || {},
{ body: formData, signal },
);
delete opts.headers['Content-Type'];
const { response, attempt } = await this.networkUtils.fetchFromServiceWithRetry(
this.actionBinder.acrobatApiConfig.acrobatEndpoint.directUpload,
opts,
this.actionBinder.workflowCfg.targetCfg.fetchApiConfig.default,
);
return { ...response, attempt };
}

async directUploadSingleFile(file, fileData, isPdf = true) {
const abortSignal = this.actionBinder.getAbortSignal();
this.actionBinder.dispatchAnalyticsEvent('uploading', fileData);
this.actionBinder.setIsUploading(true);
let assetData;
try {
assetData = await this.directUploadAsset(file, abortSignal);
} catch (error) {
this.initSplashScreen();
await this.transitionScreen.showSplashScreen();
this.handleUploadError(error, 'pre_upload_error_direct_upload');
return false;
}
fileData.assetId = assetData.id;
this.actionBinder.setAssetId(assetData.id);
const effectiveFileType = await this.getEffectiveFileType(file);
const cOpts = {
assetId: assetData.id,
targetProduct: this.actionBinder.workflowCfg.productName,
payload: {
languageRegion: this.actionBinder.workflowCfg.langRegion,
languageCode: this.actionBinder.workflowCfg.langCode,
verb: this.getVerbForFeature(),
assetMetadata: { [assetData.id]: { name: file.name, size: file.size, type: effectiveFileType } },
...(!isPdf ? { feedback: 'nonpdf' } : {}),
},
};
const redirectSuccess = await this.actionBinder.handleRedirect(cOpts, fileData);
if (!redirectSuccess) return false;

this.actionBinder.operations.push(assetData.id);
this.actionBinder.uploadTimestamp = Date.now();
this.actionBinder.dispatchAnalyticsEvent('uploaded', {
...fileData,
assetId: assetData.id,
maxRetryCount: assetData.attempt || 0,
});
return true;
}

async getEffectiveFileType(file) {
const { getExtension } = await import('../../../utils/FileUtils.js');
const isHeicWithoutMimeType = this.actionBinder.workflowCfg.enabledFeatures[0] === 'heic-to-pdf'
Expand Down Expand Up @@ -198,7 +269,22 @@ export default class UploadHandler {
return { failedFiles, attemptMap };
}

isAwaitFinalizeVerb(verb) {
const awaitFinalizeVerbs = this.actionBinder.workflowCfg.targetCfg.awaitFinalizeVerbs || [];
return awaitFinalizeVerbs.includes(verb);
}

getFinalizeRetryConfig(verb) {
const baseConfig = this.actionBinder.workflowCfg.targetCfg.fetchApiConfig.finalizeAsset;
if (this.isAwaitFinalizeVerb(verb)) {
return { ...baseConfig, retryOn202: false };
}
return baseConfig;
}

async verifyContent(assetData, signal) {
const verb = this.actionBinder.workflowCfg.enabledFeatures[0];
const finalizeRetryConfig = this.getFinalizeRetryConfig(verb);
try {
const finalAssetData = {
surfaceId: unityConfig.surfaceId,
Expand All @@ -214,7 +300,8 @@ export default class UploadHandler {
const finalizeJson = await this.networkUtils.fetchFromServiceWithRetry(
this.actionBinder.acrobatApiConfig.acrobatEndpoint.finalizeAsset,
finalizeOpts,
this.actionBinder.workflowCfg.targetCfg.fetchApiConfig.finalizeAsset,
finalizeRetryConfig,
(responseJson) => responseJson,
);
if (!finalizeJson || Object.keys(finalizeJson).length !== 0) {
if (this.actionBinder.MULTI_FILE) {
Expand Down Expand Up @@ -338,6 +425,11 @@ export default class UploadHandler {
}

async uploadSingleFile(file, fileData, isPdf = true) {
if (this.isDirectUpload(file)) {
const success = await this.directUploadSingleFile(file, fileData, isPdf);
if (success) return;
}

const { maxConcurrentChunks } = this.getConcurrentLimits();
const abortSignal = this.actionBinder.getAbortSignal();
let cOpts = {};
Expand Down
10 changes: 9 additions & 1 deletion unitylibs/utils/NetworkUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ export default class NetworkUtils {
}
}

shouldRetryPollingRequest(status, retryConfig, customRetryCheckResult) {
if (customRetryCheckResult) return true;
if (status >= 500 && status < 600) return true;
if (status === 429) return true;
if (status === 202 && retryConfig.retryOn202 !== false) return true;
return false;
}

async fetchFromServiceWithServerPollingRetry(url, options, retryConfig, onSuccess, onError) {
const maxRetryDelay = retryConfig.retryParams?.maxRetryDelay || 300000;
let timeLapsed = 0;
Expand All @@ -133,7 +141,7 @@ export default class NetworkUtils {
const { status, headers } = response;
const responseJson = await this.getResponseJson(response);
const customRetryCheckResult = retryConfig.extraRetryCheck && await retryConfig.extraRetryCheck(status, responseJson);
if (customRetryCheckResult || status === 202 || (status >= 500 && status < 600) || status === 429) {
if (this.shouldRetryPollingRequest(status, retryConfig, customRetryCheckResult)) {
const retryDelay = (parseInt(headers.get('retry-after'), 10) * 1000) || retryConfig.retryParams?.defaultRetryDelay || 5000;
await new Promise((resolve) => { setTimeout(resolve, retryDelay); });
timeLapsed += retryDelay;
Expand Down
Loading