@abtnode/core 1.16.37 → 1.16.38-beta-20250108-235929-17742885
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 +22 -1
- package/lib/blocklet/migration-dist/migration.cjs +58 -39
- package/lib/blocklet/project/create-pack-release.js +30 -1
- package/lib/blocklet/project/index.js +7 -2
- package/lib/states/release.js +2 -0
- package/lib/util/blocklet.js +1 -0
- package/lib/util/docker/blocklet-custom-dockerfile.js +29 -2
- package/lib/util/docker/docker-exec-chown.js +19 -4
- package/lib/util/docker/parse-docker-options-from-pm2.js +77 -11
- package/lib/validators/project.js +33 -0
- package/package.json +22 -21
|
@@ -25,6 +25,8 @@ const { joinURL } = require('ufo');
|
|
|
25
25
|
const { sendToUser } = require('@blocklet/sdk/lib/util/send-notification');
|
|
26
26
|
const { getDidDomainForBlocklet } = require('@abtnode/util/lib/get-domain-for-blocklet');
|
|
27
27
|
const logger = require('@abtnode/logger')('@abtnode/core:blocklet:manager');
|
|
28
|
+
const promiseSpawn = require('@abtnode/util/lib/promise-spawn');
|
|
29
|
+
|
|
28
30
|
const {
|
|
29
31
|
BLOCKLET_INSTALL_TYPE,
|
|
30
32
|
APP_STRUCT_VERSION,
|
|
@@ -2646,6 +2648,17 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2646
2648
|
const { meta } = blocklet;
|
|
2647
2649
|
const { name, did, version } = meta;
|
|
2648
2650
|
|
|
2651
|
+
const nodeInfo = await states.node.read();
|
|
2652
|
+
if (checkDockerRunHistory(nodeInfo)) {
|
|
2653
|
+
const newBlocklet = await this.getBlocklet(did);
|
|
2654
|
+
// pull docker image
|
|
2655
|
+
await forEachComponentV2(newBlocklet, async (component) => {
|
|
2656
|
+
if (component?.meta?.docker?.image) {
|
|
2657
|
+
await promiseSpawn(`docker pull ${component?.meta?.docker?.image}`, {}, { timeout: 120 * 1000, retry: 0 });
|
|
2658
|
+
}
|
|
2659
|
+
});
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2649
2662
|
// check status
|
|
2650
2663
|
if (!skipCheckStatusBeforeDownload) {
|
|
2651
2664
|
try {
|
|
@@ -2707,7 +2720,6 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
2707
2720
|
}
|
|
2708
2721
|
} catch (err) {
|
|
2709
2722
|
if (err.message.includes('EACCES:')) {
|
|
2710
|
-
const nodeInfo = await states.node.read();
|
|
2711
2723
|
if (checkDockerRunHistory(nodeInfo)) {
|
|
2712
2724
|
try {
|
|
2713
2725
|
await dockerExecChown(`${did}-${blocklet.meta.name}-download`, [
|
|
@@ -4374,6 +4386,15 @@ class DiskBlockletManager extends BaseBlockletManager {
|
|
|
4374
4386
|
if (!isExternal) {
|
|
4375
4387
|
// 将 notification 信息保存在 server 中
|
|
4376
4388
|
const serverReceivers = await this.getReceiverDids(this.teamManager.nodeDid);
|
|
4389
|
+
// 需要处理 action, staging 环境中 path 要带有 admin/
|
|
4390
|
+
const { action } = notification;
|
|
4391
|
+
let actionPath = action;
|
|
4392
|
+
if (actionPath) {
|
|
4393
|
+
const nodeInfo = await states.node.read();
|
|
4394
|
+
actionPath =
|
|
4395
|
+
process.env.NODE_ENV === 'production' ? joinURL(nodeInfo.routing.adminPath, actionPath) : actionPath;
|
|
4396
|
+
}
|
|
4397
|
+
|
|
4377
4398
|
await states.notification.create({
|
|
4378
4399
|
...notification,
|
|
4379
4400
|
blockletUrl,
|
|
@@ -7964,6 +7964,7 @@ function useColors() {
|
|
|
7964
7964
|
|
|
7965
7965
|
// Is webkit? http://stackoverflow.com/a/16459606/376773
|
|
7966
7966
|
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
|
|
7967
|
+
// eslint-disable-next-line no-return-assign
|
|
7967
7968
|
return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
|
|
7968
7969
|
// Is firebug? http://stackoverflow.com/a/398120/376773
|
|
7969
7970
|
(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
|
|
@@ -8279,24 +8280,62 @@ function setup(env) {
|
|
|
8279
8280
|
createDebug.names = [];
|
|
8280
8281
|
createDebug.skips = [];
|
|
8281
8282
|
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8283
|
+
const split = (typeof namespaces === 'string' ? namespaces : '')
|
|
8284
|
+
.trim()
|
|
8285
|
+
.replace(' ', ',')
|
|
8286
|
+
.split(',')
|
|
8287
|
+
.filter(Boolean);
|
|
8285
8288
|
|
|
8286
|
-
for (
|
|
8287
|
-
if (
|
|
8288
|
-
|
|
8289
|
-
|
|
8289
|
+
for (const ns of split) {
|
|
8290
|
+
if (ns[0] === '-') {
|
|
8291
|
+
createDebug.skips.push(ns.slice(1));
|
|
8292
|
+
} else {
|
|
8293
|
+
createDebug.names.push(ns);
|
|
8290
8294
|
}
|
|
8295
|
+
}
|
|
8296
|
+
}
|
|
8291
8297
|
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8298
|
+
/**
|
|
8299
|
+
* Checks if the given string matches a namespace template, honoring
|
|
8300
|
+
* asterisks as wildcards.
|
|
8301
|
+
*
|
|
8302
|
+
* @param {String} search
|
|
8303
|
+
* @param {String} template
|
|
8304
|
+
* @return {Boolean}
|
|
8305
|
+
*/
|
|
8306
|
+
function matchesTemplate(search, template) {
|
|
8307
|
+
let searchIndex = 0;
|
|
8308
|
+
let templateIndex = 0;
|
|
8309
|
+
let starIndex = -1;
|
|
8310
|
+
let matchIndex = 0;
|
|
8311
|
+
|
|
8312
|
+
while (searchIndex < search.length) {
|
|
8313
|
+
if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === '*')) {
|
|
8314
|
+
// Match character or proceed with wildcard
|
|
8315
|
+
if (template[templateIndex] === '*') {
|
|
8316
|
+
starIndex = templateIndex;
|
|
8317
|
+
matchIndex = searchIndex;
|
|
8318
|
+
templateIndex++; // Skip the '*'
|
|
8319
|
+
} else {
|
|
8320
|
+
searchIndex++;
|
|
8321
|
+
templateIndex++;
|
|
8322
|
+
}
|
|
8323
|
+
} else if (starIndex !== -1) { // eslint-disable-line no-negated-condition
|
|
8324
|
+
// Backtrack to the last '*' and try to match more characters
|
|
8325
|
+
templateIndex = starIndex + 1;
|
|
8326
|
+
matchIndex++;
|
|
8327
|
+
searchIndex = matchIndex;
|
|
8296
8328
|
} else {
|
|
8297
|
-
|
|
8329
|
+
return false; // No match
|
|
8298
8330
|
}
|
|
8299
8331
|
}
|
|
8332
|
+
|
|
8333
|
+
// Handle trailing '*' in template
|
|
8334
|
+
while (templateIndex < template.length && template[templateIndex] === '*') {
|
|
8335
|
+
templateIndex++;
|
|
8336
|
+
}
|
|
8337
|
+
|
|
8338
|
+
return templateIndex === template.length;
|
|
8300
8339
|
}
|
|
8301
8340
|
|
|
8302
8341
|
/**
|
|
@@ -8307,8 +8346,8 @@ function setup(env) {
|
|
|
8307
8346
|
*/
|
|
8308
8347
|
function disable() {
|
|
8309
8348
|
const namespaces = [
|
|
8310
|
-
...createDebug.names
|
|
8311
|
-
...createDebug.skips.map(
|
|
8349
|
+
...createDebug.names,
|
|
8350
|
+
...createDebug.skips.map(namespace => '-' + namespace)
|
|
8312
8351
|
].join(',');
|
|
8313
8352
|
createDebug.enable('');
|
|
8314
8353
|
return namespaces;
|
|
@@ -8322,21 +8361,14 @@ function setup(env) {
|
|
|
8322
8361
|
* @api public
|
|
8323
8362
|
*/
|
|
8324
8363
|
function enabled(name) {
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
}
|
|
8328
|
-
|
|
8329
|
-
let i;
|
|
8330
|
-
let len;
|
|
8331
|
-
|
|
8332
|
-
for (i = 0, len = createDebug.skips.length; i < len; i++) {
|
|
8333
|
-
if (createDebug.skips[i].test(name)) {
|
|
8364
|
+
for (const skip of createDebug.skips) {
|
|
8365
|
+
if (matchesTemplate(name, skip)) {
|
|
8334
8366
|
return false;
|
|
8335
8367
|
}
|
|
8336
8368
|
}
|
|
8337
8369
|
|
|
8338
|
-
for (
|
|
8339
|
-
if (
|
|
8370
|
+
for (const ns of createDebug.names) {
|
|
8371
|
+
if (matchesTemplate(name, ns)) {
|
|
8340
8372
|
return true;
|
|
8341
8373
|
}
|
|
8342
8374
|
}
|
|
@@ -8344,19 +8376,6 @@ function setup(env) {
|
|
|
8344
8376
|
return false;
|
|
8345
8377
|
}
|
|
8346
8378
|
|
|
8347
|
-
/**
|
|
8348
|
-
* Convert regexp to namespace
|
|
8349
|
-
*
|
|
8350
|
-
* @param {RegExp} regxep
|
|
8351
|
-
* @return {String} namespace
|
|
8352
|
-
* @api private
|
|
8353
|
-
*/
|
|
8354
|
-
function toNamespace(regexp) {
|
|
8355
|
-
return regexp.toString()
|
|
8356
|
-
.substring(2, regexp.toString().length - 2)
|
|
8357
|
-
.replace(/\.\*\?$/, '*');
|
|
8358
|
-
}
|
|
8359
|
-
|
|
8360
8379
|
/**
|
|
8361
8380
|
* Coerce `val`.
|
|
8362
8381
|
*
|
|
@@ -38553,7 +38572,7 @@ module.exports = require("zlib");
|
|
|
38553
38572
|
/***/ ((module) => {
|
|
38554
38573
|
|
|
38555
38574
|
"use strict";
|
|
38556
|
-
module.exports = JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.
|
|
38575
|
+
module.exports = JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.37","description":"","main":"lib/index.js","files":["lib"],"scripts":{"lint":"eslint tests lib --ignore-pattern \'tests/assets/*\'","lint:fix":"eslint --fix tests lib","test":"node tools/jest.js","coverage":"npm run test -- --coverage"},"keywords":[],"author":"wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)","license":"Apache-2.0","dependencies":{"@abtnode/analytics":"1.16.37","@abtnode/auth":"1.16.37","@abtnode/certificate-manager":"1.16.37","@abtnode/constant":"1.16.37","@abtnode/cron":"1.16.37","@abtnode/logger":"1.16.37","@abtnode/models":"1.16.37","@abtnode/queue":"1.16.37","@abtnode/rbac":"1.16.37","@abtnode/router-provider":"1.16.37","@abtnode/static-server":"1.16.37","@abtnode/timemachine":"1.16.37","@abtnode/util":"1.16.37","@abtnode/docker-utils":"1.16.37","@arcblock/did":"1.19.2","@arcblock/did-auth":"1.19.2","@arcblock/did-ext":"^1.19.2","@arcblock/did-motif":"^1.1.13","@arcblock/did-util":"1.19.2","@arcblock/event-hub":"1.19.2","@arcblock/jwt":"^1.19.2","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"^1.19.2","@arcblock/vc":"1.19.2","@blocklet/constant":"1.16.37","@blocklet/did-space-js":"^1.0.1","@blocklet/env":"1.16.37","@blocklet/meta":"1.16.37","@blocklet/resolver":"1.16.37","@blocklet/sdk":"1.16.37","@blocklet/store":"1.16.37","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.19.2","@ocap/util":"1.19.2","@ocap/wallet":"1.19.2","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.9","axon":"^2.0.3","chalk":"^4.1.2","cross-spawn":"^7.0.3","deep-diff":"^1.0.2","detect-port":"^1.5.1","envfile":"^7.1.0","escape-string-regexp":"^4.0.0","fast-glob":"^3.3.2","filesize":"^10.1.1","flat":"^5.0.2","fs-extra":"^11.2.0","get-port":"^5.1.1","hasha":"^5.2.2","is-base64":"^1.1.0","is-cidr":"4","is-ip":"3","is-url":"^1.2.4","joi":"17.12.2","joi-extension-semver":"^5.0.0","js-yaml":"^4.1.0","kill-port":"^2.0.1","lodash":"^4.17.21","lru-cache":"^11.0.2","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-limit":"^3.1.0","p-map":"^4.0.0","p-retry":"^4.6.2","read-last-lines":"^1.8.0","semver":"^7.6.3","sequelize":"^6.35.0","shelljs":"^0.8.5","ssri":"^8.0.1","stream-throttle":"^0.1.3","stream-to-promise":"^3.0.0","systeminformation":"^5.23.3","tail":"^2.2.4","tar":"^6.1.11","transliteration":"^2.3.5","ua-parser-js":"^1.0.2","ufo":"^1.5.3","uuid":"^9.0.1","valid-url":"^1.0.9","which":"^2.0.2","xbytes":"^1.8.0"},"devDependencies":{"expand-tilde":"^2.0.2","express":"^4.18.2","jest":"^29.7.0","unzipper":"^0.10.11"},"gitHead":"e5764f753181ed6a7c615cd4fc6682aacf0cb7cd"}');
|
|
38557
38576
|
|
|
38558
38577
|
/***/ }),
|
|
38559
38578
|
|
|
@@ -11,6 +11,7 @@ const { update: updateMetaFile, read: readMetaFile } = require('@blocklet/meta/l
|
|
|
11
11
|
const { createRelease: createBlockletRelease } = require('@abtnode/util/lib/create-blocklet-release');
|
|
12
12
|
const { hasStartEngine } = require('@blocklet/meta/lib/util');
|
|
13
13
|
const { convertToMoniker } = require('@abtnode/util/lib/transfer-to-moniker');
|
|
14
|
+
const { parseDockerArgsToSchema, dockerParseEnvironments, dockerParsePublishPorts } = require('@abtnode/docker-utils');
|
|
14
15
|
|
|
15
16
|
const logger = require('@abtnode/logger')('blocklet-studio-pack');
|
|
16
17
|
|
|
@@ -42,6 +43,8 @@ const createPackRelease = async ({
|
|
|
42
43
|
blockletCommunity,
|
|
43
44
|
blockletRepository,
|
|
44
45
|
blockletVideos,
|
|
46
|
+
blockletDocker,
|
|
47
|
+
contentType,
|
|
45
48
|
manager,
|
|
46
49
|
status,
|
|
47
50
|
}) => {
|
|
@@ -67,6 +70,8 @@ const createPackRelease = async ({
|
|
|
67
70
|
blockletCommunity,
|
|
68
71
|
blockletRepository,
|
|
69
72
|
blockletVideos,
|
|
73
|
+
blockletDocker,
|
|
74
|
+
contentType,
|
|
70
75
|
};
|
|
71
76
|
|
|
72
77
|
const releaseSchema = createReleaseSchema(status);
|
|
@@ -103,7 +108,7 @@ const createPackRelease = async ({
|
|
|
103
108
|
|
|
104
109
|
const projectDir = path.join(blocklet.env.dataDir, PROJECT.DIR, `${projectId}`);
|
|
105
110
|
|
|
106
|
-
if (status !== PROJECT.RELEASE_STATUS.draft) {
|
|
111
|
+
if (status !== PROJECT.RELEASE_STATUS.draft && !blockletDocker?.dockerImage) {
|
|
107
112
|
await checkResourceExists(projectDir, action, releaseId);
|
|
108
113
|
}
|
|
109
114
|
|
|
@@ -217,6 +222,15 @@ const createPackRelease = async ({
|
|
|
217
222
|
return res;
|
|
218
223
|
});
|
|
219
224
|
|
|
225
|
+
let dockerYml;
|
|
226
|
+
if (blockletDocker?.dockerImage) {
|
|
227
|
+
const { error, value } = parseDockerArgsToSchema(blockletDocker.dockerImage, blockletDocker.dockerArgs);
|
|
228
|
+
if (error) {
|
|
229
|
+
throw new Error(`Docker args is invalid: ${error.message}`);
|
|
230
|
+
}
|
|
231
|
+
dockerYml = value;
|
|
232
|
+
}
|
|
233
|
+
|
|
220
234
|
// create blocklet.yml
|
|
221
235
|
const meta = {
|
|
222
236
|
did: blockletDid,
|
|
@@ -239,6 +253,21 @@ const createPackRelease = async ({
|
|
|
239
253
|
videos: blockletVideos || [],
|
|
240
254
|
};
|
|
241
255
|
|
|
256
|
+
if (blockletDocker?.dockerImage && dockerYml) {
|
|
257
|
+
meta.group = 'dapp';
|
|
258
|
+
meta.docker = dockerYml;
|
|
259
|
+
meta.environments = dockerParseEnvironments(blockletDocker.dockerEnvs, true);
|
|
260
|
+
if (!meta.interfaces) {
|
|
261
|
+
meta.interfaces = [];
|
|
262
|
+
}
|
|
263
|
+
meta.timeout = {
|
|
264
|
+
start: 120,
|
|
265
|
+
script: 120,
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
meta.interfaces.push(...dockerParsePublishPorts(blockletDocker.dockerImage, blockletDocker.dockerArgs));
|
|
269
|
+
}
|
|
270
|
+
|
|
242
271
|
// merge extended blocklet.yml
|
|
243
272
|
const extendedMetaFile = getExtendedMetaFile({ app: blocklet, projectId, releaseId });
|
|
244
273
|
if (fs.existsSync(extendedMetaFile)) {
|
|
@@ -8,7 +8,6 @@ const { createRelease: createBlockletRelease } = require('@abtnode/util/lib/crea
|
|
|
8
8
|
const { titleSchema } = require('@blocklet/meta/lib/schema');
|
|
9
9
|
const { validateNewDid } = require('@blocklet/meta/lib/name');
|
|
10
10
|
const { convertToMoniker } = require('@abtnode/util/lib/transfer-to-moniker');
|
|
11
|
-
|
|
12
11
|
const logger = require('@abtnode/logger')('blocklet-studio');
|
|
13
12
|
|
|
14
13
|
const { createReleaseSchema } = require('../../validators/project');
|
|
@@ -184,6 +183,8 @@ const createRelease = async ({
|
|
|
184
183
|
uploadedResource,
|
|
185
184
|
blockletComponents,
|
|
186
185
|
blockletResourceType,
|
|
186
|
+
blockletDocker,
|
|
187
|
+
contentType,
|
|
187
188
|
note,
|
|
188
189
|
manager,
|
|
189
190
|
status,
|
|
@@ -214,6 +215,8 @@ const createRelease = async ({
|
|
|
214
215
|
blockletVideos,
|
|
215
216
|
uploadedResource,
|
|
216
217
|
blockletResourceType,
|
|
218
|
+
blockletDocker,
|
|
219
|
+
contentType,
|
|
217
220
|
note,
|
|
218
221
|
};
|
|
219
222
|
|
|
@@ -228,7 +231,7 @@ const createRelease = async ({
|
|
|
228
231
|
throw new Error('project not found');
|
|
229
232
|
}
|
|
230
233
|
|
|
231
|
-
const isPack = blockletComponents?.length > 0;
|
|
234
|
+
const isPack = blockletComponents?.length > 0 || !!blockletDocker?.dockerImage;
|
|
232
235
|
|
|
233
236
|
if (isPack) {
|
|
234
237
|
return createPackRelease({
|
|
@@ -248,6 +251,8 @@ const createRelease = async ({
|
|
|
248
251
|
blockletScreenshots,
|
|
249
252
|
blockletComponents,
|
|
250
253
|
blockletResourceType,
|
|
254
|
+
blockletDocker,
|
|
255
|
+
contentType,
|
|
251
256
|
note,
|
|
252
257
|
manager,
|
|
253
258
|
status,
|
package/lib/states/release.js
CHANGED
package/lib/util/blocklet.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const md5 = require('@abtnode/util/lib/md5');
|
|
4
|
+
const { dockerArgsToCamelCase } = require('@abtnode/docker-utils');
|
|
4
5
|
const debianDockerfile = require('./debian-dockerfile');
|
|
5
6
|
|
|
6
|
-
function getBlockletCustomDockerfile({ appDir, dataDir, meta, ports }) {
|
|
7
|
+
function getBlockletCustomDockerfile({ appDir, dataDir, meta, ports, env }) {
|
|
7
8
|
const dockerMeta = meta.docker || {};
|
|
8
9
|
if (!dockerMeta.image && !dockerMeta.dockerfile) {
|
|
9
10
|
return debianDockerfile;
|
|
@@ -46,7 +47,7 @@ function getBlockletCustomDockerfile({ appDir, dataDir, meta, ports }) {
|
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
const volumes = (dockerMeta.
|
|
50
|
+
const volumes = (dockerMeta.volume || [])
|
|
50
51
|
.map((volume) => {
|
|
51
52
|
const [a, b] = volume.split(':');
|
|
52
53
|
const hostDir = a.replace('$BLOCKLET_DATA_DIR', dataDir).replace('$BLOCKLET_APP_DIR', appDir);
|
|
@@ -75,6 +76,31 @@ function getBlockletCustomDockerfile({ appDir, dataDir, meta, ports }) {
|
|
|
75
76
|
throw new Error('Detected forbidden volume mount (-v) in docker args');
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
const otherRunParams = {
|
|
80
|
+
'--attach': dockerMeta.attach || '',
|
|
81
|
+
'--quiet': dockerMeta.quiet || '',
|
|
82
|
+
'--user': dockerMeta.user || '',
|
|
83
|
+
'--workdir': dockerMeta.workdir || '',
|
|
84
|
+
'--cidfile': dockerMeta.cidfile || '',
|
|
85
|
+
'--detach-keys': dockerMeta.detachKeys || '',
|
|
86
|
+
'--disable-content-trust': dockerMeta.disableContentTrust || '',
|
|
87
|
+
'--domainname': dockerMeta.domainname || '',
|
|
88
|
+
'--expose': dockerMeta.expose || '',
|
|
89
|
+
'--ip': dockerMeta.ip || '',
|
|
90
|
+
'--link-local-ip': dockerMeta.linkLocalIp || '',
|
|
91
|
+
'--platform': dockerMeta.platform || '',
|
|
92
|
+
};
|
|
93
|
+
Object.entries(otherRunParams).forEach(([key, value]) => {
|
|
94
|
+
if (value === `$${dockerArgsToCamelCase(key)}`) {
|
|
95
|
+
otherRunParams[key] = env[dockerArgsToCamelCase(key)] || '';
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const runParamString = Object.entries(otherRunParams)
|
|
100
|
+
.filter(([, value]) => value !== '')
|
|
101
|
+
.map(([key, value]) => `${key} ${value}`)
|
|
102
|
+
.join(' ');
|
|
103
|
+
|
|
78
104
|
return {
|
|
79
105
|
dockerfile: file,
|
|
80
106
|
image: dockerMeta.image || `blocklet_custom_${hash.slice(0, 16)}`,
|
|
@@ -86,6 +112,7 @@ function getBlockletCustomDockerfile({ appDir, dataDir, meta, ports }) {
|
|
|
86
112
|
args: dockerMeta.command || '',
|
|
87
113
|
script: dockerMeta.script || dockerMeta.installNodeModules ? '' : 'tail -f /dev/null',
|
|
88
114
|
installNodeModules: !!dockerMeta.installNodeModules,
|
|
115
|
+
runParamString,
|
|
89
116
|
};
|
|
90
117
|
}
|
|
91
118
|
|
|
@@ -11,16 +11,31 @@ const lockFile = new LockFile(
|
|
|
11
11
|
1000 * 60 * 2
|
|
12
12
|
);
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
let safedDataAndBlocklets = false;
|
|
15
|
+
|
|
16
|
+
async function dockerExecChown(name, targetDirs, code = 777) {
|
|
17
17
|
const { image, baseDir } = debianDockerfile;
|
|
18
|
+
|
|
19
|
+
// 将 data、blocklets、logs 目录设置为 750 权限,防止因为修改子目录权限,其他组可以访问这三个目录的子目录
|
|
20
|
+
if (!safedDataAndBlocklets && process.env.ABT_NODE_DATA_DIR && code !== 750) {
|
|
21
|
+
safedDataAndBlocklets = true;
|
|
22
|
+
await dockerExecChown(
|
|
23
|
+
'safe-data-blocklets-logs',
|
|
24
|
+
[
|
|
25
|
+
path.join(process.env.ABT_NODE_DATA_DIR, 'blocklets'),
|
|
26
|
+
path.join(process.env.ABT_NODE_DATA_DIR, 'data'),
|
|
27
|
+
path.join(process.env.ABT_NODE_DATA_DIR, 'logs'),
|
|
28
|
+
],
|
|
29
|
+
750
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
18
33
|
const dirs = targetDirs.filter((dir) => fs.existsSync(dir));
|
|
19
34
|
const volumes = dirs
|
|
20
35
|
.map((dir) => `-v ${dir}:${path.join(baseDir, dir.replace(process.env.ABT_NODE_DATA_DIR, ''))}:rw`)
|
|
21
36
|
.join(' ');
|
|
22
37
|
const command = dirs
|
|
23
|
-
.map((dir) => `
|
|
38
|
+
.map((dir) => `chmod -R ${code} ${path.join(baseDir, dir.replace(process.env.ABT_NODE_DATA_DIR, ''))}`)
|
|
24
39
|
.join(' && ');
|
|
25
40
|
const realName = parseDockerName(name, 'docker-exec-chown');
|
|
26
41
|
const startTime = Date.now();
|
|
@@ -8,7 +8,11 @@ const os = require('os');
|
|
|
8
8
|
const logger = require('@abtnode/logger')('@abtnode/docker');
|
|
9
9
|
const { existsSync, writeFileSync } = require('fs-extra');
|
|
10
10
|
const { NODE_MODES } = require('@abtnode/constant');
|
|
11
|
+
const promiseSpawn = require('@abtnode/util/lib/promise-spawn');
|
|
11
12
|
const getLocalIPAddress = require('@abtnode/util/lib/get-local-ip-address');
|
|
13
|
+
const { getObjByPath } = require('@abtnode/docker-utils');
|
|
14
|
+
const { isValid: isDid } = require('@arcblock/did');
|
|
15
|
+
|
|
12
16
|
const parseDockerName = require('./parse-docker-name');
|
|
13
17
|
const { createDockerImage } = require('./create-docker-image');
|
|
14
18
|
const checkNeedRunDocker = require('./check-need-run-docker');
|
|
@@ -36,6 +40,7 @@ async function parseDockerOptionsFromPm2({
|
|
|
36
40
|
nodeInfo,
|
|
37
41
|
meta,
|
|
38
42
|
ports,
|
|
43
|
+
rootBlocklet,
|
|
39
44
|
overrideScript,
|
|
40
45
|
dockerNamePrefix = 'blocklet',
|
|
41
46
|
isDockerRm = false,
|
|
@@ -54,6 +59,7 @@ async function parseDockerOptionsFromPm2({
|
|
|
54
59
|
dataDir: options.env.BLOCKLET_DATA_DIR,
|
|
55
60
|
meta,
|
|
56
61
|
ports,
|
|
62
|
+
env: options.env,
|
|
57
63
|
})),
|
|
58
64
|
};
|
|
59
65
|
|
|
@@ -136,7 +142,8 @@ async function parseDockerOptionsFromPm2({
|
|
|
136
142
|
dockerInfo.network = `--network ${network}`;
|
|
137
143
|
Object.keys(ports).forEach((key) => {
|
|
138
144
|
const port = ports[key];
|
|
139
|
-
|
|
145
|
+
const inter = meta.interfaces?.find((x) => x.port === key);
|
|
146
|
+
dockerInfo.network += ` -p ${inter?.hostIP || '127.0.0.1'}:${port}:${inter?.containerPort || port}`;
|
|
140
147
|
});
|
|
141
148
|
if (nextOptions.env.ALLOW_DOCKER_HOST_ACCESS) {
|
|
142
149
|
dockerInfo.network += ' --add-host=host.docker.internal:host-gateway';
|
|
@@ -144,6 +151,50 @@ async function parseDockerOptionsFromPm2({
|
|
|
144
151
|
dockerEnv.BLOCKLET_DOCKER_NETWORK = network;
|
|
145
152
|
}
|
|
146
153
|
|
|
154
|
+
const needGetVars = Object.keys(dockerEnv).filter((key) => {
|
|
155
|
+
const value = dockerEnv[key];
|
|
156
|
+
if (
|
|
157
|
+
typeof value === 'string' &&
|
|
158
|
+
value.startsWith('z') &&
|
|
159
|
+
!key.startsWith('BLOCKLET_') &&
|
|
160
|
+
!key.startsWith('ABT_NODE_')
|
|
161
|
+
) {
|
|
162
|
+
const [prefix, rest] = value.split('-');
|
|
163
|
+
return isDid(prefix) && rest;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// 读取 env 和 ports 的值
|
|
169
|
+
// zxxxxxxxx-host 读取 host
|
|
170
|
+
// zxxxxxxxx-env.aaa 读取 env
|
|
171
|
+
// zxxxxxxxx-port 读取 port
|
|
172
|
+
// zxxxxxxxx-ports.xxx 读取其他 port
|
|
173
|
+
for (const envKey of needGetVars) {
|
|
174
|
+
const [did, ...rest] = dockerEnv[envKey].split('-');
|
|
175
|
+
const matchingBlocklet = rootBlocklet.children.find((blocklet) => blocklet.meta && blocklet.meta.did === did);
|
|
176
|
+
if (!matchingBlocklet) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const envMap = {};
|
|
180
|
+
matchingBlocklet.configs?.forEach((config) => {
|
|
181
|
+
envMap[config.key] = config.value || config.default;
|
|
182
|
+
});
|
|
183
|
+
const value = getObjByPath(
|
|
184
|
+
{
|
|
185
|
+
env: envMap,
|
|
186
|
+
ports: matchingBlocklet.ports,
|
|
187
|
+
host: parseDockerName(`${rootBlocklet.meta.did}-${matchingBlocklet.meta.name}`, dockerNamePrefix),
|
|
188
|
+
port: matchingBlocklet.ports?.BLOCKLET_PORT,
|
|
189
|
+
},
|
|
190
|
+
rest.join('-')
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
if (value) {
|
|
194
|
+
dockerEnv[envKey] = value;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
147
198
|
let nodeModulesName = 'node_modules';
|
|
148
199
|
let installScript = '';
|
|
149
200
|
const appDir = nextOptions.env.BLOCKLET_APP_DIR;
|
|
@@ -178,7 +229,10 @@ async function parseDockerOptionsFromPm2({
|
|
|
178
229
|
|
|
179
230
|
let runScript = dockerInfo.script || '';
|
|
180
231
|
if (!runScript && dockerInfo.installNodeModules) {
|
|
181
|
-
|
|
232
|
+
const maxOldSpaceSize = Math.floor(Number(dockerEnv.BLOCKLET_DOCKER_MEMORY.replace('g', '')) * 0.8 * 1024);
|
|
233
|
+
runScript = /(npm|yarn|pnpm|bun)/g.test(nextOptions.script)
|
|
234
|
+
? nextOptions.script
|
|
235
|
+
: `node --max-old-space-size=${maxOldSpaceSize} ${nextOptions.script}`;
|
|
182
236
|
}
|
|
183
237
|
|
|
184
238
|
const runScripts = ['preInstall', '--installScript--', 'postInstall', 'preFlight', 'preStart', '--runScript--']
|
|
@@ -306,25 +360,32 @@ async function parseDockerOptionsFromPm2({
|
|
|
306
360
|
`mkdir -p ${dockerEnv.BLOCKLET_CACHE_DIR} || :`,
|
|
307
361
|
'mkdir -p /.local || :',
|
|
308
362
|
`mkdir -p ${path.join(baseDir, '.npm')} || :`,
|
|
309
|
-
`
|
|
310
|
-
|
|
311
|
-
`
|
|
312
|
-
`
|
|
313
|
-
`
|
|
314
|
-
`
|
|
315
|
-
`
|
|
316
|
-
`
|
|
317
|
-
`
|
|
363
|
+
`chmod 777 ${baseDir} || :`,
|
|
364
|
+
'chmod 777 /.local || :',
|
|
365
|
+
`chmod 777 ${path.join(baseDir, 'dockerTemp')} || :`,
|
|
366
|
+
`chmod 777 ${dockerEnv.BLOCKLET_APP_DIR} || :`,
|
|
367
|
+
`chmod 777 ${dockerEnv.BLOCKLET_DATA_DIR} || :`,
|
|
368
|
+
`chmod 777 ${dockerEnv.BLOCKLET_LOG_DIR} || :`,
|
|
369
|
+
`chmod 777 ${dockerEnv.BLOCKLET_CACHE_DIR} || :`,
|
|
370
|
+
`chmod 777 ${dockerEnv.BLOCKLET_SHARE_DIR} || :`,
|
|
371
|
+
`chmod 777 ${path.join(dockerEnv.BLOCKLET_APP_DATA_DIR, '.projects')} || :`,
|
|
318
372
|
],
|
|
319
373
|
name,
|
|
320
374
|
userCommands: [`cd ${dockerEnv.BLOCKLET_APP_DIR}`, ...runScripts],
|
|
321
375
|
baseDir,
|
|
322
376
|
scriptDir: dockerTempDir,
|
|
323
377
|
});
|
|
378
|
+
|
|
379
|
+
let user = '';
|
|
380
|
+
if (meta.docker?.image && !!meta.docker?.useUidGid) {
|
|
381
|
+
user = `-u ${uid}:${gid}`;
|
|
382
|
+
}
|
|
383
|
+
|
|
324
384
|
nextOptions.script = `
|
|
325
385
|
docker rm -fv ${name} > /dev/null 2>&1 || true && \
|
|
326
386
|
${awaitRestart} \
|
|
327
387
|
docker run ${isDockerRm ? '--rm' : ''} --name ${name} \
|
|
388
|
+
${user} \
|
|
328
389
|
${volumes} \
|
|
329
390
|
${dockerInfo.volumes || ''} \
|
|
330
391
|
-v ${dockerTempDir}:${path.join(baseDir, 'dockerTemp')}:rw \
|
|
@@ -333,6 +394,7 @@ async function parseDockerOptionsFromPm2({
|
|
|
333
394
|
--memory="${dockerEnv.BLOCKLET_DOCKER_MEMORY}" \
|
|
334
395
|
--env-file ${dockerEnvFile} \
|
|
335
396
|
${dockerInfo.network} \
|
|
397
|
+
${dockerInfo.runParamString || ''} \
|
|
336
398
|
${dockerInfo.image} ${dockerInfo.command || ''} \
|
|
337
399
|
${dockerInfo.runBaseScript ? `sh ${path.join(baseDir, 'dockerTemp', `root-script-${name}.sh`)}` : ''}
|
|
338
400
|
`;
|
|
@@ -372,6 +434,10 @@ async function parseDockerOptionsFromPm2({
|
|
|
372
434
|
}
|
|
373
435
|
}
|
|
374
436
|
|
|
437
|
+
if (meta.docker?.image) {
|
|
438
|
+
await promiseSpawn(`docker pull ${meta.docker.image}`, {}, { timeout: 120 * 1000, retry: 0 });
|
|
439
|
+
}
|
|
440
|
+
|
|
375
441
|
return nextOptions;
|
|
376
442
|
}
|
|
377
443
|
|
|
@@ -63,6 +63,39 @@ const createReleaseSchema = (status) =>
|
|
|
63
63
|
required: Joi.boolean().allow(null),
|
|
64
64
|
})
|
|
65
65
|
),
|
|
66
|
+
contentType: Joi.string().valid('blocklet', 'upload', 'docker'),
|
|
67
|
+
blockletDocker: Joi.object({
|
|
68
|
+
dockerImage: Joi.string().allow('').default(''),
|
|
69
|
+
dockerArgs: Joi.array()
|
|
70
|
+
.items(
|
|
71
|
+
Joi.object({
|
|
72
|
+
key: Joi.string().required(),
|
|
73
|
+
value: Joi.alternatives()
|
|
74
|
+
.try(Joi.string().required(), Joi.array().items(Joi.string().required()))
|
|
75
|
+
.required(),
|
|
76
|
+
type: Joi.string().valid('docker', 'web').default('docker'),
|
|
77
|
+
port: Joi.string().optional().allow('').default(''),
|
|
78
|
+
prefix: Joi.string().optional().allow('').default(''),
|
|
79
|
+
path: Joi.string().optional().allow('').default('/'),
|
|
80
|
+
name: Joi.string().optional().allow('').default(''),
|
|
81
|
+
protocol: Joi.string().optional().allow('').default(''),
|
|
82
|
+
})
|
|
83
|
+
)
|
|
84
|
+
.default([]),
|
|
85
|
+
dockerEnvs: Joi.array()
|
|
86
|
+
.items(
|
|
87
|
+
Joi.object({
|
|
88
|
+
key: Joi.string().required(),
|
|
89
|
+
value: Joi.string().optional().allow('').default(''),
|
|
90
|
+
description: Joi.string().optional().allow('').default(''),
|
|
91
|
+
secure: Joi.boolean().optional().default(false),
|
|
92
|
+
shared: Joi.boolean().optional().default(false),
|
|
93
|
+
required: Joi.boolean().optional().default(false),
|
|
94
|
+
custom: Joi.string().optional().allow('').default(''),
|
|
95
|
+
})
|
|
96
|
+
)
|
|
97
|
+
.default([]),
|
|
98
|
+
}).optional(),
|
|
66
99
|
uploadedResource,
|
|
67
100
|
});
|
|
68
101
|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.16.
|
|
6
|
+
"version": "1.16.38-beta-20250108-235929-17742885",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,19 +19,20 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "Apache-2.0",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@abtnode/analytics": "1.16.
|
|
23
|
-
"@abtnode/auth": "1.16.
|
|
24
|
-
"@abtnode/certificate-manager": "1.16.
|
|
25
|
-
"@abtnode/constant": "1.16.
|
|
26
|
-
"@abtnode/cron": "1.16.
|
|
27
|
-
"@abtnode/
|
|
28
|
-
"@abtnode/
|
|
29
|
-
"@abtnode/
|
|
30
|
-
"@abtnode/
|
|
31
|
-
"@abtnode/
|
|
32
|
-
"@abtnode/
|
|
33
|
-
"@abtnode/
|
|
34
|
-
"@abtnode/
|
|
22
|
+
"@abtnode/analytics": "1.16.38-beta-20250108-235929-17742885",
|
|
23
|
+
"@abtnode/auth": "1.16.38-beta-20250108-235929-17742885",
|
|
24
|
+
"@abtnode/certificate-manager": "1.16.38-beta-20250108-235929-17742885",
|
|
25
|
+
"@abtnode/constant": "1.16.38-beta-20250108-235929-17742885",
|
|
26
|
+
"@abtnode/cron": "1.16.38-beta-20250108-235929-17742885",
|
|
27
|
+
"@abtnode/docker-utils": "1.16.38-beta-20250108-235929-17742885",
|
|
28
|
+
"@abtnode/logger": "1.16.38-beta-20250108-235929-17742885",
|
|
29
|
+
"@abtnode/models": "1.16.38-beta-20250108-235929-17742885",
|
|
30
|
+
"@abtnode/queue": "1.16.38-beta-20250108-235929-17742885",
|
|
31
|
+
"@abtnode/rbac": "1.16.38-beta-20250108-235929-17742885",
|
|
32
|
+
"@abtnode/router-provider": "1.16.38-beta-20250108-235929-17742885",
|
|
33
|
+
"@abtnode/static-server": "1.16.38-beta-20250108-235929-17742885",
|
|
34
|
+
"@abtnode/timemachine": "1.16.38-beta-20250108-235929-17742885",
|
|
35
|
+
"@abtnode/util": "1.16.38-beta-20250108-235929-17742885",
|
|
35
36
|
"@arcblock/did": "1.19.2",
|
|
36
37
|
"@arcblock/did-auth": "1.19.2",
|
|
37
38
|
"@arcblock/did-ext": "^1.19.2",
|
|
@@ -42,13 +43,13 @@
|
|
|
42
43
|
"@arcblock/pm2-events": "^0.0.5",
|
|
43
44
|
"@arcblock/validator": "^1.19.2",
|
|
44
45
|
"@arcblock/vc": "1.19.2",
|
|
45
|
-
"@blocklet/constant": "1.16.
|
|
46
|
+
"@blocklet/constant": "1.16.38-beta-20250108-235929-17742885",
|
|
46
47
|
"@blocklet/did-space-js": "^1.0.1",
|
|
47
|
-
"@blocklet/env": "1.16.
|
|
48
|
-
"@blocklet/meta": "1.16.
|
|
49
|
-
"@blocklet/resolver": "1.16.
|
|
50
|
-
"@blocklet/sdk": "1.16.
|
|
51
|
-
"@blocklet/store": "1.16.
|
|
48
|
+
"@blocklet/env": "1.16.38-beta-20250108-235929-17742885",
|
|
49
|
+
"@blocklet/meta": "1.16.38-beta-20250108-235929-17742885",
|
|
50
|
+
"@blocklet/resolver": "1.16.38-beta-20250108-235929-17742885",
|
|
51
|
+
"@blocklet/sdk": "1.16.38-beta-20250108-235929-17742885",
|
|
52
|
+
"@blocklet/store": "1.16.38-beta-20250108-235929-17742885",
|
|
52
53
|
"@fidm/x509": "^1.2.1",
|
|
53
54
|
"@ocap/mcrypto": "1.19.2",
|
|
54
55
|
"@ocap/util": "1.19.2",
|
|
@@ -108,5 +109,5 @@
|
|
|
108
109
|
"jest": "^29.7.0",
|
|
109
110
|
"unzipper": "^0.10.11"
|
|
110
111
|
},
|
|
111
|
-
"gitHead": "
|
|
112
|
+
"gitHead": "09d67442bff28543c35824a41c23bea3b75a2a23"
|
|
112
113
|
}
|