Migrate remaining legacy operator workflows
This commit is contained in:
@@ -16,6 +16,16 @@
|
||||
const rowVersionPattern = /^[a-f0-9]{64}$/;
|
||||
const unsafeTextPattern = /[\p{Cc}\p{Cf}\p{Cs}\p{Zl}\p{Zp}\uFFFD]/u;
|
||||
const audiences = Object.freeze(["INDIVIDUAL", "FOREIGN", "INSTITUTION"]);
|
||||
const statusCodes = new Set([
|
||||
"READY",
|
||||
"IMPORT_INTERRUPTED",
|
||||
"IMPORTED_STATE_INVALID",
|
||||
"INITIALIZATION_FAILED",
|
||||
"UNSAFE_CONFIGURATION"
|
||||
]);
|
||||
const trustedNetSellReadResponses = new WeakSet();
|
||||
const trustedViReadResponses = new WeakSet();
|
||||
const trustedPlaylistEntries = new WeakMap();
|
||||
const audienceLabels = Object.freeze({
|
||||
INDIVIDUAL: "개인",
|
||||
FOREIGN: "외국인",
|
||||
@@ -25,6 +35,8 @@
|
||||
const bridgeContract = Object.freeze({
|
||||
statusRequestType: "request-manual-operator-data-status",
|
||||
statusResultType: "manual-operator-data-status",
|
||||
legacyImportType: "import-legacy-manual-operator-data",
|
||||
legacyImportResultType: "legacy-manual-operator-import-result",
|
||||
netSellReadType: "request-manual-net-sell-data",
|
||||
netSellDataType: "manual-net-sell-data",
|
||||
netSellSaveType: "save-manual-net-sell-data",
|
||||
@@ -107,6 +119,10 @@
|
||||
return request(bridgeContract.statusRequestType, requestId);
|
||||
}
|
||||
|
||||
function createLegacyImportRequest(requestId) {
|
||||
return request(bridgeContract.legacyImportType, requestId);
|
||||
}
|
||||
|
||||
function createNetSellReadRequest(requestId, audience) {
|
||||
const normalized = normalizeAudience(audience);
|
||||
if (!normalized) throw new RangeError("The manual net-sell audience is invalid.");
|
||||
@@ -139,15 +155,31 @@
|
||||
}
|
||||
|
||||
function normalizeStatusResponse(value, expectedRequestId) {
|
||||
if (!hasExactKeys(value, ["requestId", "available", "writeQuarantined", "message"]) ||
|
||||
if (!hasExactKeys(value, ["requestId", "available", "code", "writeQuarantined", "message"]) ||
|
||||
!isRequestId(value.requestId) ||
|
||||
typeof value.available !== "boolean" ||
|
||||
!statusCodes.has(value.code) ||
|
||||
value.available !== (value.code === "READY") ||
|
||||
typeof value.writeQuarantined !== "boolean" ||
|
||||
!(value.message === null || isSafeText(value.message, 512, false)) ||
|
||||
(expectedRequestId !== undefined && value.requestId !== expectedRequestId)) return null;
|
||||
return Object.freeze({ ...value });
|
||||
}
|
||||
|
||||
function normalizeLegacyImportResponse(value, expectedRequestId) {
|
||||
if (!hasExactKeys(value, [
|
||||
"requestId", "markerVersion", "sourceSha256", "importedAt",
|
||||
"netSellRowCount", "viItemCount"
|
||||
]) || !isRequestId(value.requestId) || value.markerVersion !== 1 ||
|
||||
!isRowVersion(value.sourceSha256) ||
|
||||
typeof value.importedAt !== "string" || !Number.isFinite(Date.parse(value.importedAt)) ||
|
||||
value.netSellRowCount !== 15 ||
|
||||
!Number.isInteger(value.viItemCount) || value.viItemCount < 0 ||
|
||||
value.viItemCount > MAXIMUM_VI_ITEMS ||
|
||||
(expectedRequestId !== undefined && value.requestId !== expectedRequestId)) return null;
|
||||
return Object.freeze({ ...value });
|
||||
}
|
||||
|
||||
function normalizeNetSellDataResponse(value, expectedRequest) {
|
||||
if (!hasExactKeys(value, ["requestId", "audience", "rows"]) ||
|
||||
!isRequestId(value.requestId) ||
|
||||
@@ -155,7 +187,10 @@
|
||||
(expectedRequest &&
|
||||
(value.requestId !== expectedRequest.requestId || value.audience !== expectedRequest.audience))) return null;
|
||||
const rows = normalizeNetSellRows(value.rows);
|
||||
return rows && Object.freeze({ requestId: value.requestId, audience: value.audience, rows });
|
||||
if (!rows) return null;
|
||||
const response = Object.freeze({ requestId: value.requestId, audience: value.audience, rows });
|
||||
trustedNetSellReadResponses.add(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
function normalizeNetSellSaveResponse(value, expectedRequest) {
|
||||
@@ -178,13 +213,15 @@
|
||||
(expectedRequestId !== undefined && value.requestId !== expectedRequestId)) return null;
|
||||
const items = normalizeViItems(value.items);
|
||||
if (!items || items.length !== value.itemCount) return null;
|
||||
return Object.freeze({
|
||||
const response = Object.freeze({
|
||||
requestId: value.requestId,
|
||||
itemCount: value.itemCount,
|
||||
pageCount: value.pageCount,
|
||||
items,
|
||||
version: value.version
|
||||
});
|
||||
trustedViReadResponses.add(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
function normalizeViSaveResponse(value, expectedRequestId) {
|
||||
@@ -213,14 +250,23 @@
|
||||
}
|
||||
|
||||
function requireOptions(options) {
|
||||
if (!hasExactKeys(options, ["id", "fadeDuration"]) || !isRequestId(options.id) ||
|
||||
!Number.isInteger(options.fadeDuration) || options.fadeDuration < 0 || options.fadeDuration > 60) {
|
||||
const keys = options && typeof options === "object" ? Object.keys(options).sort() : [];
|
||||
const exact = keys.length === 2 && keys[0] === "fadeDuration" && keys[1] === "id";
|
||||
const exactWithEnabled = keys.length === 3 && keys[0] === "enabled" &&
|
||||
keys[1] === "fadeDuration" && keys[2] === "id";
|
||||
if ((!exact && !exactWithEnabled) || !isRequestId(options.id) ||
|
||||
!Number.isInteger(options.fadeDuration) || options.fadeDuration < 0 || options.fadeDuration > 60 ||
|
||||
(exactWithEnabled && typeof options.enabled !== "boolean")) {
|
||||
throw new TypeError("Safe manual-list playlist options are required.");
|
||||
}
|
||||
return options;
|
||||
return Object.freeze({
|
||||
id: options.id,
|
||||
fadeDuration: options.fadeDuration,
|
||||
enabled: exactWithEnabled ? options.enabled : true
|
||||
});
|
||||
}
|
||||
|
||||
function createNetSellPlaylistEntry(audience, options) {
|
||||
function createNetSellEntryObject(audience, options) {
|
||||
const normalizedAudience = normalizeAudience(audience);
|
||||
const normalizedOptions = requireOptions(options);
|
||||
if (!normalizedAudience) throw new RangeError("The manual net-sell audience is invalid.");
|
||||
@@ -242,7 +288,7 @@
|
||||
category: "market",
|
||||
market: "index",
|
||||
selection,
|
||||
enabled: true,
|
||||
enabled: normalizedOptions.enabled,
|
||||
fadeDuration: normalizedOptions.fadeDuration,
|
||||
graphicType: selection.graphicType,
|
||||
subtype: selection.subtype,
|
||||
@@ -255,7 +301,7 @@
|
||||
};
|
||||
}
|
||||
|
||||
function createViPlaylistEntry(items, rowVersion, options) {
|
||||
function createViEntryObject(items, rowVersion, options) {
|
||||
const normalizedItems = normalizeViItems(items, false);
|
||||
const normalizedOptions = requireOptions(options);
|
||||
if (!normalizedItems || !isRowVersion(rowVersion)) {
|
||||
@@ -282,7 +328,7 @@
|
||||
pageSize: VI_PAGE_SIZE,
|
||||
pageCount,
|
||||
selection,
|
||||
enabled: true,
|
||||
enabled: normalizedOptions.enabled,
|
||||
fadeDuration: normalizedOptions.fadeDuration,
|
||||
graphicType: selection.graphicType,
|
||||
subtype: selection.subtype,
|
||||
@@ -302,6 +348,43 @@
|
||||
};
|
||||
}
|
||||
|
||||
function createNetSellPlaylistEntry(audience, options, freshRead) {
|
||||
const entry = createNetSellEntryObject(audience, options);
|
||||
if (trustedNetSellReadResponses.has(freshRead) &&
|
||||
freshRead.audience === entry.operator.audience && freshRead.rows.length === 5) {
|
||||
trustedPlaylistEntries.set(entry, freshRead);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
function createViPlaylistEntry(items, rowVersion, options, freshRead) {
|
||||
const entry = createViEntryObject(items, rowVersion, options);
|
||||
if (trustedViReadResponses.has(freshRead) && freshRead.version === entry.operator.rowVersion &&
|
||||
freshRead.itemCount === entry.itemCount && freshRead.pageCount === entry.pageCount &&
|
||||
freshRead.items.length === entry.operator.items.length &&
|
||||
freshRead.items.every((item, index) => item.code === entry.operator.items[index].code &&
|
||||
item.name === entry.operator.items[index].name)) {
|
||||
trustedPlaylistEntries.set(entry, freshRead);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
function isPlaylistEntryPlayable(value) {
|
||||
if (!value) return false;
|
||||
const freshRead = trustedPlaylistEntries.get(value);
|
||||
const restored = restorePlaylistEntry(value);
|
||||
if (!freshRead || !restored) return false;
|
||||
if (restored.operator.kind === "net-sell") {
|
||||
return trustedNetSellReadResponses.has(freshRead) && freshRead.rows.length === 5 &&
|
||||
freshRead.audience === restored.operator.audience;
|
||||
}
|
||||
return trustedViReadResponses.has(freshRead) && freshRead.version === restored.operator.rowVersion &&
|
||||
freshRead.itemCount === restored.itemCount && freshRead.pageCount === restored.pageCount &&
|
||||
freshRead.items.length === restored.operator.items.length &&
|
||||
freshRead.items.every((item, index) => item.code === restored.operator.items[index].code &&
|
||||
item.name === restored.operator.items[index].name);
|
||||
}
|
||||
|
||||
function sameSelection(left, right) {
|
||||
const keys = ["groupCode", "subject", "graphicType", "subtype", "dataCode"];
|
||||
return hasExactKeys(left, keys) && hasExactKeys(right, keys) && keys
|
||||
@@ -334,10 +417,10 @@
|
||||
}
|
||||
let recreated;
|
||||
try {
|
||||
const options = { id: value.id, fadeDuration: value.fadeDuration };
|
||||
const options = { id: value.id, fadeDuration: value.fadeDuration, enabled: value.enabled };
|
||||
recreated = operator.kind === "net-sell"
|
||||
? createNetSellPlaylistEntry(operator.audience, options)
|
||||
: createViPlaylistEntry(operator.items, operator.rowVersion, options);
|
||||
? createNetSellEntryObject(operator.audience, options)
|
||||
: createViEntryObject(operator.items, operator.rowVersion, options);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -355,7 +438,7 @@
|
||||
operator.pagePreview.pageSize !== recreated.operator.pagePreview.pageSize ||
|
||||
operator.pagePreview.pageCount !== recreated.operator.pagePreview.pageCount ||
|
||||
operator.pagePreview.maximumPageCount !== recreated.operator.pagePreview.maximumPageCount)) return null;
|
||||
return { ...recreated, enabled: value.enabled };
|
||||
return recreated;
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -372,11 +455,13 @@
|
||||
normalizeViItem,
|
||||
normalizeViItems,
|
||||
createStatusRequest,
|
||||
createLegacyImportRequest,
|
||||
createNetSellReadRequest,
|
||||
createNetSellSaveRequest,
|
||||
createViReadRequest,
|
||||
createViSaveRequest,
|
||||
normalizeStatusResponse,
|
||||
normalizeLegacyImportResponse,
|
||||
normalizeNetSellDataResponse,
|
||||
normalizeNetSellSaveResponse,
|
||||
normalizeViDataResponse,
|
||||
@@ -384,6 +469,7 @@
|
||||
normalizeError,
|
||||
createNetSellPlaylistEntry,
|
||||
createViPlaylistEntry,
|
||||
isPlaylistEntryPlayable,
|
||||
restorePlaylistEntry,
|
||||
refreshPlaylistEntry: restorePlaylistEntry
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user