cnpmcore
Version:
Private NPM Registry for Enterprise
341 lines • 36.1 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import fs from 'node:fs/promises';
import { AccessLevel, Inject, SingletonProto } from 'egg';
import { sortBy } from 'lodash-es';
import binaries from "../../../config/binaries.js";
import { AbstractService } from "../../common/AbstractService.js";
import { AbstractBinary } from "../../common/adapter/binary/AbstractBinary.js";
import { platforms } from "../../common/adapter/binary/PuppeteerBinary.js";
import { BinaryType } from "../../common/enum/Binary.js";
import { TaskState, TaskType } from "../../common/enum/Task.js";
import { isTimeoutError } from "../../common/ErrorUtil.js";
import { downloadToTempfile } from "../../common/FileUtil.js";
import { Binary } from "../entity/Binary.js";
import { Task } from "../entity/Task.js";
function isoNow() {
return new Date().toISOString();
}
let BinarySyncerService = class BinarySyncerService extends AbstractService {
// canvas/v2.6.1/canvas-v2.6.1-node-v57-linux-glibc-x64.tar.gz
// -> node-canvas-prebuilt/v2.6.1/node-canvas-prebuilt-v2.6.1-node-v57-linux-glibc-x64.tar.gz
// canvas 历史版本的 targetName 可能是 category 需要兼容
async findBinary(targetName, parent, name) {
return await this.binaryRepository.findBinary(targetName, parent, name);
}
async listDirBinaries(binary, options) {
return await this.binaryRepository.listBinaries(binary.category, `${binary.parent}${binary.name}`, options);
}
async listRootBinaries(binaryName) {
// 通常 binaryName 和 category 是一样的,但是有些特殊的 binaryName 会有多个 category,比如 canvas
// 所以查询 canvas 的时候,需要将 binaryName 和 category 的数据都查出来
const { category } = binaries[binaryName];
const reqs = [this.binaryRepository.listBinaries(binaryName, '/')];
if (category && category !== binaryName) {
reqs.push(this.binaryRepository.listBinaries(category, '/'));
}
const [rootBinary, categoryBinary] = await Promise.all(reqs);
const versions = new Set(rootBinary.map((b) => b.name));
if (categoryBinary) {
for (const b of categoryBinary) {
const version = b.name;
// 只将没有的版本添加进去
if (!versions.has(version)) {
rootBinary.push(b);
}
}
}
return rootBinary;
}
async downloadBinary(binary) {
return await this.nfsAdapter.getDownloadUrlOrStream(binary.storePath);
}
async createTask(binaryName, lastData) {
// chromium-browser-snapshots 产物极大,完整遍历 s3 bucket 耗时会太长
// 必须从上次同步的 revision 之后开始遍历
// 如果需要补偿数据,可以
if (binaryName === 'chromium-browser-snapshots') {
lastData = lastData || {};
for (const platform of platforms) {
if (lastData[platform])
continue;
const binaryDir = await this.binaryRepository.findLatestBinaryDir('chromium-browser-snapshots', `/${platform}/`);
if (binaryDir) {
lastData[platform] = binaryDir.name.slice(0, -1);
}
}
const latestBinary = await this.binaryRepository.findLatestBinary('chromium-browser-snapshots');
if (latestBinary && !lastData.lastSyncTime) {
lastData.lastSyncTime = latestBinary.date;
}
}
try {
return await this.taskService.createTask(Task.createSyncBinary(binaryName, lastData), false);
}
catch (e) {
this.logger.error('[BinarySyncerService.createTask] binaryName: %s, error: %s', binaryName, e);
}
}
async findTask(taskId) {
return (await this.taskService.findTask(taskId));
}
async findTaskLog(task) {
return await this.taskService.findTaskLog(task);
}
async findExecuteTask() {
return (await this.taskService.findExecuteTask(TaskType.SyncBinary));
}
async executeTask(task) {
const binaryName = task.targetName;
const binaryAdapter = await this.getBinaryAdapter(binaryName);
const logUrl = `${this.config.cnpmcore.registry}/-/binary/${binaryName}/syncs/${task.taskId}/log`;
let logs = [];
logs.push(`[${isoNow()}] 🚧🚧🚧🚧🚧 Start sync binary "${binaryName}" 🚧🚧🚧🚧🚧`);
if (!binaryAdapter) {
task.error = 'unknow binaryName';
logs.push(`[${isoNow()}] ❌ Synced "${binaryName}" fail, ${task.error}, log: ${logUrl}`);
logs.push(`[${isoNow()}] ❌❌❌❌❌ "${binaryName}" ❌❌❌❌❌`);
this.logger.error('[BinarySyncerService.executeTask:fail] taskId: %s, targetName: %s, %s', task.taskId, task.targetName, task.error);
await this.taskService.finishTask(task, TaskState.Fail, logs.join('\n'));
return;
}
await this.taskService.appendTaskLog(task, logs.join('\n'));
logs = [];
this.logger.info('[BinarySyncerService.executeTask:start] taskId: %s, targetName: %s, log: %s', task.taskId, task.targetName, logUrl);
try {
const [hasDownloadError] = await this.syncDir(binaryAdapter, task, '/');
logs.push(`[${isoNow()}] 🟢 log: ${logUrl}`);
logs.push(`[${isoNow()}] 🟢🟢🟢🟢🟢 "${binaryName}" 🟢🟢🟢🟢🟢`);
await this.taskService.finishTask(task, TaskState.Success, logs.join('\n'));
// 确保没有下载异常才算 success
await binaryAdapter.finishFetch(!hasDownloadError, binaryName);
this.logger.info('[BinarySyncerService.executeTask:success] taskId: %s, targetName: %s, log: %s, hasDownloadError: %s', task.taskId, task.targetName, logUrl, hasDownloadError);
}
catch (err) {
task.error = `${err.name}: ${err.message}`;
logs.push(`[${isoNow()}] ❌ Synced "${binaryName}" fail, ${task.error}, log: ${logUrl}`);
logs.push(`[${isoNow()}] ❌❌❌❌❌ "${binaryName}" ❌❌❌❌❌`);
if (isTimeoutError(err)) {
this.logger.warn('[BinarySyncerService.executeTask:fail] taskId: %s, targetName: %s, %s', task.taskId, task.targetName, task.error);
this.logger.warn(err);
}
else {
this.logger.error('[BinarySyncerService.executeTask:fail] taskId: %s, targetName: %s, %s', task.taskId, task.targetName, task.error);
this.logger.error(err);
}
await binaryAdapter.finishFetch(false, binaryName);
await this.taskService.finishTask(task, TaskState.Fail, logs.join('\n'));
}
}
async syncDir(binaryAdapter, task, dir, parentIndex = '', latestVersionParent = '/') {
const binaryName = task.targetName;
const result = await binaryAdapter.fetch(dir, binaryName, task.data);
let hasDownloadError = false;
let hasItems = false;
if (result && result.items.length > 0) {
hasItems = true;
let logs = [];
const startTime = Date.now();
const { newItems, latestVersionDir } = await this.diff(binaryName, dir, result.items, latestVersionParent);
const useTime = Date.now() - startTime;
logs.push(`[${isoNow()}][${dir}] 🚧 Syncing diff: ${result.items.length} => ${newItems.length}, Binary class: ${binaryAdapter.constructor.name}, use: ${useTime}ms`);
// re-check latest version
for (const [index, { item, reason }] of newItems.entries()) {
if (item.isDir) {
logs.push(`[${isoNow()}][${dir}] 🚧 [${parentIndex}${index}] Start sync dir ${JSON.stringify(item)}, reason: ${reason}`);
await this.taskService.appendTaskLog(task, logs.join('\n'));
logs = [];
const [hasError, hasSubItems] = await this.syncDir(binaryAdapter, task, `${dir}${item.name}`, `${parentIndex}${index}.`, latestVersionDir);
if (hasError) {
hasDownloadError = true;
}
else if (hasSubItems) {
// if any file download error, let dir sync again next time
// if empty dir, don't save it
await this.saveBinaryItem(item);
}
}
else {
// download to nfs
logs.push(`[${isoNow()}][${dir}] 🚧 [${parentIndex}${index}] Downloading ${JSON.stringify(item)}, reason: ${reason}`);
// skip exists binary file
const existsBinary = await this.binaryRepository.findBinary(item.category, item.parent, item.name);
if (existsBinary && existsBinary.date === item.date) {
logs.push(`[${isoNow()}][${dir}] 🟢 [${parentIndex}${index}] binary file exists, skip download, binaryId: ${existsBinary.binaryId}`);
this.logger.info('[BinarySyncerService.syncDir:skipDownload] binaryId: %s exists, storePath: %s', existsBinary.binaryId, existsBinary.storePath);
continue;
}
await this.taskService.appendTaskLog(task, logs.join('\n'));
logs = [];
let localFile = '';
try {
const { tmpfile, headers, timing } = await downloadToTempfile(this.httpClient, this.config.dataDir, item.sourceUrl, { ignoreDownloadStatuses: item.ignoreDownloadStatuses });
const log = `[${isoNow()}][${dir}] 🟢 [${parentIndex}${index}] HTTP content-length: ${headers['content-length']}, timing: ${JSON.stringify(timing)}, ${item.sourceUrl} => ${tmpfile}`;
logs.push(log);
this.logger.info('[BinarySyncerService.syncDir:downloadToTempfile] %s', log);
localFile = tmpfile;
const binary = await this.saveBinaryItem(item, tmpfile);
logs.push(`[${isoNow()}][${dir}] 🟢 [${parentIndex}${index}] Synced file success, binaryId: ${binary.binaryId}`);
await this.taskService.appendTaskLog(task, logs.join('\n'));
logs = [];
}
catch (err) {
if (err.name === 'DownloadNotFoundError') {
this.logger.info('Not found %s, skip it', item.sourceUrl);
logs.push(`[${isoNow()}][${dir}] 🧪️ [${parentIndex}${index}] Download ${item.sourceUrl} not found, skip it`);
}
else {
if (err.name === 'DownloadStatusInvalidError') {
this.logger.warn('Download binary %s %s', item.sourceUrl, err);
}
else {
this.logger.error('Download binary %s %s', item.sourceUrl, err);
}
hasDownloadError = true;
logs.push(`[${isoNow()}][${dir}] ❌ [${parentIndex}${index}] Download ${item.sourceUrl} error: ${err}`);
}
await this.taskService.appendTaskLog(task, logs.join('\n'));
logs = [];
}
finally {
if (localFile) {
await fs.rm(localFile, { force: true });
}
}
}
}
if (hasDownloadError) {
logs.push(`[${isoNow()}][${dir}] ❌ Synced dir fail`);
}
else {
logs.push(`[${isoNow()}][${dir}] 🟢 Synced dir success, hasItems: ${hasItems}`);
}
await this.taskService.appendTaskLog(task, logs.join('\n'));
}
return [hasDownloadError, hasItems];
}
// see https://github.com/cnpm/cnpmcore/issues/556
// 上游可能正在发布新版本、同步流程中断,导致同步的时候,文件列表不一致
// 如果的当前目录命中 latestVersionParent 父目录,那么就再校验一下当前目录
// 如果 existsItems 为空或者经过修改,那么就不需要 revalidate 了
async diff(binaryName, dir, fetchItems, latestVersionParent = '/') {
// Use optimized query that only fetches name and date columns
// This avoids Bone constructor overhead for each row
const existsItems = await this.binaryRepository.listBinaryNameAndDates(binaryName, dir);
const existsMap = new Map();
for (const item of existsItems) {
existsMap.set(item.name, item);
}
const diffItems = [];
let latestItem;
for (const item of fetchItems) {
const existsItem = existsMap.get(item.name);
if (!existsItem) {
diffItems.push({
item: this.createBinary(binaryName, dir, item),
reason: 'new item',
});
}
else if (existsItem.date !== item.date) {
// Date changed, create new Binary entity with updated info
diffItems.push({
item: this.createBinary(binaryName, dir, item, existsItem),
reason: `date diff, local: ${JSON.stringify(existsItem.date)}, remote: ${JSON.stringify(item.date)}`,
});
}
else if (dir.endsWith(latestVersionParent)) {
if (!latestItem) {
latestItem = sortBy(fetchItems, ['date']).pop();
}
const isLatestItem = latestItem?.name === item.name;
if (isLatestItem && item.isDir) {
// Revalidate latest version directory
diffItems.push({
item: this.createBinary(binaryName, dir, item, existsItem),
reason: `revalidate latest version, latest parent dir is ${latestVersionParent}, current dir is ${dir}, current name is ${item.name}`,
});
latestVersionParent = `${latestVersionParent}${item.name}`;
}
}
}
return {
newItems: diffItems,
latestVersionDir: latestVersionParent,
};
}
createBinary(binaryName, dir, fetchItem, existsItem) {
const bin = Binary.create({
category: binaryName,
parent: dir,
name: fetchItem.name,
isDir: fetchItem.isDir,
size: 0,
date: fetchItem.date,
sourceUrl: fetchItem.url,
ignoreDownloadStatuses: fetchItem.ignoreDownloadStatuses,
});
if (existsItem) {
bin.id = existsItem.id;
// keep binaryId not changed
bin.binaryId = existsItem.binaryId;
}
return bin;
}
async saveBinaryItem(binary, tmpfile) {
if (tmpfile) {
const stat = await fs.stat(tmpfile);
binary.size = stat.size;
await this.nfsAdapter.uploadFile(binary.storePath, tmpfile);
this.logger.info('[BinarySyncerService.saveBinaryItem:uploadFile] binaryId: %s, size: %d, %s => %s', binary.binaryId, stat.size, tmpfile, binary.storePath);
}
await this.binaryRepository.saveBinary(binary);
return binary;
}
async getBinaryAdapter(binaryName) {
const config = this.config.cnpmcore;
const binaryConfig = binaries[binaryName];
let binaryAdapter;
if (config.sourceRegistryIsCNpm) {
binaryAdapter = await this.eggObjectFactory.getEggObject(AbstractBinary, BinaryType.Api);
}
else {
binaryAdapter = await this.eggObjectFactory.getEggObject(AbstractBinary, binaryConfig.type);
}
await binaryAdapter.initFetch(binaryName);
return binaryAdapter;
}
};
__decorate([
Inject(),
__metadata("design:type", Function)
], BinarySyncerService.prototype, "binaryRepository", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], BinarySyncerService.prototype, "taskService", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], BinarySyncerService.prototype, "httpClient", void 0);
__decorate([
Inject(),
__metadata("design:type", Function)
], BinarySyncerService.prototype, "nfsAdapter", void 0);
__decorate([
Inject(),
__metadata("design:type", Object)
], BinarySyncerService.prototype, "eggObjectFactory", void 0);
BinarySyncerService = __decorate([
SingletonProto({
accessLevel: AccessLevel.PUBLIC,
})
], BinarySyncerService);
export { BinarySyncerService };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmluYXJ5U3luY2VyU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2FwcC9jb3JlL3NlcnZpY2UvQmluYXJ5U3luY2VyU2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSxPQUFPLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUVsQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxjQUFjLEVBQXFDLE1BQU0sS0FBSyxDQUFDO0FBQzdGLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFbkMsT0FBTyxRQUFnRCxNQUFNLDZCQUE2QixDQUFDO0FBQzNGLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNsRSxPQUFPLEVBQUUsY0FBYyxFQUFtQixNQUFNLCtDQUErQyxDQUFDO0FBQ2hHLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnREFBZ0QsQ0FBQztBQUUzRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDekQsT0FBTyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFOUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxJQUFJLEVBQXVCLE1BQU0sbUJBQW1CLENBQUM7QUFHOUQsU0FBUyxNQUFNO0lBQ2IsT0FBTyxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQ2xDLENBQUM7QUFLTSxJQUFNLG1CQUFtQixHQUF6QixNQUFNLG1CQUFvQixTQUFRLGVBQWU7SUFZdEQsOERBQThEO0lBQzlELDZGQUE2RjtJQUM3Riw0Q0FBNEM7SUFDckMsS0FBSyxDQUFD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