@snap/camera-kit
Version:
Camera Kit Web
139 lines • 7.42 kB
JavaScript
import { __awaiter } from "tslib";
import { Injectable } from "@snap/ts-inject";
import { dispatchRequestCompleted, dispatchRequestErrored, dispatchRequestStarted, requestStateEventTargetFactory, } from "../../handlers/requestStateEmittingHandler";
import { LensAssetManifestItem_RequestTiming, LensAssetManifestItem_Type, } from "../../generated-proto/pb_schema/camera_kit/v3/lens";
import { assertUnreachable } from "../../common/assertions";
import { getLogger } from "../../logger/logger";
import { metricsEventTargetFactory } from "../../metrics/metricsEventTarget";
import { TypedCustomEvent } from "../../events/TypedCustomEvent";
import { lensCoreFactory } from "../../lens-core-module/loader/lensCoreFactory";
import { deviceDependentAssetLoaderFactory } from "./deviceDependentAssetLoader";
import { remoteMediaAssetLoaderFactory } from "./remoteMediaAssetLoaderFactory";
import { staticAssetLoaderFactory } from "./staticAssetLoader";
const logger = getLogger("LensAssetRepository");
function getCacheKey(asset) {
return `${asset.assetId}_${asset.assetType.value}`;
}
export function mapManfiestItemToAssetType(lensCore, type) {
switch (type) {
case LensAssetManifestItem_Type.ASSET:
return lensCore.AssetType.Static;
case LensAssetManifestItem_Type.DEVICE_DEPENDENT_ASSET_UNSET:
case LensAssetManifestItem_Type.UNRECOGNIZED:
return lensCore.AssetType.DeviceDependent;
default:
return assertUnreachable(type);
}
}
export class LensAssetRepository {
constructor(lensCore, assetLoaders, metrics, requestStateEventTarget) {
this.lensCore = lensCore;
this.assetLoaders = assetLoaders;
this.metrics = metrics;
this.requestStateEventTarget = requestStateEventTarget;
this.cachedAssetKeys = new Set();
}
cacheAssets(assetManifest, lens, assetTimings = [LensAssetManifestItem_RequestTiming.REQUIRED], lowPriority = false) {
return __awaiter(this, void 0, void 0, function* () {
const assetTimingsToPreload = new Set([
LensAssetManifestItem_RequestTiming.PRELOAD_UNSET,
...assetTimings,
]);
const assetDescriptors = assetManifest
.filter((asset) => {
return assetTimingsToPreload.has(asset.requestTiming);
})
.map(({ id, type }) => ({
assetId: id,
assetType: mapManfiestItemToAssetType(this.lensCore, type),
}));
if (assetDescriptors.length) {
return this.cacheAssetsByDescriptor(assetDescriptors, lens, assetManifest, lowPriority);
}
});
}
loadAsset(request) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
const { assetDescriptor: { assetId, assetType }, lens, } = request;
const [assetTypeName, assetLoader] = (_a = this.assetLoaders.get(assetType)) !== null && _a !== void 0 ? _a : [];
const safeAssetTypeName = assetTypeName !== null && assetTypeName !== void 0 ? assetTypeName : "unknown";
const dimensions = {
requestType: "asset",
assetId: assetId,
assetType: safeAssetTypeName,
lensId: (_b = lens === null || lens === void 0 ? void 0 : lens.id) !== null && _b !== void 0 ? _b : "unknown",
};
const { requestId } = dispatchRequestStarted(this.requestStateEventTarget, { dimensions });
try {
if (!assetLoader) {
throw new Error(`Cannot get asset ${assetId}. Asset type ${safeAssetTypeName} is not supported.`);
}
const assetResponse = yield assetLoader(request);
const assetBuffer = "data" in assetResponse ? assetResponse.data : assetResponse;
const assetChecksum = "checksum" in assetResponse ? assetResponse.checksum : undefined;
if (assetBuffer.byteLength === 0) {
throw new Error(`Got empty response for asset ${assetId} from ${safeAssetTypeName} loader.`);
}
dispatchRequestCompleted(this.requestStateEventTarget, {
requestId,
dimensions,
status: 200,
sizeByte: assetBuffer.byteLength,
});
this.lensCore.provideRemoteAssetsResponse({
assetId,
assetBuffer,
assetType,
assetChecksum,
onFailure: (lensCoreError) => {
if (/validation failed/.test(lensCoreError.message)) {
this.metrics.dispatchEvent(new TypedCustomEvent("assetValidationFailed", {
name: "assetValidationFailed",
assetId,
}));
}
logger.warn(`Failed to provide lens asset ${assetId}.`, lensCoreError);
},
});
}
catch (error) {
const wrappedError = new Error(`Failed to load lens asset ${assetId}.`, { cause: error });
dispatchRequestErrored(this.requestStateEventTarget, { requestId, dimensions, error: wrappedError });
throw wrappedError;
}
});
}
cacheAssetsByDescriptor(assetDescriptors, lens, assetManifest, lowPriority) {
return __awaiter(this, void 0, void 0, function* () {
yield Promise.all(assetDescriptors
.filter((assetDescriptors) => !this.cachedAssetKeys.has(getCacheKey(assetDescriptors)))
.map((assetDescriptor) => __awaiter(this, void 0, void 0, function* () {
var _a;
try {
yield this.loadAsset({ assetDescriptor, lens, assetManifest, lowPriority });
this.cachedAssetKeys.add(getCacheKey(assetDescriptor));
}
catch (error) {
const { assetId, assetType } = assetDescriptor;
const [assetTypeName] = (_a = this.assetLoaders.get(assetType)) !== null && _a !== void 0 ? _a : [];
logger.warn(`Failed to cache asset ${assetId} of type ${assetTypeName !== null && assetTypeName !== void 0 ? assetTypeName : assetType.value}.`, error);
}
})));
});
}
}
export const lensAssetRepositoryFactory = Injectable("lensAssetRepository", [
lensCoreFactory.token,
deviceDependentAssetLoaderFactory.token,
remoteMediaAssetLoaderFactory.token,
staticAssetLoaderFactory.token,
metricsEventTargetFactory.token,
requestStateEventTargetFactory.token,
], (lensCore, deviceDependentAssetLoader, remoteMediaAssetLoader, staticAssetLoader, metrics, requestStateEventTarget) => new LensAssetRepository(lensCore, new Map([
[lensCore.AssetType.DeviceDependent, ["DeviceDependent", deviceDependentAssetLoader]],
[lensCore.AssetType.RemoteMediaByUrl, ["RemoteMediaByUrl", remoteMediaAssetLoader]],
[lensCore.AssetType.URL, ["URL", remoteMediaAssetLoader]],
[lensCore.AssetType.Static, ["Static", staticAssetLoader]],
]), metrics, requestStateEventTarget));
//# sourceMappingURL=LensAssetRepository.js.map