@abtnode/core 1.16.8-beta-186fd5aa → 1.16.8-next-c66e39c7

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.
Files changed (38) hide show
  1. package/lib/api/team.js +42 -62
  2. package/lib/blocklet/manager/disk.js +2 -8
  3. package/lib/blocklet/manager/helper/migrate-application-to-struct-v2.js +5 -5
  4. package/lib/blocklet/storage/backup/blocklet-extras.js +2 -2
  5. package/lib/blocklet/storage/backup/blocklet.js +2 -2
  6. package/lib/index.js +17 -16
  7. package/lib/migrations/1.16.8-component-title.js +1 -1
  8. package/lib/migrations/1.6.9-update-node-info-and-certificate.js +1 -1
  9. package/lib/migrations/index.js +190 -40
  10. package/lib/monitor/node-runtime-monitor.js +2 -29
  11. package/lib/router/helper.js +6 -6
  12. package/lib/router/manager.js +35 -36
  13. package/lib/states/access-key.js +3 -20
  14. package/lib/states/audit-log.js +7 -8
  15. package/lib/states/backup.js +11 -59
  16. package/lib/states/base.js +13 -5
  17. package/lib/states/blocklet-extras.js +11 -8
  18. package/lib/states/blocklet.js +148 -222
  19. package/lib/states/cache.js +3 -21
  20. package/lib/states/connect-account.js +8 -0
  21. package/lib/states/index.js +28 -18
  22. package/lib/states/job.js +8 -0
  23. package/lib/states/migration.js +3 -4
  24. package/lib/states/node.js +104 -145
  25. package/lib/states/notification.js +18 -40
  26. package/lib/states/passport.js +8 -0
  27. package/lib/states/session.js +28 -44
  28. package/lib/states/site.js +32 -39
  29. package/lib/states/user.js +169 -378
  30. package/lib/states/webhook.js +5 -7
  31. package/lib/team/manager.js +108 -116
  32. package/lib/util/blocklet.js +0 -1
  33. package/lib/util/index.js +3 -0
  34. package/lib/util/queue.js +14 -20
  35. package/lib/util/ready.js +1 -1
  36. package/lib/webhook/index.js +6 -4
  37. package/package.json +19 -18
  38. package/lib/states/challenge.js +0 -58
@@ -1,13 +1,55 @@
1
+ /* eslint-disable no-continue */
1
2
  /* eslint-disable no-await-in-loop */
2
3
  const fs = require('fs');
3
4
  const path = require('path');
4
5
  const semver = require('semver');
5
6
  const uniqBy = require('lodash/uniqBy');
6
7
  const logger = require('@abtnode/logger')('@abtnode/core:migration');
8
+ const {
9
+ doSchemaMigration,
10
+ doDataMigration,
11
+ getBlockletModels,
12
+ getServerModels,
13
+ getServiceModels,
14
+ getCertificateManagerModels,
15
+ createSequelize,
16
+ } = require('@abtnode/models');
17
+ const { getDbFilePath } = require('../util');
7
18
 
8
- const BACKUP_FILE_STATE_DB = 'state.json';
19
+ const BACKUP_FILE_DB = 'server.db';
9
20
  const BACKUP_FILE_CONFIG = 'config.yml';
10
21
 
22
+ const MODULES = ['certificate-manager'];
23
+ const MAPPINGS = {
24
+ server: {
25
+ access_key: 'AccessKey',
26
+ 'audit-log': 'AuditLog',
27
+ blocklet: 'Blocklet',
28
+ blocklet_extras: 'BlockletExtra',
29
+ cache: 'Cache',
30
+ migration: 'Migration',
31
+ node: 'Server',
32
+ notification: 'Notification',
33
+ routing_rule: 'Site',
34
+ session: 'Session',
35
+ user: 'User',
36
+ webhook: 'WebHook',
37
+ },
38
+ blocklet: {
39
+ user: 'User',
40
+ session: 'Session',
41
+ rbac: 'Rbac',
42
+ },
43
+ service: {
44
+ message: 'Message',
45
+ },
46
+ 'certificate-manager': {
47
+ account: 'Account',
48
+ certificate: 'Certificate',
49
+ 'http-challenge': 'HttpChallenge',
50
+ },
51
+ };
52
+
11
53
  const getMigrationScripts = (scriptsDir) => {
12
54
  const files = fs.readdirSync(scriptsDir);
13
55
  const scripts = files
@@ -36,23 +78,17 @@ const getMigrationScripts = (scriptsDir) => {
36
78
  return sorted;
37
79
  };
38
80
 
39
- // TODO: enter upgrading mode
40
- const doBackup = async ({ states, dataDir, configFile, printInfo, printSuccess }) => {
81
+ const doBackup = async ({ dataDir, configFile, printInfo, printSuccess }) => {
41
82
  printInfo('Backing up state db and config before migration...');
42
- const data = {};
43
- const keys = Object.keys(states);
44
- for (let i = 0; i < keys.length; i++) {
45
- const key = keys[i];
46
- const state = states[key];
47
- data[key] = await state.asyncDB.find({});
48
- }
49
83
 
50
84
  const backupDir = path.join(dataDir, 'migration', Date.now().toString());
51
85
  fs.mkdirSync(backupDir, { recursive: true });
52
86
 
53
- const stateBackup = path.join(backupDir, BACKUP_FILE_STATE_DB);
54
- fs.writeFileSync(stateBackup, JSON.stringify(data, null, 2));
55
- if (configFile && fs.existsSync(configFile)) {
87
+ const dbFile = path.join(dataDir, 'core/server.db');
88
+ if (fs.existsSync(dbFile)) {
89
+ fs.copyFileSync(dbFile, path.join(backupDir, BACKUP_FILE_DB));
90
+ }
91
+ if (fs.existsSync(configFile)) {
56
92
  fs.copyFileSync(configFile, path.join(backupDir, BACKUP_FILE_CONFIG));
57
93
  }
58
94
 
@@ -60,47 +96,28 @@ const doBackup = async ({ states, dataDir, configFile, printInfo, printSuccess }
60
96
  return backupDir;
61
97
  };
62
98
 
63
- // TODO: exit upgrading mode
64
- const doRestore = async ({ states, configFile, backupPath, printInfo, printSuccess }) => {
99
+ const doRestore = async ({ dataDir, configFile, backupPath, printInfo, printSuccess }) => {
65
100
  printInfo('Restoring when migration failed...');
66
101
 
67
- const stateBackup = path.join(backupPath, BACKUP_FILE_STATE_DB);
102
+ const dbBackup = path.join(backupPath, BACKUP_FILE_DB);
68
103
  const configBackup = path.join(backupPath, BACKUP_FILE_CONFIG);
69
104
 
70
105
  // Validate backup
71
106
  if (fs.existsSync(backupPath) === false) {
72
107
  throw new Error(`Backup folder does not exist: ${backupPath}`);
73
108
  }
74
- if (fs.existsSync(stateBackup) === false) {
75
- throw new Error(`Backup file for state does not exist: ${stateBackup}`);
109
+ if (fs.existsSync(dbBackup) === false) {
110
+ throw new Error(`Backup file for state does not exist: ${dbBackup}`);
76
111
  }
77
112
  if (configFile && fs.existsSync(configBackup) === false) {
78
113
  throw new Error(`Backup file for config does not exist: ${configBackup}`);
79
114
  }
80
115
 
81
116
  // Restore state db
82
- let backup = null;
83
- try {
84
- backup = JSON.parse(fs.readFileSync(stateBackup));
85
- } catch (err) {
86
- throw new Error(`Failed to read and parse backup file: ${stateBackup}, ${err.message}`);
87
- }
88
- const keys = Object.keys(states);
89
- for (let i = 0; i < keys.length; i++) {
90
- const key = keys[i];
91
- const state = states[key];
92
- if (Array.isArray(backup[key])) {
93
- await state.asyncDB.remove({}, { multi: true });
94
- await state.asyncDB.insert(backup[key]);
95
- } else {
96
- throw new Error(`Invalid backup for state ${key}`);
97
- }
98
- }
117
+ fs.copyFileSync(dbBackup, path.join(dataDir, 'core/server.db'));
99
118
 
100
119
  // Restore config
101
- if (configFile) {
102
- fs.copyFileSync(configBackup, configFile);
103
- }
120
+ fs.copyFileSync(configBackup, configFile);
104
121
 
105
122
  printSuccess('State db and config was successfully restored!');
106
123
  };
@@ -154,7 +171,7 @@ const runMigrationScripts = async ({
154
171
 
155
172
  let backupPath = null;
156
173
  try {
157
- backupPath = await doBackup({ node, states, config, dataDir, configFile, printInfo, printSuccess, printError });
174
+ backupPath = await doBackup({ dataDir, configFile, printInfo, printSuccess });
158
175
  } catch (err) {
159
176
  printError(`Failed to backup state db due to ${err.message}, abort!`);
160
177
  return false;
@@ -177,7 +194,7 @@ const runMigrationScripts = async ({
177
194
  printError(`Failed to execute migration script: ${script}, error: ${err.message}`);
178
195
 
179
196
  try {
180
- await doRestore({ node, states, config, configFile, dataDir, printInfo, printSuccess, printError, backupPath });
197
+ await doRestore({ configFile, dataDir, printInfo, printSuccess, backupPath });
181
198
  } catch (err2) {
182
199
  printError(`Failed to restore state db due to: ${err2.message}`);
183
200
  }
@@ -189,9 +206,142 @@ const runMigrationScripts = async ({
189
206
  return true;
190
207
  };
191
208
 
209
+ const runSchemaMigrations = async ({
210
+ dataDir,
211
+ blocklets = [],
212
+ printInfo = console.info, // eslint-disable-line
213
+ printSuccess = console.info, // eslint-disable-line
214
+ }) => {
215
+ // migrate server schema
216
+ let filePath = getDbFilePath(path.join(dataDir, 'core/server.db'));
217
+ await doSchemaMigration(filePath, 'server');
218
+ printSuccess(`Server schema successfully migrated: ${filePath}`);
219
+
220
+ // migrate service schema
221
+ filePath = getDbFilePath(path.join(dataDir, 'services/service.db'));
222
+ await doSchemaMigration(filePath, 'service');
223
+ printSuccess(`Service schema successfully migrated: ${filePath}`);
224
+
225
+ // migrate blocklet schema
226
+ for (let i = 0; i < blocklets.length; i++) {
227
+ const blocklet = blocklets[i];
228
+ const env = blocklet.environments.find((x) => x.key === 'BLOCKLET_DATA_DIR');
229
+ if (env) {
230
+ filePath = getDbFilePath(path.join(env.value, 'blocklet.db'));
231
+ await doSchemaMigration(filePath, 'blocklet');
232
+ printSuccess(`Blocklet schema successfully migrated: ${blocklet.appPid}: ${filePath}`);
233
+ } else {
234
+ printInfo(`Skip migrate schema for blocklet: ${blocklet.appPid}`);
235
+ }
236
+ }
237
+
238
+ // migrate certificate manager schema
239
+ for (let i = 0; i < MODULES.length; i++) {
240
+ filePath = getDbFilePath(path.join(dataDir, `modules/${MODULES[i]}/module.db`));
241
+ await doSchemaMigration(filePath, MODULES[i]);
242
+ printSuccess(`${MODULES[i]} schema successfully migrated: ${filePath}`);
243
+ }
244
+ };
245
+
246
+ const runDataMigrations = async ({
247
+ dataDir,
248
+ blocklets = [],
249
+ printInfo = console.info, // eslint-disable-line
250
+ printSuccess = console.info, // eslint-disable-line
251
+ printError = console.error,
252
+ }) => {
253
+ // migrate server data
254
+ await doDataMigration({
255
+ srcDir: path.join(dataDir, 'core'),
256
+ dbFile: path.join(dataDir, 'core/server.db'),
257
+ mapping: MAPPINGS.server,
258
+ models: getServerModels(),
259
+ printInfo,
260
+ printError,
261
+ printSuccess,
262
+ });
263
+ printSuccess('Server data successfully migrated');
264
+
265
+ // migrate service data
266
+ await doDataMigration({
267
+ srcDir: path.join(dataDir, 'services'),
268
+ dbFile: path.join(dataDir, 'services/service.db'),
269
+ models: getServiceModels(),
270
+ mapping: MAPPINGS.service,
271
+ printInfo,
272
+ printError,
273
+ printSuccess,
274
+ });
275
+ printSuccess('Service data successfully migrated');
276
+
277
+ // migrate blocklet data
278
+ for (let i = 0; i < blocklets.length; i++) {
279
+ const blocklet = blocklets[i];
280
+ const env = blocklet.environments.find((x) => x.key === 'BLOCKLET_DATA_DIR');
281
+ if (env) {
282
+ await doDataMigration({
283
+ srcDir: path.join(env.value),
284
+ dbFile: path.join(env.value, 'blocklet.db'),
285
+ models: getBlockletModels(),
286
+ mapping: MAPPINGS.blocklet,
287
+ printInfo,
288
+ printError,
289
+ printSuccess,
290
+ });
291
+ printSuccess(`Blocklet data successfully migrated: ${blocklet.appPid}`);
292
+ } else {
293
+ printInfo(`Skip migrate data for blocklet: ${blocklet.appPid}`);
294
+ }
295
+ }
296
+
297
+ // migrate certificate manager schema
298
+ for (let i = 0; i < MODULES.length; i++) {
299
+ await doDataMigration({
300
+ srcDir: path.join(dataDir, `modules/${MODULES[i]}/db`),
301
+ dbFile: path.join(dataDir, `modules/${MODULES[i]}/module.db`),
302
+ models: getCertificateManagerModels(),
303
+ mapping: MAPPINGS[MODULES[i]],
304
+ printInfo,
305
+ printError,
306
+ printSuccess,
307
+ });
308
+ printSuccess(`${MODULES[i]} data successfully migrated`);
309
+ }
310
+ };
311
+
312
+ const closeDatabaseConnections = async ({
313
+ dataDir,
314
+ blocklets = [],
315
+ printInfo = console.info, // eslint-disable-line
316
+ }) => {
317
+ const dataFiles = [
318
+ getDbFilePath(path.join(dataDir, 'core/server.db')),
319
+ getDbFilePath(path.join(dataDir, 'services/service.db')),
320
+ ];
321
+ for (let i = 0; i < blocklets.length; i++) {
322
+ const blocklet = blocklets[i];
323
+ const env = blocklet.environments.find((x) => x.key === 'BLOCKLET_DATA_DIR');
324
+ if (env) {
325
+ dataFiles.push(getDbFilePath(path.join(env.value, 'blocklet.db')));
326
+ }
327
+ }
328
+ for (let i = 0; i < MODULES.length; i++) {
329
+ dataFiles.push(getDbFilePath(path.join(dataDir, `modules/${MODULES[i]}/module.db`)));
330
+ }
331
+
332
+ const connections = dataFiles.map((x) => createSequelize(x));
333
+ connections.forEach((x) => {
334
+ x.close();
335
+ printInfo(`Closed database connection: ${x}`);
336
+ });
337
+ };
338
+
192
339
  module.exports = {
193
340
  getMigrationScripts,
194
341
  runMigrationScripts,
342
+ runSchemaMigrations,
343
+ runDataMigrations,
344
+ closeDatabaseConnections,
195
345
  doBackup,
196
346
  doRestore,
197
347
  };
@@ -2,7 +2,7 @@ const EventEmitter = require('events');
2
2
  const pick = require('lodash/pick');
3
3
  const cloneDeep = require('lodash/cloneDeep');
4
4
 
5
- const { PROCESS_NAME_DAEMON, PROCESS_NAME_PROXY, PROCESS_NAME_SERVICE, EVENTS } = require('@abtnode/constant');
5
+ const { PROCESS_NAME_DAEMON, PROCESS_NAME_SERVICE, EVENTS } = require('@abtnode/constant');
6
6
  const defaultLogger = require('@abtnode/logger')('@abtnode/util:node-runtime-info');
7
7
  const pm2 = require('@abtnode/util/lib/async-pm2');
8
8
 
@@ -45,7 +45,6 @@ const getProcessInfo = (processId, { returnList } = {}) =>
45
45
  // mem: number;
46
46
  // daemonMem: number;
47
47
  // serviceMem: number;
48
- // dbMem: number;
49
48
  // };
50
49
 
51
50
  // type History = Array<NodeHistoryItem>;
@@ -57,7 +56,6 @@ const getProcessInfo = (processId, { returnList } = {}) =>
57
56
  // disks: [];
58
57
  // daemon: RuntimeInfo
59
58
  // service: ServiceRuntimeInfo
60
- // db: RuntimeInfo
61
59
 
62
60
  // type MonitorData = {
63
61
  // realtime: Realtime;
@@ -72,7 +70,6 @@ const DEFAULT_DATA = {
72
70
  disks: [],
73
71
  daemon: {},
74
72
  service: {},
75
- db: {},
76
73
  },
77
74
  history: [],
78
75
  };
@@ -123,13 +120,8 @@ class NodeRuntimeMonitor extends EventEmitter {
123
120
  this.logger.error(`failed to get daemon info: ${error.message}`);
124
121
  })
125
122
  : Promise.resolve(),
126
- process.env.NODE_ENV !== 'development'
127
- ? getProcessInfo(PROCESS_NAME_PROXY).catch((error) => {
128
- this.logger.error(`failed to get db info: ${error.message}`);
129
- })
130
- : Promise.resolve(),
131
123
  ])
132
- .then(([{ value: sysInfo }, { value: serviceInfos }, { value: daemonInfo }, { value: dbInfo }]) => {
124
+ .then(([{ value: sysInfo }, { value: serviceInfos }, { value: daemonInfo }]) => {
133
125
  this.inProgress = false;
134
126
 
135
127
  const historyItem = {
@@ -138,7 +130,6 @@ class NodeRuntimeMonitor extends EventEmitter {
138
130
  mem: 0,
139
131
  daemonMem: 0,
140
132
  serviceMem: 0,
141
- dbMem: 0,
142
133
  };
143
134
 
144
135
  if (sysInfo) {
@@ -186,24 +177,6 @@ class NodeRuntimeMonitor extends EventEmitter {
186
177
  this.data.realtime.daemon = {};
187
178
  }
188
179
 
189
- if (dbInfo) {
190
- const proc = dbInfo;
191
-
192
- const runtimeInfo = {
193
- pid: proc.pid,
194
- uptime: proc.pm2_env ? +new Date() - Number(proc.pm2_env.pm_uptime) : 0,
195
- memoryUsage: proc.monit.memory,
196
- cpuUsage: proc.monit.cpu,
197
- status: proc.pm2_env ? proc.pm2_env.status : null,
198
- };
199
-
200
- this.data.realtime.db = runtimeInfo;
201
-
202
- historyItem.dbMem = runtimeInfo.memoryUsage;
203
- } else {
204
- this.data.realtime.db = {};
205
- }
206
-
207
180
  this.logger.info('server runtime info', historyItem);
208
181
 
209
182
  this._push(historyItem);
@@ -836,7 +836,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
836
836
  domainAliases.push(...dashboardAliasDomains);
837
837
 
838
838
  try {
839
- const result = await siteState.update({ _id: dashboardSite.id }, { $set: { domainAliases } });
839
+ const result = await siteState.update({ id: dashboardSite.id }, { $set: { domainAliases } });
840
840
 
841
841
  updatedResult.push(result);
842
842
  } catch (error) {
@@ -992,7 +992,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
992
992
  * add rules in wellknown site
993
993
  * This function should be called after `ensureDashboardRouting`
994
994
  *
995
- * @returns {boolean} if routing changed
995
+ * @returns {Promise<boolean>} if routing changed
996
996
  */
997
997
  const ensureBlockletRouting = async (blocklet, context = {}) => {
998
998
  const nodeInfo = await nodeState.read();
@@ -1008,7 +1008,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1008
1008
  * remove custom rules of blocklet in old interface does not exist
1009
1009
  * update custom rules of blocklet
1010
1010
  *
1011
- * @returns {boolean} if routing changed
1011
+ * @returns {Promise<boolean>} if routing changed
1012
1012
  */
1013
1013
  const ensureBlockletCustomRouting = async (blocklet) => {
1014
1014
  // Only one blocklet web interface can be declared since router 2.0
@@ -1053,7 +1053,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1053
1053
  try {
1054
1054
  // eslint-disable-next-line no-await-in-loop
1055
1055
  await states.site.update(
1056
- { _id: site.id },
1056
+ { id: site.id },
1057
1057
  { $set: { rules: site.rules.filter((x) => rulesToRemove.includes(x.id) === false) } }
1058
1058
  );
1059
1059
  changed = true;
@@ -1075,7 +1075,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1075
1075
  * Update routing for blocklet when blocklet is upgraded
1076
1076
  * This function should be called after `ensureDashboardRouting`
1077
1077
  *
1078
- * @returns {boolean} if routing changed
1078
+ * @returns {Promise<boolean>} if routing changed
1079
1079
  */
1080
1080
  const ensureBlockletRoutingForUpgrade = async (blocklet, context = {}) => {
1081
1081
  await routerManager.deleteRoutingRulesItemByDid(
@@ -1092,7 +1092,7 @@ module.exports = function getRouterHelpers({ dataDirs, routingSnapshot, routerMa
1092
1092
  /**
1093
1093
  * Remove routing for blocklet
1094
1094
  *
1095
- * @returns {boolean} if routing changed
1095
+ * @returns {Promise<boolean>} if routing changed
1096
1096
  */
1097
1097
  const removeBlockletRouting = async (blocklet, context = {}) => {
1098
1098
  const ruleChanged = await routerManager.deleteRoutingRulesItemByDid({ did: blocklet.meta.did }, context);
@@ -134,7 +134,7 @@ class RouterManager extends EventEmitter {
134
134
 
135
135
  // eslint-disable-next-line no-unused-vars
136
136
  async deleteRoutingSite({ id }, context = {}) {
137
- const site = await states.site.findOne({ _id: id });
137
+ const site = await states.site.findOne({ id });
138
138
  if ([DOMAIN_FOR_IP_SITE, DOMAIN_FOR_DEFAULT_SITE].includes(site.domain)) {
139
139
  // eslint-disable-next-line quotes
140
140
  throw new Error("Can not delete this site because it's protected");
@@ -143,7 +143,7 @@ class RouterManager extends EventEmitter {
143
143
  // validate router config
144
144
  await this.validateRouterConfig('deleteRoutingSite', { id });
145
145
 
146
- const removedSiteCount = await states.site.remove({ _id: id });
146
+ const removedSiteCount = await states.site.remove({ id });
147
147
 
148
148
  if (removedSiteCount === 0) {
149
149
  throw new Error(`remove site ${id} failed`);
@@ -156,7 +156,7 @@ class RouterManager extends EventEmitter {
156
156
  // eslint-disable-next-line no-unused-vars
157
157
  async updateRoutingSite(params, context = {}) {
158
158
  const site = await validateUpdateSite(params, context);
159
- const existed = await states.site.findOne({ _id: site.id });
159
+ const existed = await states.site.findOne({ id: site.id });
160
160
  if (!existed) {
161
161
  throw new Error('Can not update non-existing site');
162
162
  }
@@ -169,30 +169,27 @@ class RouterManager extends EventEmitter {
169
169
 
170
170
  if (site.domain) {
171
171
  const newDomain = site.domain;
172
- const ruleCountInDB = await states.site.count({
173
- $or: [{ domain: newDomain }, { domainAliases: newDomain }, { 'domainAliases.value': newDomain }],
174
- });
175
-
176
- if (ruleCountInDB > 0) {
172
+ const exist = await states.site.domainExists(newDomain);
173
+ if (exist) {
177
174
  throw new Error(`Site ${newDomain} already exists`);
178
175
  }
179
176
 
180
177
  updateSet.domain = newDomain;
181
178
  }
182
179
 
183
- const updated = await states.site.update({ _id: site.id }, { $set: updateSet }, { multi: false, upsert: false });
180
+ const updated = await states.site.update({ id: site.id }, { $set: updateSet });
184
181
 
185
182
  logger.info('router.site.updated', { site, updated });
186
183
  this.emit('router.site.updated', site.id);
187
184
 
188
- const dbSite = await states.site.findOne({ _id: site.id });
185
+ const dbSite = await states.site.findOne({ id: site.id });
189
186
  await attachRuntimeDomainAliases({ sites: dbSite, context, node: states.node });
190
187
  return dbSite;
191
188
  }
192
189
 
193
190
  async addDomainAlias({ id, domainAlias: tmpAlias, force }, context = {}) {
194
191
  const domainAlias = await validateAddDomainAlias(tmpAlias, context);
195
- const dbSite = await states.site.findOne({ _id: id });
192
+ const dbSite = await states.site.findOne({ id });
196
193
  if (!dbSite) {
197
194
  throw new Error(`site ${id} does not exist`);
198
195
  }
@@ -211,10 +208,7 @@ class RouterManager extends EventEmitter {
211
208
  }
212
209
 
213
210
  // check domain exists in site alias domain
214
- const aliasDomainSite = await states.site.findOne({
215
- $or: [{ domainAliases: domainAlias }, { 'domainAliases.value': domainAlias }],
216
- });
217
-
211
+ const aliasDomainSite = await states.site.findByDomainAlias(domainAlias);
218
212
  if (aliasDomainSite) {
219
213
  if (!force) {
220
214
  throw new Error(`${domainAlias} already exists`);
@@ -223,13 +217,14 @@ class RouterManager extends EventEmitter {
223
217
  }
224
218
  }
225
219
 
220
+ const doc = await states.site.findOne({ id });
226
221
  const updateResult = await states.site.update(
227
- { _id: id },
228
- { $push: { domainAliases: { value: domainAlias, isProtected: false } } }
222
+ { id },
223
+ { $set: { domainAliases: [...doc.domainAliases, { value: domainAlias, isProtected: false }] } }
229
224
  );
230
225
  logger.debug('add domain alias update result', { id, updateResult, domainAlias });
231
226
 
232
- const newSite = await states.site.findOne({ _id: id });
227
+ const newSite = await states.site.findOne({ id });
233
228
  await attachRuntimeDomainAliases({ sites: newSite, context, node: states.node });
234
229
 
235
230
  return newSite;
@@ -237,7 +232,7 @@ class RouterManager extends EventEmitter {
237
232
 
238
233
  async deleteDomainAlias({ id, domainAlias: tmpAlias }, context = {}) {
239
234
  const domainAlias = await validateAddDomainAlias(tmpAlias, context);
240
- const dbSite = await states.site.findOne({ _id: id });
235
+ const dbSite = await states.site.findOne({ id });
241
236
  if (!dbSite) {
242
237
  throw new Error(`site ${id} does not exist`);
243
238
  }
@@ -250,7 +245,7 @@ class RouterManager extends EventEmitter {
250
245
  return toLower(x.value) !== domainAlias;
251
246
  });
252
247
 
253
- const updateResult = await states.site.update({ _id: id }, { $set: { domainAliases: dbSite.domainAliases } });
248
+ const updateResult = await states.site.update({ id }, { $set: { domainAliases: dbSite.domainAliases } });
254
249
  logger.debug('remove domain alias update result', { id, updateResult, domainAlias });
255
250
 
256
251
  await attachRuntimeDomainAliases({ sites: dbSite, context, node: states.node });
@@ -268,7 +263,7 @@ class RouterManager extends EventEmitter {
268
263
  rule.from.pathPrefix = tempRule.from.pathPrefix;
269
264
  }
270
265
 
271
- const dbSite = await states.site.findOne({ _id: id });
266
+ const dbSite = await states.site.findOne({ id });
272
267
  if (!dbSite) {
273
268
  throw new Error(`site ${id} does not exist`);
274
269
  }
@@ -295,7 +290,7 @@ class RouterManager extends EventEmitter {
295
290
  await states.site.addRuleToSite(id, x);
296
291
  }
297
292
 
298
- const newSite = await states.site.findOne({ _id: id });
293
+ const newSite = await states.site.findOne({ id });
299
294
  await attachRuntimeDomainAliases({ sites: newSite, context, node: states.node });
300
295
 
301
296
  this.emit('router.rule.created', newSite);
@@ -312,8 +307,11 @@ class RouterManager extends EventEmitter {
312
307
  rule.from.pathPrefix = tmpRule.from.pathPrefix;
313
308
  }
314
309
 
315
- const dbSite = await states.site.findOne({ _id: id, 'rules.id': rule.id });
310
+ const dbSite = await states.site.findOne({ id });
316
311
  if (!dbSite) {
312
+ throw new Error(`site ${id} does not exist`);
313
+ }
314
+ if (!dbSite.rules.find((x) => x.id === rule.id)) {
317
315
  throw new Error(`site ${id}, rule ${rule.id} does not exist`);
318
316
  }
319
317
 
@@ -344,9 +342,9 @@ class RouterManager extends EventEmitter {
344
342
  ...(await this.getRulesForMutation(rule)),
345
343
  ];
346
344
 
347
- const updateResult = await states.site.update({ _id: id }, { $set: { rules: newRules } });
345
+ const updateResult = await states.site.update({ id }, { $set: { rules: newRules } });
348
346
  logger.info('update result', { updateResult });
349
- const newSite = await states.site.findOne({ _id: id });
347
+ const newSite = await states.site.findOne({ id });
350
348
 
351
349
  await attachRuntimeDomainAliases({ sites: newSite, context, node: states.node });
352
350
 
@@ -356,7 +354,7 @@ class RouterManager extends EventEmitter {
356
354
  }
357
355
 
358
356
  async deleteRoutingRule({ id, ruleId }, context = {}) {
359
- const tmpRule = await states.site.findOne({ _id: id, 'rules.id': ruleId });
357
+ const tmpRule = await states.site.getSiteByRuleId(id, ruleId);
360
358
  if (!tmpRule) {
361
359
  throw new Error(`rule item ${ruleId} in rule ${id} does not exist`);
362
360
  }
@@ -371,11 +369,14 @@ class RouterManager extends EventEmitter {
371
369
  await this.validateRouterConfig('deleteRoutingRule', { id, ruleId });
372
370
 
373
371
  // 只要有匹配到的查询条件,不管是否删除成功都不会返回 0,所以这里没用 update 的返回值
374
- await states.site.update({ _id: id }, { $pull: { rules: { groupId: ruleId } } });
375
- await states.site.update({ _id: id }, { $pull: { rules: { id: ruleId } } }); // for legacy compatible
372
+ const doc = await states.site.findOne({ id });
373
+ if (doc.rules.some((x) => x.id === ruleId || x.groupId === ruleId)) {
374
+ const newRules = doc.rules.filter((x) => x.id !== ruleId && x.groupId !== ruleId);
375
+ await states.site.update({ id }, { $set: { rules: newRules } });
376
+ }
376
377
 
377
378
  logger.info('router.rule.removed', { id, ruleId });
378
- const newSite = await states.site.findOne({ _id: id });
379
+ const newSite = await states.site.findOne({ id });
379
380
 
380
381
  await attachRuntimeDomainAliases({ sites: newSite, context, node: states.node });
381
382
 
@@ -410,9 +411,8 @@ class RouterManager extends EventEmitter {
410
411
  // eslint-disable-next-line no-unused-vars
411
412
  async deleteRoutingRulesItemByDid({ did, ruleFilter }, context = {}) {
412
413
  logger.info('deleteRoutingRulesItemByDid.did', { did });
413
- const sites = await states.site.find({ 'rules.to.did': did });
414
- if (!Array.isArray(sites)) {
415
- logger.warn('deleteRoutingRulesItemByDid sites is not an array');
414
+ const sites = await states.site.getSitesByBlocklet(did);
415
+ if (!sites.length) {
416
416
  return false;
417
417
  }
418
418
 
@@ -429,7 +429,7 @@ class RouterManager extends EventEmitter {
429
429
  return false;
430
430
  });
431
431
 
432
- tasks.push(states.site.update({ _id: site._id }, { $set: { rules: site.rules } })); // eslint-disable-line no-underscore-dangle
432
+ tasks.push(states.site.update({ id: site.id }, { $set: { rules: site.rules } })); // eslint-disable-line no-underscore-dangle
433
433
  }
434
434
 
435
435
  const result = await Promise.all(tasks);
@@ -461,10 +461,9 @@ class RouterManager extends EventEmitter {
461
461
  // eslint-disable-next-line consistent-return
462
462
  async repopulateRouting({ sites }) {
463
463
  if (Array.isArray(sites) && sites.length) {
464
- const result = await states.site.remove({}, { multi: true });
464
+ const result = await states.site.remove({});
465
465
  logger.info('routing rules all removed', { result });
466
-
467
- await states.site.insert(sites.map((x) => ({ ...x, _id: x.id })));
466
+ await states.site.insertMany(sites.map((x) => ({ ...x, id: x.id })));
468
467
  }
469
468
  }
470
469
 
@@ -18,19 +18,10 @@ const validatePassport = (passport) => {
18
18
 
19
19
  const getUserName = (context) => get(context, 'user.fullName', '');
20
20
 
21
+ /**
22
+ * @extends BaseState<import('@abtnode/models').AccessKeyState>
23
+ */
21
24
  class AccessKeyState extends BaseState {
22
- constructor(baseDir, config = {}) {
23
- super(baseDir, { filename: 'access_key.db', ...config });
24
-
25
- this.onReady(() => {
26
- this.ensureIndex({ fieldName: 'accessKeyId', unique: true }, (error) => {
27
- if (error) {
28
- logger.error('ensure unique index failed', { error });
29
- }
30
- });
31
- });
32
- }
33
-
34
25
  async create(input, context) {
35
26
  const { remark, passport, tag } = input || {};
36
27
 
@@ -62,14 +53,6 @@ class AccessKeyState extends BaseState {
62
53
  };
63
54
  }
64
55
 
65
- async getAccessKeyByTag({ tag } = {}) {
66
- if (!tag) {
67
- throw new Error('tag should not be empty');
68
- }
69
-
70
- return this.findOne({ tag });
71
- }
72
-
73
56
  // eslint-disable-next-line no-unused-vars
74
57
  async list(params, context) {
75
58
  const res = await this.paginate({}, { createdAt: -1 }, { pageSize: 100 });