@abtnode/core 1.17.7-beta-20251223-090654-55d57623 → 1.17.7-beta-20251225-073259-cb6ecf68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/blocklet/manager/disk.js +1 -1
- package/lib/blocklet/storage/backup/spaces.js +1 -1
- package/lib/event/index.js +14 -5
- package/lib/states/blocklet-extras.js +46 -14
- package/lib/states/blocklet.js +25 -2
- package/lib/util/blocklet.js +34 -8
- package/lib/util/docker/create-docker-image.js +10 -2
- package/lib/util/docker/parse-docker-options-from-pm2.js +14 -0
- package/lib/util/docker/parse-tmpfs.js +92 -0
- package/lib/validators/backup.js +15 -1
- package/package.json +24 -24
|
@@ -290,7 +290,7 @@ const getWalletAppNotification = async (blocklet, tempBlockletInfo) => {
|
|
|
290
290
|
data: {
|
|
291
291
|
url: blockletInfo.appUrl,
|
|
292
292
|
appDID: blocklet.appPid,
|
|
293
|
-
logo: appLogo,
|
|
293
|
+
logo: joinURL(blockletInfo.appUrl, appLogo),
|
|
294
294
|
title: blockletInfo.name,
|
|
295
295
|
desc: blockletInfo.description,
|
|
296
296
|
},
|
|
@@ -373,7 +373,7 @@ class SpacesBackup extends BaseBackup {
|
|
|
373
373
|
appDid: this.blocklet.appDid,
|
|
374
374
|
appName: getAppName(this.blocklet),
|
|
375
375
|
appDescription: getAppDescription(this.blocklet),
|
|
376
|
-
userDid: this.input.userDid,
|
|
376
|
+
userDid: isValid(this.input.userDid) ? this.input.userDid : process.env.ABT_NODE_DID,
|
|
377
377
|
referrer: this.input.referrer,
|
|
378
378
|
serverDid,
|
|
379
379
|
signerDid: this.securityContext.signer.address,
|
package/lib/event/index.js
CHANGED
|
@@ -533,11 +533,20 @@ module.exports = ({
|
|
|
533
533
|
if ([BlockletEvents.started, BlockletEvents.stopped].includes(eventName)) {
|
|
534
534
|
try {
|
|
535
535
|
const nodeInfo = await node.getNodeInfo();
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
536
|
+
updateDidDocument({ did: blocklet.appPid, nodeInfo, teamManager, states })
|
|
537
|
+
.then(() => {
|
|
538
|
+
logger.info('updated blocklet DID document after state change', {
|
|
539
|
+
did: blocklet.meta.did,
|
|
540
|
+
event: eventName,
|
|
541
|
+
});
|
|
542
|
+
})
|
|
543
|
+
.catch((error) => {
|
|
544
|
+
logger.error('update blocklet DID document failed after state change', {
|
|
545
|
+
did: blocklet.meta.did,
|
|
546
|
+
event: eventName,
|
|
547
|
+
error,
|
|
548
|
+
});
|
|
549
|
+
});
|
|
541
550
|
} catch (error) {
|
|
542
551
|
logger.error('update blocklet DID document failed after state change', {
|
|
543
552
|
did: blocklet.meta.did,
|
|
@@ -150,21 +150,37 @@ class BlockletExtrasState extends BaseState {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
return
|
|
155
|
-
|
|
156
|
-
dids = [].concat(dids);
|
|
157
|
-
const [rootDid, ...childDids] = dids;
|
|
158
|
-
const { dek } = this.config;
|
|
159
|
-
const { name, afterGet = noop('data') } = extra;
|
|
153
|
+
getExtraByDid(did, { selection = {} } = {}) {
|
|
154
|
+
return this.findOne({ did }, selection);
|
|
155
|
+
}
|
|
160
156
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
157
|
+
/**
|
|
158
|
+
* 从文档中提取指定字段的数据
|
|
159
|
+
* @private
|
|
160
|
+
*/
|
|
161
|
+
_extractFromDoc(doc, dids, extra) {
|
|
162
|
+
// eslint-disable-next-line no-param-reassign
|
|
163
|
+
dids = [].concat(dids);
|
|
164
|
+
const [rootDid, ...childDids] = dids;
|
|
165
|
+
const { dek } = this.config;
|
|
166
|
+
const { name, afterGet = noop('data') } = extra;
|
|
167
|
+
|
|
168
|
+
// 遍历 children 查找目标组件
|
|
169
|
+
let item = doc;
|
|
170
|
+
const didsToTraverse = [...childDids];
|
|
171
|
+
while (item && didsToTraverse.length) {
|
|
172
|
+
const did = didsToTraverse.shift();
|
|
173
|
+
item = (item.children || []).find((x) => x.did === did);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return afterGet({ data: item ? item[name] : null, did: rootDid, dek });
|
|
177
|
+
}
|
|
166
178
|
|
|
167
|
-
|
|
179
|
+
generateGetFn(extra) {
|
|
180
|
+
return async (dids, path, defaultValue) => {
|
|
181
|
+
const [rootDid] = [].concat(dids);
|
|
182
|
+
const doc = await this.findOne({ did: rootDid });
|
|
183
|
+
const data = this._extractFromDoc(doc, dids, extra);
|
|
168
184
|
if (!path) {
|
|
169
185
|
return data;
|
|
170
186
|
}
|
|
@@ -172,6 +188,22 @@ class BlockletExtrasState extends BaseState {
|
|
|
172
188
|
};
|
|
173
189
|
}
|
|
174
190
|
|
|
191
|
+
/**
|
|
192
|
+
* 从已查询的文档中获取指定类型的数据,避免重复查询数据库
|
|
193
|
+
* @param {object} doc - 已查询的 blockletExtras 文档
|
|
194
|
+
* @param {string|string[]} dids - did 数组,第一个是 rootDid,后续是 childDids
|
|
195
|
+
* @param {string} type - 数据类型,如 'configs' 或 'settings'
|
|
196
|
+
* @returns {any} 对应类型的数据
|
|
197
|
+
*/
|
|
198
|
+
getFromDoc({ doc = null, dids = [], name = '' }) {
|
|
199
|
+
if (!doc || !name || !dids.length) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const extra = this.extras.find((x) => x.name === name);
|
|
204
|
+
return this._extractFromDoc(doc, dids, extra);
|
|
205
|
+
}
|
|
206
|
+
|
|
175
207
|
// CAUTION: setConfig() 方法中非必要 **不要** 传入 [{ name: xxx }], 要传入 [{ key: xxx }]. 前者会导致某些配置被自动删掉
|
|
176
208
|
generateSetFn(extra) {
|
|
177
209
|
return async (dids, data) => {
|
|
@@ -271,7 +303,7 @@ class BlockletExtrasState extends BaseState {
|
|
|
271
303
|
}
|
|
272
304
|
|
|
273
305
|
getMeta(did) {
|
|
274
|
-
return
|
|
306
|
+
return this.getExtraByDid(did, { selection: { did: 1, controller: 1, meta: 1 } });
|
|
275
307
|
}
|
|
276
308
|
|
|
277
309
|
async isLauncherSessionConsumed(sessionId) {
|
package/lib/states/blocklet.js
CHANGED
|
@@ -254,6 +254,8 @@ class BlockletState extends BaseState {
|
|
|
254
254
|
this.defaultPort = config.blockletPort || 5555;
|
|
255
255
|
// @didMap: { [did: string]: metaDid: string }
|
|
256
256
|
this.didMap = new Map();
|
|
257
|
+
// @didToIdMap: { [did: string]: id: string } - 缓存 did 到 doc.id 的映射,避免重复 $or 查询
|
|
258
|
+
this.didToIdMap = new Map();
|
|
257
259
|
this.statusLocks = new Map();
|
|
258
260
|
|
|
259
261
|
// BlockletChildState instance passed from outside
|
|
@@ -481,11 +483,23 @@ class BlockletState extends BaseState {
|
|
|
481
483
|
return null;
|
|
482
484
|
}
|
|
483
485
|
|
|
484
|
-
|
|
486
|
+
// 优先使用缓存的 id 直接查询,避免 $or 查询
|
|
487
|
+
const cachedId = process.env.NODE_ENV === 'test' ? null : this.didToIdMap.get(did);
|
|
488
|
+
const doc = await this.findOne(cachedId ? { id: cachedId } : { $or: getConditions(did) });
|
|
485
489
|
if (!doc) {
|
|
490
|
+
// 如果缓存的 id 查不到,可能是缓存失效,清除并重试
|
|
491
|
+
if (cachedId) {
|
|
492
|
+
this.didToIdMap.delete(did);
|
|
493
|
+
return this.getBlocklet(did, { decryptSk });
|
|
494
|
+
}
|
|
486
495
|
return null;
|
|
487
496
|
}
|
|
488
497
|
|
|
498
|
+
// 缓存 did -> id 映射
|
|
499
|
+
if (!cachedId && process.env.NODE_ENV !== 'test') {
|
|
500
|
+
this.didToIdMap.set(did, doc.id);
|
|
501
|
+
}
|
|
502
|
+
|
|
489
503
|
// Load children from BlockletChild table
|
|
490
504
|
const children = await this.loadChildren(doc.id);
|
|
491
505
|
doc.children = children;
|
|
@@ -560,6 +574,10 @@ class BlockletState extends BaseState {
|
|
|
560
574
|
|
|
561
575
|
this.didMap.delete(doc.meta?.did);
|
|
562
576
|
this.didMap.delete(doc.appDid);
|
|
577
|
+
this.didToIdMap.delete(did);
|
|
578
|
+
this.didToIdMap.delete(doc.meta?.did);
|
|
579
|
+
this.didToIdMap.delete(doc.appDid);
|
|
580
|
+
this.didToIdMap.delete(doc.appPid);
|
|
563
581
|
this.statusLocks.delete(doc.meta?.did);
|
|
564
582
|
this.statusLocks.delete(doc.appDid);
|
|
565
583
|
|
|
@@ -1016,7 +1034,9 @@ class BlockletState extends BaseState {
|
|
|
1016
1034
|
await lock.acquire(lockName);
|
|
1017
1035
|
try {
|
|
1018
1036
|
const doc = await this.getBlocklet(did);
|
|
1019
|
-
|
|
1037
|
+
if (!doc) {
|
|
1038
|
+
throw new Error(`Blocklet not found: ${did}`);
|
|
1039
|
+
}
|
|
1020
1040
|
if (doc.meta?.group === BlockletGroup.gateway && !doc.children?.length) {
|
|
1021
1041
|
const updateData = { status, operator };
|
|
1022
1042
|
const res = await this.updateBlocklet(did, updateData);
|
|
@@ -1090,6 +1110,9 @@ class BlockletState extends BaseState {
|
|
|
1090
1110
|
// Recalculate status after children are loaded with updated status
|
|
1091
1111
|
res.status = getBlockletStatus(res);
|
|
1092
1112
|
return res;
|
|
1113
|
+
} catch (error) {
|
|
1114
|
+
logger.error('setBlockletStatus failed', { did, status, componentDids, operator, error });
|
|
1115
|
+
throw error;
|
|
1093
1116
|
} finally {
|
|
1094
1117
|
await lock.releaseLock(lockName);
|
|
1095
1118
|
}
|
package/lib/util/blocklet.js
CHANGED
|
@@ -14,6 +14,7 @@ const mergeWith = require('lodash/mergeWith');
|
|
|
14
14
|
const toLower = require('lodash/toLower');
|
|
15
15
|
const isEmpty = require('lodash/isEmpty');
|
|
16
16
|
const omit = require('lodash/omit');
|
|
17
|
+
const pick = require('lodash/pick');
|
|
17
18
|
const streamToPromise = require('stream-to-promise');
|
|
18
19
|
const { Throttle } = require('stream-throttle');
|
|
19
20
|
const { slugify } = require('transliteration');
|
|
@@ -1972,9 +1973,19 @@ const _getBlocklet = async ({
|
|
|
1972
1973
|
return null;
|
|
1973
1974
|
}
|
|
1974
1975
|
|
|
1976
|
+
// 优化:并行查询独立数据(只查询一次 extraDoc,然后从内存中同步提取)
|
|
1977
|
+
const [extraDoc, nodeInfo, site] = await Promise.all([
|
|
1978
|
+
states.blockletExtras.getExtraByDid(blocklet.meta.did),
|
|
1979
|
+
states.node.read(),
|
|
1980
|
+
states.site.findOneByBlocklet(blocklet.meta.did),
|
|
1981
|
+
]);
|
|
1982
|
+
|
|
1983
|
+
// 从 extraDoc 中同步提取 settings(不需要再次查询数据库)
|
|
1984
|
+
const extrasMeta = extraDoc ? pick(extraDoc, ['did', 'meta', 'controller']) : null;
|
|
1985
|
+
const settings = states.blockletExtras.getFromDoc({ doc: extraDoc, dids: [blocklet.meta.did], name: 'settings' });
|
|
1986
|
+
|
|
1975
1987
|
// app settings
|
|
1976
1988
|
// FIXME: @zhanghan 在 server 开发模式下,使用 `node /workspace/arcblock/blocklet-server/core/cli/tools/dev.js` 运行的 blocklet,blocklet.meta.did 和 blocklet.appPid 是不一致的
|
|
1977
|
-
const settings = await states.blockletExtras.getSettings(blocklet.meta.did);
|
|
1978
1989
|
blocklet.trustedPassports = get(settings, 'trustedPassports') || [];
|
|
1979
1990
|
blocklet.trustedFactories = (get(settings, 'trustedFactories') || []).map((x) => {
|
|
1980
1991
|
if (!x.passport.ttlPolicy) {
|
|
@@ -1989,7 +2000,6 @@ const _getBlocklet = async ({
|
|
|
1989
2000
|
blocklet.enablePassportIssuance = get(settings, 'enablePassportIssuance', true);
|
|
1990
2001
|
blocklet.settings = settings || {};
|
|
1991
2002
|
|
|
1992
|
-
const extrasMeta = await states.blockletExtras.getMeta(blocklet.meta.did);
|
|
1993
2003
|
if (extrasMeta) {
|
|
1994
2004
|
blocklet.controller = extrasMeta.controller;
|
|
1995
2005
|
}
|
|
@@ -2005,8 +2015,6 @@ const _getBlocklet = async ({
|
|
|
2005
2015
|
);
|
|
2006
2016
|
}
|
|
2007
2017
|
|
|
2008
|
-
const nodeInfo = await states.node.read();
|
|
2009
|
-
|
|
2010
2018
|
(nodeInfo?.blockletRegistryList || []).forEach((store) => {
|
|
2011
2019
|
if (!blocklet.settings.storeList.find((x) => x.url === store.url)) {
|
|
2012
2020
|
blocklet.settings.storeList.push({
|
|
@@ -2016,11 +2024,29 @@ const _getBlocklet = async ({
|
|
|
2016
2024
|
}
|
|
2017
2025
|
});
|
|
2018
2026
|
|
|
2019
|
-
blocklet.site =
|
|
2027
|
+
blocklet.site = site;
|
|
2020
2028
|
blocklet.enableDocker = nodeInfo.enableDocker;
|
|
2021
2029
|
blocklet.enableDockerNetwork = nodeInfo.enableDockerNetwork;
|
|
2022
2030
|
|
|
2023
|
-
|
|
2031
|
+
// 第一次 forEachBlockletSync:收集所有组件的 dids
|
|
2032
|
+
const componentConfigRequests = [];
|
|
2033
|
+
forEachBlockletSync(blocklet, (component, { ancestors }) => {
|
|
2034
|
+
const dids = [...ancestors.map((x) => x.meta.did), component.meta.did];
|
|
2035
|
+
componentConfigRequests.push({
|
|
2036
|
+
componentDid: component.meta.did,
|
|
2037
|
+
dids,
|
|
2038
|
+
});
|
|
2039
|
+
});
|
|
2040
|
+
|
|
2041
|
+
// 基于缓存文档,为每个组件提取 configs(同步操作,不需要再次查询数据库)
|
|
2042
|
+
const configsMap = new Map();
|
|
2043
|
+
componentConfigRequests.forEach(({ componentDid, dids }) => {
|
|
2044
|
+
const configs = states.blockletExtras.getFromDoc({ doc: extraDoc, dids, name: 'configs' });
|
|
2045
|
+
configsMap.set(componentDid, configs);
|
|
2046
|
+
});
|
|
2047
|
+
|
|
2048
|
+
// 第二次 forEachBlockletSync:填充组件
|
|
2049
|
+
forEachBlockletSync(blocklet, (component, { id, level, ancestors }) => {
|
|
2024
2050
|
// component env
|
|
2025
2051
|
try {
|
|
2026
2052
|
// Validate component has required meta fields for getComponentDirs
|
|
@@ -2056,8 +2082,8 @@ const _getBlocklet = async ({
|
|
|
2056
2082
|
throw error;
|
|
2057
2083
|
}
|
|
2058
2084
|
|
|
2059
|
-
// component config
|
|
2060
|
-
const configs =
|
|
2085
|
+
// component config - 从预取的 configsMap 中获取
|
|
2086
|
+
const configs = configsMap.get(component.meta.did) || [];
|
|
2061
2087
|
const rootBlocklet = ancestors.length > 0 ? ancestors[0] : blocklet;
|
|
2062
2088
|
fillBlockletConfigs(component, configs, { rootBlocklet, nodeInfo, dataDirs });
|
|
2063
2089
|
});
|
|
@@ -74,10 +74,17 @@ async function buildImage({ image, dockerfile }) {
|
|
|
74
74
|
const building = {};
|
|
75
75
|
|
|
76
76
|
async function createDockerImage(data) {
|
|
77
|
+
const metaDockerInfo = data?.meta?.docker || {};
|
|
78
|
+
const keys = Object.keys(metaDockerInfo);
|
|
79
|
+
for (const key of keys) {
|
|
80
|
+
if (metaDockerInfo[key] === '') {
|
|
81
|
+
delete metaDockerInfo[key];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
77
84
|
const customInfo = getBlockletCustomDockerfile(data);
|
|
78
85
|
if (building[customInfo.image]) {
|
|
79
86
|
await building[customInfo.image];
|
|
80
|
-
return customInfo;
|
|
87
|
+
return Object.assign(customInfo, metaDockerInfo);
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
if (
|
|
@@ -94,7 +101,8 @@ async function createDockerImage(data) {
|
|
|
94
101
|
building[customInfo.image] = buildImage(customInfo);
|
|
95
102
|
await building[customInfo.image];
|
|
96
103
|
}
|
|
97
|
-
|
|
104
|
+
|
|
105
|
+
return Object.assign(customInfo, metaDockerInfo);
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
module.exports = {
|
|
@@ -22,6 +22,7 @@ const checkNeedRunDocker = require('./check-need-run-docker');
|
|
|
22
22
|
const replaceEnvValue = require('./replace-env-value');
|
|
23
23
|
const parseDockerCpVolume = require('./parse-docker-cp-volume');
|
|
24
24
|
const generateClusterNodeScript = require('./generate-cluster-node-script');
|
|
25
|
+
const { parseTmpfs } = require('./parse-tmpfs');
|
|
25
26
|
|
|
26
27
|
const getSystemResources = (() => {
|
|
27
28
|
let cachedResources = null;
|
|
@@ -86,6 +87,9 @@ async function parseDockerOptionsFromPm2({
|
|
|
86
87
|
dockerInfo.command = nextOptions.env.DOCKER_CMD;
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
const { tmpfs } = dockerInfo;
|
|
91
|
+
delete dockerInfo.tmpfs;
|
|
92
|
+
|
|
89
93
|
try {
|
|
90
94
|
dockerCmdValidator(dockerInfo.image);
|
|
91
95
|
} catch (error) {
|
|
@@ -102,6 +106,7 @@ async function parseDockerOptionsFromPm2({
|
|
|
102
106
|
const defaultCpus = '2';
|
|
103
107
|
const defaultMemory = '1.5g';
|
|
104
108
|
const defaultDiskSize = '0g';
|
|
109
|
+
const defaultTmpfsSize = '4g';
|
|
105
110
|
|
|
106
111
|
const cpus = isServerless
|
|
107
112
|
? process.env.ABT_NODE_DOCKER_CPUS
|
|
@@ -115,6 +120,12 @@ async function parseDockerOptionsFromPm2({
|
|
|
115
120
|
? process.env.ABT_NODE_DOCKER_DISK_SIZE
|
|
116
121
|
: options.env.DOCKER_DISK_SIZE || process.env.ABT_NODE_DOCKER_DISK_SIZE;
|
|
117
122
|
|
|
123
|
+
const tmpfsSize = isServerless
|
|
124
|
+
? process.env.ABT_NODE_DOCKER_TMPFS_SIZE
|
|
125
|
+
: options.env.DOCKER_TMPFS_SIZE || process.env.ABT_NODE_DOCKER_TMPFS_SIZE;
|
|
126
|
+
|
|
127
|
+
const tmpfsOption = parseTmpfs(tmpfs, tmpfsSize || defaultTmpfsSize);
|
|
128
|
+
|
|
118
129
|
// Ensure environment variables are properly set within the Docker container
|
|
119
130
|
const envDefaults = {
|
|
120
131
|
BLOCKLET_DOCKER_CPUS: cpus || defaultCpus,
|
|
@@ -138,6 +149,7 @@ async function parseDockerOptionsFromPm2({
|
|
|
138
149
|
dockerEnv.BLOCKLET_DOCKER_CPUS = `${Math.min(Number(dockerEnv.BLOCKLET_DOCKER_CPUS), maxCPUs)}`;
|
|
139
150
|
dockerEnv.BLOCKLET_DOCKER_MEMORY = `${Math.min(Number(dockerEnv.BLOCKLET_DOCKER_MEMORY.replace('g', '')), maxMemory)}g`;
|
|
140
151
|
dockerEnv.BLOCKLET_DOCKER_DISK_SIZE = `${Math.min(Number(dockerEnv.BLOCKLET_DOCKER_DISK_SIZE.replace('g', '')), 20)}g`;
|
|
152
|
+
dockerEnv.BLOCKLET_DOCKER_TMPFS_SIZE = tmpfsOption.size;
|
|
141
153
|
|
|
142
154
|
const { baseDir } = dockerInfo;
|
|
143
155
|
const serverDir = process.env.ABT_NODE_DATA_DIR;
|
|
@@ -152,6 +164,7 @@ async function parseDockerOptionsFromPm2({
|
|
|
152
164
|
dockerEnv.BLOCKLET_DATA_DIR = replaceDir(nextOptions.env.BLOCKLET_DATA_DIR);
|
|
153
165
|
dockerEnv.BLOCKLET_LOG_DIR = path.join(baseDir, 'logs');
|
|
154
166
|
dockerEnv.BLOCKLET_CACHE_DIR = path.join(baseDir, 'cache');
|
|
167
|
+
dockerEnv.BLOCKLET_TMPFS_DIR = tmpfsOption.fullDir;
|
|
155
168
|
dockerEnv.BLOCKLET_APP_SHARE_DIR = replaceDir(nextOptions.env.BLOCKLET_APP_SHARE_DIR);
|
|
156
169
|
dockerEnv.BLOCKLET_SHARE_DIR = replaceDir(nextOptions.env.BLOCKLET_SHARE_DIR);
|
|
157
170
|
dockerEnv.BLOCKLET_HOST = getLocalIPAddress();
|
|
@@ -361,6 +374,7 @@ async function parseDockerOptionsFromPm2({
|
|
|
361
374
|
--memory-swap="${dockerEnv.BLOCKLET_DOCKER_MEMORY}" \
|
|
362
375
|
--oom-kill-disable=false \
|
|
363
376
|
--env-file ${dockerEnvFile} \
|
|
377
|
+
${tmpfsOption.tmpfs} \
|
|
364
378
|
${dockerInfo.network} \
|
|
365
379
|
${dockerInfo.runParamString || ''} \
|
|
366
380
|
${dockerInfo.image} ${dockerInfo.command || ''} \
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const { join } = require('path');
|
|
2
|
+
|
|
3
|
+
const DEFAULT_MAX_TMPFS_SIZE = '4g';
|
|
4
|
+
|
|
5
|
+
function parseSize(sizeStr) {
|
|
6
|
+
if (typeof sizeStr === 'string') {
|
|
7
|
+
if (sizeStr.endsWith('m')) {
|
|
8
|
+
return Number(sizeStr.replace('m', ''));
|
|
9
|
+
}
|
|
10
|
+
if (sizeStr.endsWith('g')) {
|
|
11
|
+
return Number(sizeStr.replace('g', '')) * 1024;
|
|
12
|
+
}
|
|
13
|
+
// Try to parse as number (assume GB if no unit)
|
|
14
|
+
return Number(sizeStr) * 1024;
|
|
15
|
+
}
|
|
16
|
+
return Number(sizeStr) * 1024;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function parseTmpfs(tmpfs, maxTmpfsSize = DEFAULT_MAX_TMPFS_SIZE, prefixDir = '/') {
|
|
20
|
+
if (!tmpfs) {
|
|
21
|
+
return {
|
|
22
|
+
tmpfs: '',
|
|
23
|
+
size: '0m',
|
|
24
|
+
fullDir: '',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const [fsPath, size] = tmpfs.split(':');
|
|
28
|
+
if (!fsPath || !size) {
|
|
29
|
+
return {
|
|
30
|
+
tmpfs: '',
|
|
31
|
+
size: '0m',
|
|
32
|
+
fullDir: '',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const fullDir = join(prefixDir, fsPath);
|
|
37
|
+
const defaultMaxSizeMb = parseSize(DEFAULT_MAX_TMPFS_SIZE);
|
|
38
|
+
|
|
39
|
+
// Parse maxTmpfsSize to a number in MB
|
|
40
|
+
let maxSizeMb = parseSize(maxTmpfsSize);
|
|
41
|
+
// Fallback to default if parsing failed (NaN), invalid value, or zero/empty
|
|
42
|
+
if (Number.isNaN(maxSizeMb) || maxSizeMb <= 0) {
|
|
43
|
+
maxSizeMb = defaultMaxSizeMb;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Extract size value from various formats:
|
|
47
|
+
// - "1g" or "512m" (simple size)
|
|
48
|
+
// - "1g,rw" or "rw,1g" (size with options)
|
|
49
|
+
// - "size=512m" or "size=1g" (Docker style with size= prefix)
|
|
50
|
+
// - "size=512m,rw" (Docker style with options)
|
|
51
|
+
const sizeParts = size.split(',');
|
|
52
|
+
let sizeValue = '';
|
|
53
|
+
for (const part of sizeParts) {
|
|
54
|
+
let trimmed = part.trim();
|
|
55
|
+
// Handle "size=512m" format - extract the value after "size="
|
|
56
|
+
if (trimmed.startsWith('size=')) {
|
|
57
|
+
trimmed = trimmed.slice(5); // Remove "size=" prefix
|
|
58
|
+
}
|
|
59
|
+
if (trimmed.endsWith('g') || trimmed.endsWith('m')) {
|
|
60
|
+
sizeValue = trimmed;
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let sizeMb = 0;
|
|
66
|
+
if (sizeValue.endsWith('g')) {
|
|
67
|
+
const parsed = Number(sizeValue.replace('g', ''));
|
|
68
|
+
sizeMb = Number.isNaN(parsed) ? 0 : parsed * 1024;
|
|
69
|
+
sizeMb = Math.min(sizeMb, maxSizeMb);
|
|
70
|
+
}
|
|
71
|
+
if (sizeValue.endsWith('m')) {
|
|
72
|
+
const parsed = Number(sizeValue.replace('m', ''));
|
|
73
|
+
sizeMb = Number.isNaN(parsed) ? 0 : parsed;
|
|
74
|
+
sizeMb = Math.min(sizeMb, maxSizeMb);
|
|
75
|
+
}
|
|
76
|
+
// Ensure sizeMb is valid
|
|
77
|
+
if (Number.isNaN(sizeMb) || sizeMb < 0) {
|
|
78
|
+
sizeMb = 0;
|
|
79
|
+
}
|
|
80
|
+
sizeMb = Math.min(sizeMb, maxSizeMb);
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
tmpfs: `--tmpfs ${fullDir}:size=${sizeMb}m`,
|
|
84
|
+
size: `${sizeMb}m`,
|
|
85
|
+
fullDir,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
parseTmpfs,
|
|
91
|
+
DEFAULT_MAX_TMPFS_SIZE,
|
|
92
|
+
};
|
package/lib/validators/backup.js
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
const { Joi } = require('@arcblock/validator');
|
|
2
|
+
const { isValid } = require('@arcblock/did');
|
|
2
3
|
|
|
3
4
|
const validateBackupStart = Joi.object({
|
|
4
5
|
appPid: Joi.DID().required(),
|
|
5
|
-
userDid: Joi.
|
|
6
|
+
userDid: Joi.string()
|
|
7
|
+
.custom((value, helper) => {
|
|
8
|
+
if (isValid(value)) {
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// value 不一定是一个 did,可能是用户名或者 @blocklet/cli,此时都会 fallback 到 ABT_NODE_DID
|
|
13
|
+
if (isValid(process.env.ABT_NODE_DID)) {
|
|
14
|
+
return process.env.ABT_NODE_DID;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return helper.message('Expect "userDid" to be valid did');
|
|
18
|
+
})
|
|
19
|
+
.required(),
|
|
6
20
|
strategy: Joi.number().valid(0, 1).optional().default(0),
|
|
7
21
|
|
|
8
22
|
sourceUrl: Joi.string().required(),
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.17.7-beta-
|
|
6
|
+
"version": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -17,21 +17,21 @@
|
|
|
17
17
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
18
18
|
"license": "Apache-2.0",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@abtnode/analytics": "1.17.7-beta-
|
|
21
|
-
"@abtnode/auth": "1.17.7-beta-
|
|
22
|
-
"@abtnode/certificate-manager": "1.17.7-beta-
|
|
23
|
-
"@abtnode/constant": "1.17.7-beta-
|
|
24
|
-
"@abtnode/cron": "1.17.7-beta-
|
|
25
|
-
"@abtnode/db-cache": "1.17.7-beta-
|
|
26
|
-
"@abtnode/docker-utils": "1.17.7-beta-
|
|
27
|
-
"@abtnode/logger": "1.17.7-beta-
|
|
28
|
-
"@abtnode/models": "1.17.7-beta-
|
|
29
|
-
"@abtnode/queue": "1.17.7-beta-
|
|
30
|
-
"@abtnode/rbac": "1.17.7-beta-
|
|
31
|
-
"@abtnode/router-provider": "1.17.7-beta-
|
|
32
|
-
"@abtnode/static-server": "1.17.7-beta-
|
|
33
|
-
"@abtnode/timemachine": "1.17.7-beta-
|
|
34
|
-
"@abtnode/util": "1.17.7-beta-
|
|
20
|
+
"@abtnode/analytics": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
21
|
+
"@abtnode/auth": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
22
|
+
"@abtnode/certificate-manager": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
23
|
+
"@abtnode/constant": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
24
|
+
"@abtnode/cron": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
25
|
+
"@abtnode/db-cache": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
26
|
+
"@abtnode/docker-utils": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
27
|
+
"@abtnode/logger": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
28
|
+
"@abtnode/models": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
29
|
+
"@abtnode/queue": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
30
|
+
"@abtnode/rbac": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
31
|
+
"@abtnode/router-provider": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
32
|
+
"@abtnode/static-server": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
33
|
+
"@abtnode/timemachine": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
34
|
+
"@abtnode/util": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
35
35
|
"@aigne/aigne-hub": "^0.10.15",
|
|
36
36
|
"@arcblock/did": "^1.27.15",
|
|
37
37
|
"@arcblock/did-connect-js": "^1.27.15",
|
|
@@ -43,15 +43,15 @@
|
|
|
43
43
|
"@arcblock/pm2-events": "^0.0.5",
|
|
44
44
|
"@arcblock/validator": "^1.27.15",
|
|
45
45
|
"@arcblock/vc": "^1.27.15",
|
|
46
|
-
"@blocklet/constant": "1.17.7-beta-
|
|
46
|
+
"@blocklet/constant": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
47
47
|
"@blocklet/did-space-js": "^1.2.11",
|
|
48
|
-
"@blocklet/env": "1.17.7-beta-
|
|
48
|
+
"@blocklet/env": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
49
49
|
"@blocklet/error": "^0.3.5",
|
|
50
|
-
"@blocklet/meta": "1.17.7-beta-
|
|
51
|
-
"@blocklet/resolver": "1.17.7-beta-
|
|
52
|
-
"@blocklet/sdk": "1.17.7-beta-
|
|
53
|
-
"@blocklet/server-js": "1.17.7-beta-
|
|
54
|
-
"@blocklet/store": "1.17.7-beta-
|
|
50
|
+
"@blocklet/meta": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
51
|
+
"@blocklet/resolver": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
52
|
+
"@blocklet/sdk": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
53
|
+
"@blocklet/server-js": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
54
|
+
"@blocklet/store": "1.17.7-beta-20251225-073259-cb6ecf68",
|
|
55
55
|
"@blocklet/theme": "^3.2.19",
|
|
56
56
|
"@fidm/x509": "^1.2.1",
|
|
57
57
|
"@ocap/mcrypto": "^1.27.15",
|
|
@@ -116,5 +116,5 @@
|
|
|
116
116
|
"express": "^4.18.2",
|
|
117
117
|
"unzipper": "^0.10.11"
|
|
118
118
|
},
|
|
119
|
-
"gitHead": "
|
|
119
|
+
"gitHead": "16715912460ed534e1e023d7e968714e3990051d"
|
|
120
120
|
}
|