@abtnode/core 1.16.33 → 1.16.34-beta-20241120-080738-bbbe036c

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/README.md CHANGED
@@ -1,3 +1,3 @@
1
1
  # ABT Node Core
2
2
 
3
- ABT Node core state management lib, that powers `@abtnode/cli` and `@abtnode/webapp`.
3
+ ABT Node core state management lib, that powers `@blocklet/cli` and `@abtnode/webapp`.
@@ -216,7 +216,11 @@ const statusLock = new Lock('blocklet-status-lock');
216
216
  const getHookArgs = (blocklet) => ({
217
217
  output: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT ? '' : path.join(blocklet.env.logsDir, 'output.log'),
218
218
  error: blocklet.mode === BLOCKLET_MODES.DEVELOPMENT ? '' : path.join(blocklet.env.logsDir, 'error.log'),
219
- timeout: (get(blocklet, 'meta.timeout.script') || 120) * 1000,
219
+ timeout:
220
+ Math.max(
221
+ get(blocklet, 'meta.timeout.script', 120),
222
+ ...(blocklet?.children || []).map((child) => child.meta?.timeout?.script || 0)
223
+ ) * 1000,
220
224
  });
221
225
 
222
226
  const pm2StatusMap = {
@@ -906,6 +910,7 @@ class DiskBlockletManager extends BaseBlockletManager {
906
910
  env: nextEnv,
907
911
  hookName: 'preStop',
908
912
  nodeInfo,
913
+ timeout: getHookArgs(b).timeout,
909
914
  });
910
915
  }
911
916
  return null;
@@ -1124,6 +1129,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1124
1129
  script: b.meta.scripts.preUninstall,
1125
1130
  hookName: 'preUninstall',
1126
1131
  nodeInfo,
1132
+ timeout: getHookArgs(b).timeout,
1127
1133
  });
1128
1134
  }
1129
1135
  return null;
@@ -1178,7 +1184,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1178
1184
  const nodeInfo = await states.node.read();
1179
1185
  // 如果删除因为权限问题失败,尝试用 docker 用户去调整用户组为宿主机当前用户
1180
1186
  if (checkDockerRunHistory(nodeInfo) && error.code === 'EACCES') {
1181
- await dockerExecChown(`${did}-${childDid}`, dirs);
1187
+ await dockerExecChown(`${did}-${childDid}-remove-catch`, dirs);
1182
1188
  for (const dir of dirs) {
1183
1189
  fs.removeSync(dir);
1184
1190
  logger.info(`removed blocklet ${did} ${childDid}: ${dir}`);
@@ -1246,7 +1252,12 @@ class DiskBlockletManager extends BaseBlockletManager {
1246
1252
 
1247
1253
  async deleteComponent({ did, rootDid, keepData, keepState }, context) {
1248
1254
  logger.info('delete blocklet component', { did, rootDid, keepData });
1249
-
1255
+ const nodeInfo = await states.node.read();
1256
+ if (checkDockerRunHistory(nodeInfo)) {
1257
+ await dockerExecChown(`${did}-${rootDid}-deleteComponent`, [
1258
+ path.join(process.env.ABT_NODE_DATA_DIR, 'data', rootDid),
1259
+ ]);
1260
+ }
1250
1261
  const app = await this.getBlocklet(rootDid);
1251
1262
 
1252
1263
  const child = app.children.find((x) => x.meta.did === did);
@@ -1602,7 +1613,7 @@ class DiskBlockletManager extends BaseBlockletManager {
1602
1613
  nodeInfo,
1603
1614
  env: nextEnv,
1604
1615
  script: blocklet.meta.scripts.preConfig,
1605
- timeout: 1000 * 10,
1616
+ timeout: getHookArgs(blocklet).timeout,
1606
1617
  retry: 0,
1607
1618
  hookName: 'preConfig',
1608
1619
  });
@@ -4121,6 +4132,10 @@ class DiskBlockletManager extends BaseBlockletManager {
4121
4132
  const dataDir = path.join(this.dataDirs.data, name);
4122
4133
  const logsDir = path.join(this.dataDirs.logs, name);
4123
4134
  const cacheDir = path.join(this.dataDirs.cache, name);
4135
+ const nodeInfo = await states.node.read();
4136
+ if (checkDockerRunHistory(nodeInfo)) {
4137
+ await dockerExecChown(`${blocklet.meta.did}-clean-data`, [dataDir, logsDir, cacheDir]);
4138
+ }
4124
4139
 
4125
4140
  logger.info(`clean blocklet ${blocklet.meta.did} data`, { keepData, keepLogsDir, keepConfigs });
4126
4141
 
@@ -4580,7 +4595,10 @@ class DiskBlockletManager extends BaseBlockletManager {
4580
4595
  // eslint-disable-next-line no-unused-vars
4581
4596
  async _backupToDisk({ blocklet }, context) {
4582
4597
  const { appDid } = blocklet;
4583
-
4598
+ const nodeInfo = await states.node.read();
4599
+ if (checkDockerRunHistory(nodeInfo)) {
4600
+ await dockerExecChown(`${appDid}-backup-to-disk`, [path.join(process.env.ABT_NODE_DATA_DIR, 'data', appDid)]);
4601
+ }
4584
4602
  const diskBackup = new DiskBackup({ appDid, event: this });
4585
4603
  await diskBackup.backup();
4586
4604
 
@@ -67,6 +67,9 @@ const installApplicationFromBackup = async ({
67
67
  );
68
68
  }
69
69
 
70
+ /** @type {import('@abtnode/client').RoutingSite} */
71
+ const routingSite = omit(fs.readJSONSync(path.join(dir, 'routing_rule.json')));
72
+
70
73
  const { meta } = blockletState;
71
74
  const { did, name: appName } = meta;
72
75
 
@@ -135,6 +138,10 @@ const installApplicationFromBackup = async ({
135
138
  let blocklet = null;
136
139
 
137
140
  try {
141
+ // 还原 routing rule
142
+ await states.site.remove({ id: routingSite.id });
143
+ await states.site.insert(routingSite);
144
+
138
145
  // copy extra
139
146
  const existExtra = await states.blockletExtras.find({ did });
140
147
  if (existExtra) {
@@ -38532,7 +38532,7 @@ module.exports = require("zlib");
38532
38532
  /***/ ((module) => {
38533
38533
 
38534
38534
  "use strict";
38535
- module.exports = JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.32","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.32","@abtnode/auth":"1.16.32","@abtnode/certificate-manager":"1.16.32","@abtnode/constant":"1.16.32","@abtnode/cron":"1.16.32","@abtnode/logger":"1.16.32","@abtnode/models":"1.16.32","@abtnode/queue":"1.16.32","@abtnode/rbac":"1.16.32","@abtnode/router-provider":"1.16.32","@abtnode/static-server":"1.16.32","@abtnode/timemachine":"1.16.32","@abtnode/util":"1.16.32","@arcblock/did":"1.18.139","@arcblock/did-auth":"1.18.139","@arcblock/did-ext":"^1.18.139","@arcblock/did-motif":"^1.1.13","@arcblock/did-util":"1.18.139","@arcblock/event-hub":"1.18.139","@arcblock/jwt":"^1.18.139","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"^1.18.139","@arcblock/vc":"1.18.139","@blocklet/constant":"1.16.32","@blocklet/env":"1.16.32","@blocklet/meta":"1.16.32","@blocklet/resolver":"1.16.32","@blocklet/sdk":"1.16.32","@blocklet/store":"1.16.32","@blocklet/did-space-js":"^0.5.65","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.18.139","@ocap/util":"1.18.139","@ocap/wallet":"1.18.139","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.5","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-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":"^6.0.0","node-stream-zip":"^1.15.0","p-all":"^3.0.0","p-map":"^4.0.0","p-limit":"^3.1.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"}');
38535
+ module.exports = JSON.parse('{"name":"@abtnode/core","publishConfig":{"access":"public"},"version":"1.16.33","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.33","@abtnode/auth":"1.16.33","@abtnode/certificate-manager":"1.16.33","@abtnode/constant":"1.16.33","@abtnode/cron":"1.16.33","@abtnode/logger":"1.16.33","@abtnode/models":"1.16.33","@abtnode/queue":"1.16.33","@abtnode/rbac":"1.16.33","@abtnode/router-provider":"1.16.33","@abtnode/static-server":"1.16.33","@abtnode/timemachine":"1.16.33","@abtnode/util":"1.16.33","@arcblock/did":"1.18.139","@arcblock/did-auth":"1.18.139","@arcblock/did-ext":"^1.18.139","@arcblock/did-motif":"^1.1.13","@arcblock/did-util":"1.18.139","@arcblock/event-hub":"1.18.139","@arcblock/jwt":"^1.18.139","@arcblock/pm2-events":"^0.0.5","@arcblock/validator":"^1.18.139","@arcblock/vc":"1.18.139","@blocklet/constant":"1.16.33","@blocklet/did-space-js":"^0.5.65","@blocklet/env":"1.16.33","@blocklet/meta":"1.16.33","@blocklet/resolver":"1.16.33","@blocklet/sdk":"1.16.33","@blocklet/store":"1.16.33","@fidm/x509":"^1.2.1","@ocap/mcrypto":"1.18.139","@ocap/util":"1.18.139","@ocap/wallet":"1.18.139","@slack/webhook":"^5.0.4","archiver":"^7.0.1","axios":"^1.7.5","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-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":"^6.0.0","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"}');
38536
38536
 
38537
38537
  /***/ }),
38538
38538
 
package/lib/index.js CHANGED
@@ -273,7 +273,14 @@ function ABTNode(options) {
273
273
  deleteRoutingRule,
274
274
  addDomainAlias,
275
275
  deleteDomainAlias,
276
- } = getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager });
276
+ } = getRouterHelpers({
277
+ dataDirs,
278
+ routingSnapshot,
279
+ routerManager,
280
+ blockletManager,
281
+ certManager,
282
+ daemon: options.daemon,
283
+ });
277
284
 
278
285
  blockletManager.resetSiteByDid = resetSiteByDid;
279
286
 
@@ -74,6 +74,7 @@ const { getFromCache: getAccessibleExternalNodeIp } = require('../util/get-acces
74
74
 
75
75
  const Router = require('./index');
76
76
  const states = require('../states');
77
+ const monitor = require('../util/monitor');
77
78
  const { getBlockletDomainGroupName, getDidFromDomainGroupName, createProviderInstance } = require('../util/router');
78
79
  const {
79
80
  getBlockletDidDomainList,
@@ -679,7 +680,14 @@ const getDidDomainCertDownloadUrl = (baseUrl) => joinCertDownUrl(baseUrl, 'did-a
679
680
  const getDownloadCertBaseUrl = (info) =>
680
681
  process.env.ABT_NODE_WILDCARD_CERT_HOST || get(info, 'routing.wildcardCertHost', '');
681
682
 
682
- module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerManager, blockletManager, certManager }) {
683
+ module.exports = function getRouterHelpers({
684
+ dataDirs,
685
+ routingSnapshot,
686
+ routerManager,
687
+ blockletManager,
688
+ certManager,
689
+ daemon = false,
690
+ }) {
683
691
  const nodeState = states.node;
684
692
  const blockletState = states.blocklet;
685
693
  const siteState = states.site;
@@ -1317,6 +1325,20 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1317
1325
  await providers[providerName].start();
1318
1326
  }
1319
1327
 
1328
+ if (daemon && process.env.ABT_NODE_MONITOR_GATEWAY_5XX) {
1329
+ monitor.stopLogWatcher();
1330
+ const logs = providers[providerName].getLogFilesForToday();
1331
+ monitor.startLogWatcher(logs.access, (logEntries) => {
1332
+ notification.create({
1333
+ title: 'Server 5xx Alert',
1334
+ description: `5xx request detected: ${JSON.stringify(logEntries, null, 2)}`,
1335
+ entityType: 'server',
1336
+ severity: 'error',
1337
+ sticky: true,
1338
+ });
1339
+ });
1340
+ }
1341
+
1320
1342
  logger.info('done handle routing', { cost: Date.now() - now });
1321
1343
  };
1322
1344
 
@@ -1325,7 +1347,20 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1325
1347
  const providerName = get(info, 'routing.provider', null);
1326
1348
 
1327
1349
  if (providerName && providers[providerName] && typeof providers[providerName].rotateLogs === 'function') {
1350
+ monitor.stopLogWatcher();
1328
1351
  await providers[providerName].rotateLogs({ retain: LOG_RETAIN_IN_DAYS });
1352
+ if (daemon && process.env.ABT_NODE_MONITOR_GATEWAY_5XX) {
1353
+ const logs = providers[providerName].getLogFilesForToday();
1354
+ monitor.startLogWatcher(logs.access, (logEntries) => {
1355
+ notification.create({
1356
+ title: 'Server 5xx Alert',
1357
+ description: `5xx request detected: ${JSON.stringify(logEntries, null, 2)}`,
1358
+ entityType: 'server',
1359
+ severity: 'error',
1360
+ sticky: true,
1361
+ });
1362
+ });
1363
+ }
1329
1364
  }
1330
1365
  };
1331
1366
 
@@ -524,8 +524,11 @@ const getHealthyCheckTimeout = (blocklet, { checkHealthImmediately } = {}) => {
524
524
  }
525
525
 
526
526
  // Let's wait for at least 1 minute for the blocklet to go live
527
- let startTimeout = process.env.NODE_ENV === 'test' ? 10 : 60;
528
- startTimeout = Math.max(get(blocklet, 'meta.timeout.start', startTimeout), startTimeout) * 1000;
527
+ const startTimeout =
528
+ Math.max(
529
+ get(blocklet, 'meta.timeout.start', process.env.NODE_ENV === 'test' ? 10 : 60),
530
+ ...(blocklet?.children || []).map((child) => child.meta?.timeout?.start || 0)
531
+ ) * 1000;
529
532
 
530
533
  return {
531
534
  startTimeout,
@@ -970,8 +973,10 @@ const expandTarball = async ({ source, dest, strip = 1 }) => {
970
973
  };
971
974
 
972
975
  const verifyIntegrity = async ({ file, integrity: expected }) => {
973
- const result = await ssri.checkStream(fs.createReadStream(file), ssri.parse(expected));
976
+ const stream = fs.createReadStream(file);
977
+ const result = await ssri.checkStream(stream, ssri.parse(expected));
974
978
  logger.debug('verify integrity result', { result });
979
+ stream.destroy();
975
980
  return true;
976
981
  };
977
982
 
@@ -3,6 +3,7 @@ const fs = require('fs');
3
3
  const logger = require('@abtnode/logger')('@abtnode/docker-exec-chown');
4
4
  const debianDockerfile = require('./debian-dockerfile');
5
5
  const promiseSpawn = require('../promise-spawn');
6
+ const parseDockerName = require('./parse-docker-name');
6
7
 
7
8
  async function dockerExecChown(name, targetDirs) {
8
9
  const uid = process.getuid();
@@ -15,7 +16,7 @@ async function dockerExecChown(name, targetDirs) {
15
16
  const command = dirs
16
17
  .map((dir) => `chown -R ${uid}:${gid} ${path.join(baseDir, dir.replace(process.env.ABT_NODE_DATA_DIR, ''))}`)
17
18
  .join(' && ');
18
- const realName = `blocklet-chown-${name.replace(/\\/g, '_')}`;
19
+ const realName = parseDockerName(`blocklet-chown-${name.replace(/\\/g, '_')}`);
19
20
  const startTime = Date.now();
20
21
  try {
21
22
  await promiseSpawn(
@@ -7,6 +7,7 @@ const fs = require('fs');
7
7
  const os = require('os');
8
8
  const logger = require('@abtnode/logger')('@abtnode/docker');
9
9
  const { existsSync, writeFileSync } = require('fs-extra');
10
+ const { NODE_MODES } = require('@abtnode/constant');
10
11
 
11
12
  const parseDockerName = require('./parse-docker-name');
12
13
  const { createDockerImage } = require('./create-docker-image');
@@ -35,6 +36,8 @@ async function parseDockerOptionsFromPm2({ options, nodeInfo, meta, ports, overr
35
36
  return options;
36
37
  }
37
38
 
39
+ const isServerless = nodeInfo.mode === NODE_MODES.SERVERLESS;
40
+
38
41
  const dockerInfo = await createDockerImage({
39
42
  appDir: options.env.BLOCKLET_APP_DIR,
40
43
  dataDir: options.env.BLOCKLET_DATA_DIR,
@@ -46,13 +49,30 @@ async function parseDockerOptionsFromPm2({ options, nodeInfo, meta, ports, overr
46
49
  nextOptions.env = { ...nextOptions.env };
47
50
  const name = parseDockerName(options.name);
48
51
 
52
+ const defaultCpus = '2';
53
+ const defaultMemory = '2g';
54
+ const defaultDiskSize = '0g';
55
+
56
+ const cpus = isServerless
57
+ ? process.env.ABT_NODE_DOCKER_CPUS
58
+ : options.env.DOCKER_CPUS || process.env.ABT_NODE_DOCKER_CPUS;
59
+
60
+ const memory = isServerless
61
+ ? process.env.ABT_NODE_DOCKER_MEMORY
62
+ : options.env.DOCKER_MEMORY || process.env.ABT_NODE_DOCKER_MEMORY;
63
+
64
+ const diskSize = isServerless
65
+ ? process.env.ABT_NODE_DOCKER_DISK_SIZE
66
+ : options.env.DOCKER_DISK_SIZE || process.env.ABT_NODE_DOCKER_DISK_SIZE;
67
+
49
68
  // Ensure environment variables are properly set within the Docker container
50
69
  const envDefaults = {
51
- BLOCKLET_DOCKER_CPUS: '2',
52
- BLOCKLET_DOCKER_MEMORY: '2g',
53
- BLOCKLET_DOCKER_DISK_SIZE: '0g',
70
+ BLOCKLET_DOCKER_CPUS: cpus || defaultCpus,
71
+ BLOCKLET_DOCKER_MEMORY: memory || defaultMemory,
72
+ BLOCKLET_DOCKER_DISK_SIZE: diskSize || defaultDiskSize,
54
73
  BLOCKLET_DOCKER_NAME: name,
55
74
  INTERNAL_HOST: 'host.docker.internal',
75
+ NODE_MODES: options.env.NODE_MODES || (isServerless ? NODE_MODES.SERVERLESS : NODE_MODES.PRODUCTION),
56
76
  HTTP_PROXY: process.env.DOCKER_HTTP_PROXY || '',
57
77
  HTTPS_PROXY: process.env.DOCKER_HTTPS_PROXY || '',
58
78
  };
@@ -163,11 +183,13 @@ async function parseDockerOptionsFromPm2({ options, nodeInfo, meta, ports, overr
163
183
  target: path.join(dockerEnv.BLOCKLET_APP_DATA_DIR, '.assets'),
164
184
  canEdit: false,
165
185
  },
166
- {
167
- source: nextOptions.env.BLOCKLET_APP_DATA_DIR,
168
- target: dockerEnv.BLOCKLET_APP_DATA_DIR,
169
- canEdit: false,
170
- },
186
+ options.env.SHARE_DOCKER_APP_DATA_DIR
187
+ ? {
188
+ source: nextOptions.env.BLOCKLET_APP_DATA_DIR,
189
+ target: dockerEnv.BLOCKLET_APP_DATA_DIR,
190
+ canEdit: false,
191
+ }
192
+ : null,
171
193
  { source: nextOptions.env.BLOCKLET_APP_DIR, target: dockerEnv.BLOCKLET_APP_DIR, canEdit: true },
172
194
  { source: nextOptions.env.BLOCKLET_DATA_DIR, target: dockerEnv.BLOCKLET_DATA_DIR, canEdit: true },
173
195
  { source: nextOptions.env.BLOCKLET_LOG_DIR, target: dockerEnv.BLOCKLET_LOG_DIR, canEdit: true },
@@ -188,6 +210,9 @@ async function parseDockerOptionsFromPm2({ options, nodeInfo, meta, ports, overr
188
210
  canEdit: true,
189
211
  },
190
212
  ].filter((v) => {
213
+ if (!v) {
214
+ return false;
215
+ }
191
216
  if (targetDirs.has(v.target)) {
192
217
  return false;
193
218
  }
@@ -0,0 +1,159 @@
1
+ /* eslint-disable no-await-in-loop */
2
+ const fs = require('fs');
3
+
4
+ const THROTTLE_DELAY = 1000; // 1 second throttle
5
+
6
+ // Function to parse the log entry and extract relevant information
7
+ function parseLogEntry(line) {
8
+ const regex =
9
+ /^(\S+) - (\S+) \[([^\]]+)\] (\S+) "([^"]+)" "([^"]+)" (\d{3}) (\d+) "(.*?)" "(.*?)" "(.*?)" rt="(\S+)" uid="(.+?)" uos="(.+?)" uct="(\S+)" uht="(\S+)" urt="(\S+)"/;
10
+ const match = line.match(regex);
11
+ if (match) {
12
+ return {
13
+ ip: match[1],
14
+ remoteUser: match[2],
15
+ timeIso8601: match[3],
16
+ requestId: match[4],
17
+ host: match[5],
18
+ request: match[6],
19
+ status: parseInt(match[7], 10),
20
+ bodyBytesSent: parseInt(match[8], 10),
21
+ referer: match[9],
22
+ userAgent: match[10],
23
+ forwardedFor: match[11],
24
+ requestTime: parseFloat(match[12]),
25
+ connectedDid: match[13],
26
+ connectedWalletOs: match[14],
27
+ upstreamConnectTime: parseFloat(match[15]),
28
+ upstreamHeaderTime: parseFloat(match[16]),
29
+ upstreamResponseTime: parseFloat(match[17]),
30
+ };
31
+ }
32
+ return null;
33
+ }
34
+
35
+ async function readLogFile(filePath, startPosition = 0) {
36
+ let fd = null;
37
+ try {
38
+ if (!fs.existsSync(filePath)) {
39
+ return { lines: [], fileSize: 0 };
40
+ }
41
+
42
+ const realPath = await fs.promises.realpath(filePath);
43
+ fd = await fs.promises.open(realPath, 'r');
44
+ const stats = await fd.stat();
45
+ const fileSize = stats.size;
46
+
47
+ if (startPosition < 0) {
48
+ // eslint-disable-next-line no-param-reassign
49
+ startPosition = Math.max(0, fileSize + startPosition);
50
+ }
51
+
52
+ if (startPosition >= fileSize) {
53
+ return { lines: [], fileSize };
54
+ }
55
+
56
+ const readSize = fileSize - startPosition;
57
+ if (readSize <= 0) {
58
+ return { lines: [], fileSize };
59
+ }
60
+
61
+ const buffer = Buffer.alloc(readSize);
62
+ const { bytesRead } = await fd.read(buffer, 0, readSize, startPosition);
63
+ const content = buffer.slice(0, bytesRead).toString();
64
+
65
+ const lines = content
66
+ .split('\n')
67
+ .map((line) => line.trim())
68
+ .filter(Boolean);
69
+
70
+ return { lines, fileSize };
71
+ } finally {
72
+ if (fd) {
73
+ await fd.close();
74
+ }
75
+ }
76
+ }
77
+
78
+ let watcher;
79
+ process.on('SIGINT', () => {
80
+ watcher?.close();
81
+ });
82
+
83
+ process.on('SIGTERM', () => {
84
+ watcher?.close();
85
+ });
86
+
87
+ function startLogWatcher(logFilePath, onLogEntry, initialBufferSize = 10240) {
88
+ if (!fs.existsSync(logFilePath)) {
89
+ console.error(`Log file ${logFilePath} does not exist`);
90
+ return;
91
+ }
92
+
93
+ console.warn(`Start watching ${logFilePath} for 5xx requests...`);
94
+
95
+ let isProcessing = false;
96
+ let isFirstRun = true;
97
+ let timeoutId = null;
98
+ let lastProcessedPosition = 0;
99
+
100
+ async function processLogChanges() {
101
+ isProcessing = true;
102
+ try {
103
+ const { lines, fileSize } = await readLogFile(
104
+ logFilePath,
105
+ isFirstRun ? -initialBufferSize : lastProcessedPosition
106
+ );
107
+ const entries = [];
108
+
109
+ for (const line of lines) {
110
+ const logEntry = parseLogEntry(line);
111
+ if (logEntry && logEntry.status >= 500 && logEntry.status <= 599) {
112
+ console.warn(`5xx request detected: ${logEntry.host}`, line);
113
+ entries.push(logEntry);
114
+ }
115
+ }
116
+
117
+ if (entries.length > 0) {
118
+ onLogEntry(entries);
119
+ }
120
+
121
+ lastProcessedPosition = fileSize;
122
+ isFirstRun = false;
123
+ } catch (error) {
124
+ console.error(`Error reading log file ${logFilePath}`, error);
125
+ } finally {
126
+ isProcessing = false;
127
+ }
128
+ }
129
+
130
+ watcher = fs.watch(logFilePath, { persistent: true }, async (eventType, filename) => {
131
+ if (!filename || eventType !== 'change') return;
132
+
133
+ // Clear any pending timeout
134
+ if (timeoutId) {
135
+ clearTimeout(timeoutId);
136
+ }
137
+
138
+ // If already processing, schedule for later
139
+ if (isProcessing) {
140
+ timeoutId = setTimeout(() => {
141
+ processLogChanges();
142
+ }, THROTTLE_DELAY);
143
+ return;
144
+ }
145
+
146
+ await processLogChanges();
147
+ });
148
+ }
149
+
150
+ function stopLogWatcher() {
151
+ watcher?.close();
152
+ }
153
+
154
+ module.exports = {
155
+ parseLogEntry,
156
+ readLogFile,
157
+ startLogWatcher,
158
+ stopLogWatcher,
159
+ };
@@ -112,6 +112,12 @@ module.exports = class LogRotate {
112
112
  }
113
113
 
114
114
  const onError = (err) => {
115
+ if (GZIP) {
116
+ GZIP.close();
117
+ }
118
+ readStream?.close();
119
+ writeStream?.close();
120
+
115
121
  logError(err);
116
122
  callback(err);
117
123
  };
@@ -128,8 +134,8 @@ module.exports = class LogRotate {
128
134
  if (GZIP) {
129
135
  GZIP.close();
130
136
  }
131
- readStream.close();
132
- writeStream.close();
137
+ readStream?.close();
138
+ writeStream?.close();
133
139
 
134
140
  fs.truncateSync(file);
135
141
  logInfo('rotated file:', finalName);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.16.33",
6
+ "version": "1.16.34-beta-20241120-080738-bbbe036c",
7
7
  "description": "",
8
8
  "main": "lib/index.js",
9
9
  "files": [
@@ -19,19 +19,19 @@
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.33",
23
- "@abtnode/auth": "1.16.33",
24
- "@abtnode/certificate-manager": "1.16.33",
25
- "@abtnode/constant": "1.16.33",
26
- "@abtnode/cron": "1.16.33",
27
- "@abtnode/logger": "1.16.33",
28
- "@abtnode/models": "1.16.33",
29
- "@abtnode/queue": "1.16.33",
30
- "@abtnode/rbac": "1.16.33",
31
- "@abtnode/router-provider": "1.16.33",
32
- "@abtnode/static-server": "1.16.33",
33
- "@abtnode/timemachine": "1.16.33",
34
- "@abtnode/util": "1.16.33",
22
+ "@abtnode/analytics": "1.16.34-beta-20241120-080738-bbbe036c",
23
+ "@abtnode/auth": "1.16.34-beta-20241120-080738-bbbe036c",
24
+ "@abtnode/certificate-manager": "1.16.34-beta-20241120-080738-bbbe036c",
25
+ "@abtnode/constant": "1.16.34-beta-20241120-080738-bbbe036c",
26
+ "@abtnode/cron": "1.16.34-beta-20241120-080738-bbbe036c",
27
+ "@abtnode/logger": "1.16.34-beta-20241120-080738-bbbe036c",
28
+ "@abtnode/models": "1.16.34-beta-20241120-080738-bbbe036c",
29
+ "@abtnode/queue": "1.16.34-beta-20241120-080738-bbbe036c",
30
+ "@abtnode/rbac": "1.16.34-beta-20241120-080738-bbbe036c",
31
+ "@abtnode/router-provider": "1.16.34-beta-20241120-080738-bbbe036c",
32
+ "@abtnode/static-server": "1.16.34-beta-20241120-080738-bbbe036c",
33
+ "@abtnode/timemachine": "1.16.34-beta-20241120-080738-bbbe036c",
34
+ "@abtnode/util": "1.16.34-beta-20241120-080738-bbbe036c",
35
35
  "@arcblock/did": "1.18.139",
36
36
  "@arcblock/did-auth": "1.18.139",
37
37
  "@arcblock/did-ext": "^1.18.139",
@@ -42,13 +42,13 @@
42
42
  "@arcblock/pm2-events": "^0.0.5",
43
43
  "@arcblock/validator": "^1.18.139",
44
44
  "@arcblock/vc": "1.18.139",
45
- "@blocklet/constant": "1.16.33",
45
+ "@blocklet/constant": "1.16.34-beta-20241120-080738-bbbe036c",
46
46
  "@blocklet/did-space-js": "^0.5.65",
47
- "@blocklet/env": "1.16.33",
48
- "@blocklet/meta": "1.16.33",
49
- "@blocklet/resolver": "1.16.33",
50
- "@blocklet/sdk": "1.16.33",
51
- "@blocklet/store": "1.16.33",
47
+ "@blocklet/env": "1.16.34-beta-20241120-080738-bbbe036c",
48
+ "@blocklet/meta": "1.16.34-beta-20241120-080738-bbbe036c",
49
+ "@blocklet/resolver": "1.16.34-beta-20241120-080738-bbbe036c",
50
+ "@blocklet/sdk": "1.16.34-beta-20241120-080738-bbbe036c",
51
+ "@blocklet/store": "1.16.34-beta-20241120-080738-bbbe036c",
52
52
  "@fidm/x509": "^1.2.1",
53
53
  "@ocap/mcrypto": "1.18.139",
54
54
  "@ocap/util": "1.18.139",
@@ -106,5 +106,5 @@
106
106
  "jest": "^29.7.0",
107
107
  "unzipper": "^0.10.11"
108
108
  },
109
- "gitHead": "f314706b7a6150adbf6bf700f06d2989981eaf1f"
109
+ "gitHead": "4bc345b51743e28a95bf09f7e0c0740838b39ad3"
110
110
  }