Skip to content

Commit

Permalink
feat: async secureDeliveryProxyUrlResolver (#677)
Browse files Browse the repository at this point in the history
* feat: async `secureDeliveryProxyUrlResolver`

* feat: async `secureDeliveryProxyUrlResolver`

* refactor: use optional chaining to invoke fn

---------

Co-authored-by: nd0ut <[email protected]>
  • Loading branch information
nd0ut and nd0ut authored Jul 16, 2024
1 parent dea43c7 commit 60f06be
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 59 deletions.
20 changes: 12 additions & 8 deletions abstract/Block.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,26 +236,30 @@ export class Block extends BaseComponent {
Data.deleteCtx(this.ctxName);

this.localeManager?.destroy();
this.a11y?.destroy();
}

/**
* @param {String} url
* @returns {String}
* @returns {Promise<String>}
* @protected
*/
proxyUrl(url) {
async proxyUrl(url) {
if (this.cfg.secureDeliveryProxy && this.cfg.secureDeliveryProxyUrlResolver) {
console.warn(
'Both secureDeliveryProxy and secureDeliveryProxyUrlResolver are set. The secureDeliveryProxyUrlResolver will be used.',
);
}
if (this.cfg.secureDeliveryProxyUrlResolver) {
return this.cfg.secureDeliveryProxyUrlResolver(url, {
uuid: extractUuid(url),
cdnUrlModifiers: extractCdnUrlModifiers(url),
fileName: extractFilename(url),
});
try {
return await this.cfg.secureDeliveryProxyUrlResolver(url, {
uuid: extractUuid(url),
cdnUrlModifiers: extractCdnUrlModifiers(url),
fileName: extractFilename(url),
});
} catch (err) {
console.error('Failed to resolve secure delivery proxy URL. Falling back to the default URL.', err);
return url;
}
}
if (this.cfg.secureDeliveryProxy) {
return applyTemplateData(
Expand Down
8 changes: 4 additions & 4 deletions abstract/UploaderBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,10 @@ export class UploaderBlock extends ActivityBlock {
return entry.getValue('errors').length > 0;
});
if (
uploadCollection.size > 0 &&
errorItems.length === 0 &&
uploadCollection.size === loadedItems.length &&
this.$['*collectionErrors'].length === 0
uploadCollection.size > 0 &&
errorItems.length === 0 &&
uploadCollection.size === loadedItems.length &&
this.$['*collectionErrors'].length === 0
) {
this.emit(
EventType.COMMON_UPLOAD_SUCCESS,
Expand Down
2 changes: 1 addition & 1 deletion blocks/CloudImageEditor/src/CloudImageEditorBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export class CloudImageEditorBlock extends Block {
}

try {
const cdnUrl = createCdnUrl(this.$['*originalUrl'], createCdnUrlModifiers('json'));
const cdnUrl = await this.proxyUrl(createCdnUrl(this.$['*originalUrl'], createCdnUrlModifiers('json')));
const json = await fetch(cdnUrl).then((response) => response.json());

const { width, height } = /** @type {{ width: number; height: number }} */ (json);
Expand Down
54 changes: 32 additions & 22 deletions blocks/CloudImageEditor/src/EditorFilterControl.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
// @ts-check
import { createCdnUrl, createCdnUrlModifiers } from '../../../utils/cdn-utils.js';
import { EditorButtonControl } from './EditorButtonControl.js';
import { FAKE_ORIGINAL_FILTER } from './EditorSlider.js';
import { COMMON_OPERATIONS, transformationsToOperations } from './lib/transformationUtils.js';
import { preloadImage } from './lib/preloadImage.js';

export class EditorFilterControl extends EditorButtonControl {
init$ = {
...this.init$,
active: false,
title: '',
icon: '',
isOriginal: false,
iconSize: '20',
'on.click': null,
};
constructor() {
super();

this.init$ = {
...this.init$,
active: false,
title: '',
icon: '',
isOriginal: false,
iconSize: '20',
'on.click': null,
};
}

_previewSrc() {
let previewSize = parseInt(window.getComputedStyle(this).getPropertyValue('--l-base-min-width'), 10);
Expand All @@ -24,6 +29,7 @@ export class EditorFilterControl extends EditorButtonControl {

/** @type {import('./types.js').Transformations} */
let transformations = { ...this.$['*editorTransformations'] };
// @ts-expect-error FIXME: fix this
transformations[this._operation] =
this._filter !== FAKE_ORIGINAL_FILTER
? {
Expand All @@ -47,10 +53,10 @@ export class EditorFilterControl extends EditorButtonControl {
* @param {IntersectionObserverEntry[]} entries
* @param {IntersectionObserver} observer
*/
_observerCallback(entries, observer) {
async _observerCallback(entries, observer) {
let intersectionEntry = entries[0];
if (intersectionEntry.isIntersecting) {
let src = this.proxyUrl(this._previewSrc());
let src = await this.proxyUrl(this._previewSrc());
let previewEl = this.ref['preview-el'];
let { promise, cancel } = preloadImage(src);
this._cancelPreload = cancel;
Expand All @@ -66,14 +72,14 @@ export class EditorFilterControl extends EditorButtonControl {
observer.unobserve(this);
});
} else {
this._cancelPreload && this._cancelPreload();
this._cancelPreload?.();
}
}

initCallback() {
super.initCallback();

this.$['on.click'] = (e) => {
this.$['on.click'] = () => {
if (!this.$.active) {
this.$['*sliderEl'].setOperation(this._operation, this._filter);
this.$['*sliderEl'].apply();
Expand All @@ -85,12 +91,16 @@ export class EditorFilterControl extends EditorButtonControl {
this.$['*currentFilter'] = this._filter;
};

this.defineAccessor('filter', (filter) => {
this._operation = 'filter';
this._filter = filter;
this.$.isOriginal = filter === FAKE_ORIGINAL_FILTER;
this.$.icon = this.$.isOriginal ? 'original' : 'slider';
});
this.defineAccessor(
'filter',
/** @param {string} filter */
(filter) => {
this._operation = 'filter';
this._filter = filter;
this.$.isOriginal = filter === FAKE_ORIGINAL_FILTER;
this.$.icon = this.$.isOriginal ? 'original' : 'slider';
},
);

this._observer = new window.IntersectionObserver(this._observerCallback.bind(this), {
threshold: [0, 1],
Expand Down Expand Up @@ -128,9 +138,9 @@ export class EditorFilterControl extends EditorButtonControl {
}
});

this.sub('*networkProblems', (networkProblems) => {
this.sub('*networkProblems', async (networkProblems) => {
if (!networkProblems) {
let src = this.proxyUrl(this._previewSrc());
let src = await this.proxyUrl(this._previewSrc());
let previewEl = this.ref['preview-el'];
if (previewEl.style.backgroundImage) {
previewEl.style.backgroundImage = 'none';
Expand All @@ -143,7 +153,7 @@ export class EditorFilterControl extends EditorButtonControl {
destroyCallback() {
super.destroyCallback();
this._observer?.disconnect();
this._cancelPreload && this._cancelPreload();
this._cancelPreload?.();
}
}

Expand Down
6 changes: 3 additions & 3 deletions blocks/CloudImageEditor/src/EditorImageCropper.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ export class EditorImageCropper extends Block {
* @param {import('./types.js').Transformations} transformations
* @returns {Promise<HTMLImageElement>}
*/
_waitForImage(originalUrl, transformations) {
async _waitForImage(originalUrl, transformations) {
let width = this.offsetWidth;
transformations = {
...transformations,
Expand All @@ -470,13 +470,13 @@ export class EditorImageCropper extends Block {
flip: undefined,
mirror: undefined,
};
let src = this.proxyUrl(viewerImageSrc(originalUrl, width, transformations));
let src = await this.proxyUrl(viewerImageSrc(originalUrl, width, transformations));
let { promise, cancel, image } = preloadImage(src);

let stop = this._handleImageLoading(src);
image.addEventListener('load', stop, { once: true });
image.addEventListener('error', stop, { once: true });
this._cancelPreload && this._cancelPreload();
this._cancelPreload?.();
this._cancelPreload = cancel;

return promise
Expand Down
32 changes: 17 additions & 15 deletions blocks/CloudImageEditor/src/EditorImageFader.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ export class EditorImageFader extends Block {
* @param {String} [options.filter]
* @param {String} [options.operation]
* @param {Number} [options.value]
* @returns {String}
* @returns {Promise<String>}
*/
_imageSrc({ url = this._url, filter = this._filter, operation, value } = {}) {
async _imageSrc({ url = this._url, filter = this._filter, operation, value } = {}) {
let transformations = { ...this._transformations };

if (operation) {
Expand All @@ -149,17 +149,17 @@ export class EditorImageFader extends Block {

// do not use getBoundingClientRect because scale transform affects it
let width = this.offsetWidth;
return this.proxyUrl(viewerImageSrc(url, width, transformations));
return await this.proxyUrl(viewerImageSrc(url, width, transformations));
}

/**
* @private
* @param {String} operation
* @param {Number} value
* @returns {Keypoint}
* @returns {Promise<Keypoint>}
*/
_constructKeypoint(operation, value) {
let src = this._imageSrc({ operation, value });
async _constructKeypoint(operation, value) {
let src = await this._imageSrc({ operation, value });
return {
src,
image: null,
Expand Down Expand Up @@ -187,14 +187,14 @@ export class EditorImageFader extends Block {
* @param {String | null} filter
* @param {Number} value
*/
_addKeypoint(operation, filter, value) {
async _addKeypoint(operation, filter, value) {
let shouldSkip = () =>
!this._isSame(operation, filter) || this._value !== value || !!this._keypoints.find((kp) => kp.value === value);

if (shouldSkip()) {
return;
}
let keypoint = this._constructKeypoint(operation, value);
let keypoint = await this._constructKeypoint(operation, value);
let image = new Image();
image.src = keypoint.src;
let stop = this._handleImageLoading(keypoint.src);
Expand Down Expand Up @@ -308,10 +308,10 @@ export class EditorImageFader extends Block {
}

/** @param {import('./types.js').Transformations} transformations */
setTransformations(transformations) {
async setTransformations(transformations) {
this._transformations = transformations;
if (this._previewImage) {
let src = this._imageSrc();
let src = await this._imageSrc();
let stop = this._handleImageLoading(src);
this._previewImage.src = src;
this._previewImage.addEventListener('load', stop, { once: true });
Expand All @@ -335,11 +335,11 @@ export class EditorImageFader extends Block {
* @param {Number} options.value
* @param {String} [options.filter]
*/
preload({ url, filter, operation, value }) {
async preload({ url, filter, operation, value }) {
this._cancelBatchPreload && this._cancelBatchPreload();

let keypoints = keypointsRange(operation, value);
let srcList = keypoints.map((kp) => this._imageSrc({ url, filter, operation, value: kp }));
let srcList = await Promise.all(keypoints.map((kp) => this._imageSrc({ url, filter, operation, value: kp })));
let { cancel } = batchPreloadImages(srcList);

this._cancelBatchPreload = cancel;
Expand Down Expand Up @@ -400,7 +400,7 @@ export class EditorImageFader extends Block {
* @param {String} [options.filter]
* @param {Boolean} [options.fromViewer]
*/
activate({ url, operation, value, filter, fromViewer }) {
async activate({ url, operation, value, filter, fromViewer }) {
this._isActive = true;
this._hidden = false;
this._url = url;
Expand All @@ -411,12 +411,14 @@ export class EditorImageFader extends Block {

let isOriginal = typeof value !== 'number' && !filter;
if (isOriginal) {
let src = this._imageSrc({ operation, value });
let src = await this._imageSrc({ operation, value });
this._setOriginalSrc(src);
this._container && this._container.remove();
return;
}
this._keypoints = keypointsRange(operation, value).map((keyValue) => this._constructKeypoint(operation, keyValue));
this._keypoints = await Promise.all(
keypointsRange(operation, value).map((keyValue) => this._constructKeypoint(operation, keyValue)),
);

this._update(operation, value);
this._initNodes();
Expand Down
8 changes: 4 additions & 4 deletions blocks/CloudImageEditor/src/EditorToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class EditorToolbar extends Block {
visible: 'uc-tab-toggles--visible',
},
'on.cancel': () => {
this._cancelPreload && this._cancelPreload();
this._cancelPreload?.();
this.$['*on.cancel']();
},
'on.apply': () => {
Expand Down Expand Up @@ -271,11 +271,11 @@ export class EditorToolbar extends Block {
}

/** @private */
_preloadEditedImage() {
async _preloadEditedImage() {
if (this.$['*imgContainerEl'] && this.$['*originalUrl']) {
let width = this.$['*imgContainerEl'].offsetWidth;
let src = this.proxyUrl(viewerImageSrc(this.$['*originalUrl'], width, this.$['*editorTransformations']));
this._cancelPreload && this._cancelPreload();
let src = await this.proxyUrl(viewerImageSrc(this.$['*originalUrl'], width, this.$['*editorTransformations']));
this._cancelPreload?.();
let { cancel } = batchPreloadImages([src]);
this._cancelPreload = () => {
cancel();
Expand Down
2 changes: 1 addition & 1 deletion blocks/FileItem/FileItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export class FileItem extends UploaderBlock {

if (entry.getValue('fileInfo') && entry.getValue('isImage')) {
let size = this.cfg.thumbSize;
let thumbUrl = this.proxyUrl(
let thumbUrl = await this.proxyUrl(
createCdnUrl(
createOriginalUrl(this.cfg.cdnCname, this._entry.getValue('uuid')),
createCdnUrlModifiers(entry.getValue('cdnUrlModifiers'), `scale_crop/${size}x${size}/center`),
Expand Down
2 changes: 1 addition & 1 deletion types/exported.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export type LocaleDefinitionOverride = Record<string, LocaleDefinition>;
export type SecureDeliveryProxyUrlResolver = (
previewUrl: string,
urlParts: { uuid: string; cdnUrlModifiers: string; fileName: string },
) => string;
) => Promise<string> | string;
export type SecureUploadsSignatureAndExpire = { secureSignature: string; secureExpire: string };
export type SecureUploadsSignatureResolver = () => Promise<SecureUploadsSignatureAndExpire | null>;
export type IconHrefResolver = (iconName: string) => string;
Expand Down

0 comments on commit 60f06be

Please sign in to comment.