// Copyright Epic Games, Inc. All Rights Reserved. "use strict"; import { Fetcher } from "../util/fetcher.js" //////////////////////////////////////////////////////////////////////////////// export class Message { static None = 0; // static Init = 1; // project_id, oplog static Map = 2; // start, end, page_size, stride static MapPage = 3; // page static MapDone = 4; // static create(msg, ...args) { return [msg, ...args]; } } //////////////////////////////////////////////////////////////////////////////// async function map_id_to_key(project_id, oplog, start, end, page_size, stride) { if (start >= end) return postMessage(Message.create(Message.MapDone)); const uri = "/prj/" + project_id + "/oplog/" + oplog + "/entries"; const fetch_page = async function(index) { const cbo = new Fetcher() .resource(uri) .param("start", index) .param("count", page_size) .param("fieldfilter", "packagedata,bulkdata,key") .cbo() const entry_count = Math.min(page_size, -(index - end)); return [await cbo, entry_count]; }; var fetch = fetch_page(start); while (fetch !== undefined) { performance.mark("fetch"); const [cbo, entry_count] = await fetch; start += stride; fetch = (start < end) ? fetch_page(start) : undefined; var entries = (await cbo).as_object().find("entries"); if (entries == undefined) break; entries = entries.as_array(); if (entries.num() == 0) break; performance.mark("build"); var count = 0; var result = new Array(entry_count); for (var entry of entries) { if (!entry.is_object()) continue entry = entry.as_object(); var key = undefined; var pkg_data = undefined; var bulk_data = undefined; for (const field of entry) { if (field.is_named("key")) key = field; else if (field.is_named("packagedata")) pkg_data = field; else if (field.is_named("bulkdata")) bulk_data = field; } if (key == undefined) continue; var id = 0n; var size = 0n; var raw_size = 0n; if (pkg_data) { for (const item of pkg_data.as_array()) { var found = 0, pkg_id = undefined; for (const field of item.as_object()) { if (!id && field.is_named("id")) pkg_id = field.as_value(); else if (field.is_named("size")) size += field.as_value(); else if (field.is_named("rawsize")) raw_size += field.as_value(); else continue; if (found++ >= 3) break; } if (pkg_id === undefined) continue; pkg_id = pkg_id.subarray(0, 8); for (var i = 7; i >= 0; --i) { id <<= 8n; id |= BigInt(pkg_id[i]); } } } if (bulk_data) { for (const item of bulk_data.as_array()) { var found = 0; for (const field of item.as_object()) { if (field.is_named("size")) size += field.as_value(); else if (field.is_named("rawsize")) raw_size += field.as_value(); else continue; if (found++ >= 2) break; } } } result[count] = [id, key.as_value(), size, raw_size]; count++; } if (count == 0) continue; if (count != result.length) result = result.slice(0, count); performance.mark("sort"); result.sort(function(l, r) { return Number(l[0] - r[0]); }); const msg = Message.create(Message.MapPage, result); postMessage(msg); } postMessage(Message.create(Message.MapDone)); } //////////////////////////////////////////////////////////////////////////////// function worker_scope() { var project_id; var oplog; return (evt) => { const [msg_id, ...params] = evt.data; switch (msg_id) { case Message.Init: [project_id, oplog] = params; break; case Message.Map: var [start, end, page_size, stride] = params; map_id_to_key(project_id, oplog, start, end, page_size, stride); break; } } } //////////////////////////////////////////////////////////////////////////////// if (typeof DedicatedWorkerGlobalScope != "undefined" && self instanceof DedicatedWorkerGlobalScope) { onmessage = worker_scope(); }