@did-space/core 0.5.18 → 0.5.20

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.
@@ -1,4 +1,4 @@
1
- import { Model } from 'skypesky-sequelize';
1
+ import { Model } from 'sequelize';
2
2
  /**
3
3
  * @description 存储的是对象的信息,不保存结构,创建之初就确定了,只能增加,删除
4
4
  * @export
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ObjectCollectionRepositoryClass = void 0;
4
- const skypesky_sequelize_1 = require("skypesky-sequelize");
5
- class ObjectCollectionRepositoryClass extends skypesky_sequelize_1.Model {
4
+ const sequelize_1 = require("sequelize");
5
+ class ObjectCollectionRepositoryClass extends sequelize_1.Model {
6
6
  }
7
7
  exports.ObjectCollectionRepositoryClass = ObjectCollectionRepositoryClass;
@@ -1,4 +1,4 @@
1
- import { Model } from 'skypesky-sequelize';
1
+ import { Model } from 'sequelize';
2
2
  /**
3
3
  * @description 存储的是对象的信息,不保存结构,创建之初就确定了,只能增加,删除
4
4
  * @export
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ObjectRepositoryClass = void 0;
4
- const skypesky_sequelize_1 = require("skypesky-sequelize");
5
- class ObjectRepositoryClass extends skypesky_sequelize_1.Model {
4
+ const sequelize_1 = require("sequelize");
5
+ class ObjectRepositoryClass extends sequelize_1.Model {
6
6
  }
7
7
  exports.ObjectRepositoryClass = ObjectRepositoryClass;
@@ -0,0 +1,21 @@
1
+ import { Model } from 'sequelize';
2
+ import type { LiteralUnion } from 'type-fest';
3
+ export declare class SpaceRepositoryClass extends Model<SpaceRepositoryClass, SpaceRepositoryClass> {
4
+ id: string;
5
+ drive: string;
6
+ did: string;
7
+ type: LiteralUnion<'default' | 'buy', string>;
8
+ name: string;
9
+ description: string;
10
+ size: number;
11
+ assetDid: string;
12
+ metadata: {
13
+ usageReportId?: string;
14
+ usedUnit?: number;
15
+ };
16
+ createAt: Date;
17
+ updateAt: Date | string;
18
+ expireAt: Date;
19
+ ownerDid: string;
20
+ }
21
+ export type SpaceRepository = typeof SpaceRepositoryClass;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SpaceRepositoryClass = void 0;
4
+ const sequelize_1 = require("sequelize");
5
+ class SpaceRepositoryClass extends sequelize_1.Model {
6
+ }
7
+ exports.SpaceRepositoryClass = SpaceRepositoryClass;
@@ -1,4 +1,4 @@
1
- import { Model } from 'skypesky-sequelize';
1
+ import { Model } from 'sequelize';
2
2
  import { ObjectModel } from './object';
3
3
  export interface TreeModel {
4
4
  /**
@@ -17,7 +17,6 @@ export interface TreeModel {
17
17
  spaceDid: string;
18
18
  /**
19
19
  * @description 当且仅当,指向文件夹的时候才为空
20
- * @type {string}
21
20
  * @column {DataTypes.CHAR(64)}
22
21
  * @memberof Tree
23
22
  */
@@ -25,11 +24,10 @@ export interface TreeModel {
25
24
  /**
26
25
  * @description 绑定对象的上一级目录的 id
27
26
  * @example /abc/
28
- * @type {string}
29
27
  * @column {DataTypes.BIGINT.UNSIGNED}
30
28
  * @memberof Tree
31
29
  */
32
- parentId: string;
30
+ parentId: null | string;
33
31
  /**
34
32
  * @description 等价于文件夹和文件的路径,注意不包含 SpaceDid
35
33
  * @example /app 或 /app/objects
@@ -60,14 +58,16 @@ export interface TreeModel {
60
58
  * @column {DataTypes.DATE}
61
59
  * @memberof Tree
62
60
  */
63
- createdAt: string;
61
+ createdAt: Date | string;
64
62
  /**
65
63
  * @description
66
64
  * @type {string}
67
65
  * @column {DataTypes.DATE}
68
66
  * @memberof Tree
69
67
  */
70
- updatedAt: string;
68
+ updatedAt: Date | string;
69
+ size?: number;
70
+ count?: number;
71
71
  }
72
72
  export interface TreeModelMeta {
73
73
  }
@@ -80,10 +80,12 @@ export declare class TreeRepositoryClass extends Model<TreeModel, CreationTreeMo
80
80
  key: string;
81
81
  type: number;
82
82
  meta: TreeModelMeta;
83
- createdAt: string;
84
- updatedAt: string;
83
+ createdAt: Date;
84
+ updatedAt: Date;
85
+ size: number;
86
+ count: number;
85
87
  Object: ObjectModel;
86
- static deepCreate(data: CreationTreeModel): Promise<TreeModel>;
88
+ static deepCreate(_data: CreationTreeModel): Promise<TreeModel>;
87
89
  [key: string]: any;
88
90
  }
89
91
  export type TreeRepository = typeof TreeRepositoryClass;
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TreeModelDefaultMeta = exports.TreeModelType = exports.TreeRepositoryClass = void 0;
4
- const skypesky_sequelize_1 = require("skypesky-sequelize");
5
- class TreeRepositoryClass extends skypesky_sequelize_1.Model {
4
+ const sequelize_1 = require("sequelize");
5
+ class TreeRepositoryClass extends sequelize_1.Model {
6
6
  // 不需要实现,只需要类型提示而已
7
7
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
8
- static deepCreate(data) {
8
+ static deepCreate(_data) {
9
9
  throw new Error('not implemented');
10
10
  }
11
11
  }
@@ -1,5 +1,7 @@
1
+ /// <reference types="node" />
2
+ import type EventEmitter from 'events';
1
3
  import { BaseSpaceProtocol } from './base-space';
2
4
  import { DriverProtocol } from './driver';
3
- export interface SpaceProtocol extends BaseSpaceProtocol {
5
+ export interface SpaceProtocol extends BaseSpaceProtocol, EventEmitter {
4
6
  readonly driver: DriverProtocol;
5
7
  }
@@ -14,7 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.GlobalSpace = void 0;
16
16
  const lodash_1 = require("lodash");
17
- const skypesky_sequelize_1 = require("skypesky-sequelize");
17
+ const sequelize_1 = require("sequelize");
18
18
  const mime_types_1 = __importDefault(require("mime-types"));
19
19
  const debug_1 = __importDefault(require("debug"));
20
20
  const p_all_1 = __importDefault(require("p-all"));
@@ -118,11 +118,11 @@ class GlobalSpace {
118
118
  objectId: hash,
119
119
  };
120
120
  debug('delete.$where', JSON.stringify(where));
121
- const count = yield this.treeRepository.count({
121
+ const treeRefCount = yield this.treeRepository.count({
122
122
  where,
123
123
  });
124
- debug('delete.$count', count);
125
- if (count) {
124
+ debug('delete.$treeRefCount', treeRefCount);
125
+ if (treeRefCount) {
126
126
  yield this.objectCollectionRepository.destroy({ where: { id: hash } });
127
127
  return;
128
128
  }
@@ -143,7 +143,7 @@ class GlobalSpace {
143
143
  const objects = yield this.objectCollectionRepository.findAll({
144
144
  where: {
145
145
  createdAt: {
146
- [skypesky_sequelize_1.Op.lt]: (0, dayjs_1.default)().subtract(10, 'm').toDate(),
146
+ [sequelize_1.Op.lt]: (0, dayjs_1.default)().subtract(10, 'm').toDate(),
147
147
  },
148
148
  },
149
149
  attributes: ['id'],
@@ -1,23 +1,27 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { Stream } from 'stream';
4
+ import EventEmitter from 'events';
3
5
  import { SpaceConfig } from '../configuration';
4
- import { Object, Data } from '../meta';
6
+ import type { Object, Data } from '../meta';
5
7
  import { AppSpaceOptions, DeleteOptions, DriverProtocol, GetHashOptions, KeyStatus, ListOptions, ListsOptions, PermissionOptions, ReadAsOwnerOptions, ReadOptions, SpaceProtocol, WriteAsOwnerOptions, WriteOptions } from '../protocols';
6
8
  import { ObjectCollectionRepository, ObjectRepository, TreeRepository } from '../model';
7
9
  import { GlobalSpace } from './global-space';
10
+ import type { SpaceRepository } from '../model/space';
8
11
  export type ObjectSpaceOptions = {
9
12
  driver: DriverProtocol;
10
13
  spaceDid: string;
11
14
  treeRepository: TreeRepository;
12
15
  objectRepository: ObjectRepository;
13
16
  objectCollectionRepository: ObjectCollectionRepository;
17
+ spaceRepository: SpaceRepository;
14
18
  /**
15
19
  * @description 忽略存储容量限制吗?
16
20
  * @type {(false | true)}
17
21
  */
18
22
  ignoreStorageLimit?: false | true;
19
23
  };
20
- export declare class ObjectSpace implements SpaceProtocol {
24
+ export declare class ObjectSpace extends EventEmitter implements SpaceProtocol {
21
25
  readonly options: ObjectSpaceOptions;
22
26
  readonly globalSpace: GlobalSpace;
23
27
  readonly driver: DriverProtocol;
@@ -42,7 +46,6 @@ export declare class ObjectSpace implements SpaceProtocol {
42
46
  */
43
47
  destroyAppSpace(options: AppSpaceOptions): Promise<void>;
44
48
  getAppSpacePath(options: AppSpaceOptions): Promise<string>;
45
- private verifySpace;
46
49
  write(options: WriteOptions): Promise<void>;
47
50
  delete(options: DeleteOptions): Promise<void>;
48
51
  read(options: ReadOptions): Promise<Stream>;
@@ -75,8 +78,8 @@ export declare class ObjectSpace implements SpaceProtocol {
75
78
  * @memberof ObjectSpace
76
79
  */
77
80
  writeAsOwner(key: string, data: Data, options?: WriteAsOwnerOptions): Promise<void>;
78
- private updateAsOwner;
79
- private createAsOwner;
81
+ private _updateAsOwner;
82
+ private _createAsOwner;
80
83
  private updateMetadata;
81
84
  deleteAsOwner(key: string): Promise<void>;
82
85
  readAsOwner(key: string, options?: ReadAsOwnerOptions): Promise<Stream>;
@@ -14,14 +14,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.ObjectSpace = void 0;
16
16
  const debug_1 = __importDefault(require("debug"));
17
- const skypesky_sequelize_1 = require("skypesky-sequelize");
17
+ const sequelize_1 = require("sequelize");
18
18
  const js_yaml_1 = __importDefault(require("js-yaml"));
19
19
  const path_1 = require("path");
20
20
  const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
21
21
  const isUndefined_1 = __importDefault(require("lodash/isUndefined"));
22
22
  const omit_1 = __importDefault(require("lodash/omit"));
23
- const xbytes_1 = __importDefault(require("xbytes"));
24
23
  const lodash_1 = require("lodash");
24
+ const events_1 = __importDefault(require("events"));
25
25
  const configuration_1 = require("../configuration");
26
26
  const model_1 = require("../model");
27
27
  const utils_1 = require("../utils");
@@ -30,8 +30,9 @@ const constants_1 = require("../constants");
30
30
  const stream_1 = require("../utils/stream");
31
31
  const global_space_1 = require("./global-space");
32
32
  const debug = (0, debug_1.default)('@did-space/core:ObjectSpace');
33
- class ObjectSpace {
33
+ class ObjectSpace extends events_1.default {
34
34
  constructor(options) {
35
+ super();
35
36
  const { error } = schemas_1.ObjectSpaceOptionsSchema.validate(options, {
36
37
  allowUnknown: true,
37
38
  stripUnknown: true,
@@ -59,15 +60,14 @@ class ObjectSpace {
59
60
  isSpaceCreated() {
60
61
  return __awaiter(this, void 0, void 0, function* () {
61
62
  const where = {
62
- spaceDid: this.options.spaceDid,
63
- key: '/config.yml',
63
+ did: this.options.spaceDid,
64
64
  };
65
65
  debug('isSpaceCreated.before', JSON.stringify(where));
66
- const created = Boolean(yield this.options.treeRepository.count({
66
+ const created = yield this.options.spaceRepository.count({
67
67
  where,
68
- }));
68
+ });
69
69
  debug('isSpaceCreated.after', JSON.stringify({ created }));
70
- return created;
70
+ return Boolean(created);
71
71
  });
72
72
  }
73
73
  /**
@@ -118,34 +118,6 @@ class ObjectSpace {
118
118
  // @ts-expect-error
119
119
  return (0, path_1.join)(`/${constants_1.APPS}`, `${options.appDid}/`);
120
120
  }
121
- verifySpace(size = 0) {
122
- var _a, _b;
123
- return __awaiter(this, void 0, void 0, function* () {
124
- debug('verifySpace.before', { size });
125
- // 创建的时候怎么做空间大小检测呢?目前是跳过检测的
126
- if (!(yield this.isSpaceCreated())) {
127
- return;
128
- }
129
- // 如果忽略了存储限制,直接不用校验了
130
- if (this.options.ignoreStorageLimit) {
131
- return;
132
- }
133
- const [did, capacity, usedCapacity] = yield Promise.all([
134
- this.options.spaceDid,
135
- // @FIXME: 此处应该用 cache 层的数据,可以加速查询
136
- this.get('size'),
137
- this.getSpaceSize(),
138
- ]);
139
- const whiteList = ((_b = (_a = process.env) === null || _a === void 0 ? void 0 : _a.SPACE_WHITE_LIST) !== null && _b !== void 0 ? _b : '')
140
- .split(',')
141
- .map((s) => s.trim())
142
- .filter(Boolean);
143
- debug('verifySpace.before', { did, capacity, usedCapacity });
144
- if (capacity && usedCapacity + size >= capacity && !whiteList.includes(did)) {
145
- throw new Error(`Insufficient free space, total capacity is ${(0, xbytes_1.default)(capacity, { iec: true })}, used capacity is ${(0, xbytes_1.default)(usedCapacity, { iec: true })}`);
146
- }
147
- });
148
- }
149
121
  write(options) {
150
122
  return __awaiter(this, void 0, void 0, function* () {
151
123
  debug('write.before', JSON.stringify((0, omit_1.default)(options, 'data')));
@@ -156,10 +128,6 @@ class ObjectSpace {
156
128
  if (error) {
157
129
  throw error;
158
130
  }
159
- // @note: 只有新增的时候才会触发检测
160
- if (!(yield this.exists(options))) {
161
- yield this.verifySpace(options === null || options === void 0 ? void 0 : options.size);
162
- }
163
131
  const key = (0, path_1.join)(yield this.getAppSpacePath(options), options.key);
164
132
  // @ts-expect-error
165
133
  yield this.writeAsOwner(key, options.data, options);
@@ -195,7 +163,11 @@ class ObjectSpace {
195
163
  if (!(yield this.exists(options))) {
196
164
  throw new Error(`Object(${key}) not exists`);
197
165
  }
198
- const tree = yield this.options.treeRepository.findOne({ where });
166
+ const tree = yield this.options.treeRepository.findOne({
167
+ where,
168
+ attributes: ['objectId'],
169
+ raw: true,
170
+ });
199
171
  return tree.objectId;
200
172
  });
201
173
  }
@@ -215,6 +187,7 @@ class ObjectSpace {
215
187
  debug('listsOneLevel.before', JSON.stringify(options));
216
188
  const parentTree = yield this.options.treeRepository.findOne({
217
189
  where,
190
+ attributes: ['id'],
218
191
  raw: true,
219
192
  });
220
193
  debug('listsOneLevel.$parentTree', JSON.stringify(parentTree, null, 2));
@@ -228,7 +201,6 @@ class ObjectSpace {
228
201
  return Promise.all(trees.map((x) => __awaiter(this, void 0, void 0, function* () {
229
202
  const absolutePath = (0, path_1.join)(x.spaceDid, x.key);
230
203
  if (x.type === model_1.TreeModelType.FOLDER) {
231
- // @FIXME: 如果追求极速,此处是一个优化的点,文件夹不一定需要看到 更新时间和大小,S3 就是这么做的,默认是不展示的
232
204
  const { size, lastModified } = yield this.getStatusAsOwner(x.key);
233
205
  return {
234
206
  key: x.key,
@@ -263,7 +235,7 @@ class ObjectSpace {
263
235
  const where = {
264
236
  spaceDid: this.options.spaceDid,
265
237
  key: {
266
- [skypesky_sequelize_1.Op.like]: `${options.key}%`,
238
+ [sequelize_1.Op.like]: `${options.key}%`,
267
239
  },
268
240
  type: model_1.TreeModelType.FILE,
269
241
  };
@@ -327,20 +299,20 @@ class ObjectSpace {
327
299
  spaceDid: this.options.spaceDid,
328
300
  key: options.key,
329
301
  };
330
- const x = yield this.options.treeRepository.findOne({
302
+ const tree = yield this.options.treeRepository.findOne({
331
303
  where,
332
304
  include: this.options.objectRepository,
333
305
  });
334
306
  return {
335
- key: x.key,
336
- name: (0, path_1.basename)(x.key),
337
- isDir: x.type === model_1.TreeModelType.FOLDER,
338
- size: x.type === model_1.TreeModelType.FOLDER ? 0 : x.Object.size,
339
- lastModified: new Date(x.updatedAt).getTime(),
307
+ key: tree.key,
308
+ name: (0, path_1.basename)(tree.key),
309
+ isDir: tree.type === model_1.TreeModelType.FOLDER,
310
+ size: tree.type === model_1.TreeModelType.FOLDER ? 0 : tree.Object.size,
311
+ lastModified: new Date(tree.updatedAt).getTime(),
340
312
  editable: true,
341
- mimeType: x.type === model_1.TreeModelType.FOLDER ? null : x.Object.meta.mimeType,
342
- absolutePath: (0, path_1.join)(x.spaceDid, x.key),
343
- metadata: x.meta,
313
+ mimeType: tree.type === model_1.TreeModelType.FOLDER ? null : tree.Object.meta.mimeType,
314
+ absolutePath: (0, path_1.join)(tree.spaceDid, tree.key),
315
+ metadata: tree.meta,
344
316
  };
345
317
  });
346
318
  }
@@ -372,22 +344,33 @@ class ObjectSpace {
372
344
  throw new Error('Hash and size cannot be empty');
373
345
  }
374
346
  }
375
- const exists = yield this.existsAsOwner(key);
376
- debug('writeAsOwner.$exists', exists);
377
- if (exists) {
378
- // 更新对象
379
- yield this.updateAsOwner(key, data, options);
347
+ try {
348
+ const exists = yield this.existsAsOwner(key);
349
+ debug('writeAsOwner.$exists', exists);
350
+ if (exists) {
351
+ // 更新对象
352
+ yield this._updateAsOwner(key, data, options);
353
+ }
354
+ else {
355
+ // 添加新对象
356
+ yield this._createAsOwner(key, data, options);
357
+ }
380
358
  }
381
- else {
382
- // @note: 只有新增的时候才会触发检测
383
- yield this.verifySpace(options === null || options === void 0 ? void 0 : options.size);
384
- // 添加新对象
385
- yield this.createAsOwner(key, data, options);
359
+ catch (err) {
360
+ utils_1.logger.error('writeAsOwner.$options', options);
361
+ utils_1.logger.error('writeAsOwner.$error', err);
362
+ throw err;
363
+ }
364
+ finally {
365
+ this.emit('space.writeAsOwner.after', {
366
+ spaceDid: this.options.spaceDid,
367
+ key,
368
+ });
369
+ debug('writeAsOwner.after', JSON.stringify({ key, options: (0, omit_1.default)(options, 'data') }));
386
370
  }
387
- debug('writeAsOwner.after', JSON.stringify({ key, options: (0, omit_1.default)(options, 'data') }));
388
371
  });
389
372
  }
390
- updateAsOwner(key, data, options) {
373
+ _updateAsOwner(key, data, options) {
391
374
  return __awaiter(this, void 0, void 0, function* () {
392
375
  debug('updateAsOwner.before', { key, options: (0, omit_1.default)(options, 'data') });
393
376
  yield this.updateMetadata(key, data, options);
@@ -401,12 +384,10 @@ class ObjectSpace {
401
384
  spaceDid: this.options.spaceDid,
402
385
  key,
403
386
  };
404
- debug('updateAsOwner.before', JSON.stringify({ key, options: (0, omit_1.default)(options, 'data'), where }));
405
387
  const oldTree = yield this.options.treeRepository.findOne({
406
388
  where,
407
389
  include: this.options.objectRepository,
408
390
  });
409
- debug('updateAsOwner.$oldTree', JSON.stringify(oldTree));
410
391
  const listObject = yield this.driver.list({
411
392
  key: (0, utils_1.getHashPath)(options.hash),
412
393
  useGlobal: true,
@@ -415,9 +396,10 @@ class ObjectSpace {
415
396
  if (oldTree.objectId === options.hash &&
416
397
  oldTree.Object.size === options.size &&
417
398
  (listObject === null || listObject === void 0 ? void 0 : listObject.size) === options.size) {
418
- // 内容不变,不需要再次存储对象,只需要更新对象的事件即可
399
+ // 内容不变,不需要再次存储对象,只需要更新对象的更新时间即可
419
400
  yield this.options.treeRepository.update({
420
401
  updatedAt: new Date().toISOString(),
402
+ size: options.size,
421
403
  }, {
422
404
  where: {
423
405
  id: oldTree.id,
@@ -428,8 +410,9 @@ class ObjectSpace {
428
410
  yield this.globalSpace.add(key, data, options);
429
411
  // 更新 tree 记录
430
412
  yield this.options.treeRepository.update({
431
- updatedAt: new Date().toISOString(),
432
413
  objectId: options.hash,
414
+ size: options.size,
415
+ updatedAt: new Date().toISOString(),
433
416
  }, {
434
417
  where: {
435
418
  id: oldTree.id,
@@ -439,7 +422,7 @@ class ObjectSpace {
439
422
  yield this.globalSpace.mark(oldTree.objectId);
440
423
  });
441
424
  }
442
- createAsOwner(key, data, options) {
425
+ _createAsOwner(key, data, options) {
443
426
  return __awaiter(this, void 0, void 0, function* () {
444
427
  debug('createAsOwner.before', JSON.stringify({ key, options: (0, omit_1.default)(options, 'data') }));
445
428
  const isDir = key.endsWith('/');
@@ -451,24 +434,28 @@ class ObjectSpace {
451
434
  parentId: null,
452
435
  key,
453
436
  type: model_1.TreeModelType.FOLDER,
437
+ count: 0,
438
+ size: 0,
439
+ });
440
+ }
441
+ else {
442
+ // 存储新对象到全局存储区
443
+ yield this.globalSpace.add(key, data, options);
444
+ // 添加 tree 记录
445
+ yield this.options.treeRepository.deepCreate({
446
+ spaceDid: this.options.spaceDid,
447
+ objectId: options.hash,
448
+ parentId: null,
449
+ key,
450
+ type: model_1.TreeModelType.FILE,
451
+ count: 1,
452
+ size: options.size,
454
453
  });
455
- yield this.updateMetadata(key, data, options);
456
- return;
457
454
  }
458
- // 存储新对象到全局存储区
459
- yield this.globalSpace.add(key, data, options);
460
- // 添加 tree 记录
461
- yield this.options.treeRepository.deepCreate({
462
- spaceDid: this.options.spaceDid,
463
- objectId: options.hash,
464
- parentId: null,
465
- key,
466
- type: key.endsWith('/') ? model_1.TreeModelType.FOLDER : model_1.TreeModelType.FILE,
467
- });
468
455
  yield this.updateMetadata(key, data, options);
469
456
  });
470
457
  }
471
- updateMetadata(key, data, options) {
458
+ updateMetadata(key, _data, options) {
472
459
  return __awaiter(this, void 0, void 0, function* () {
473
460
  debug('updateMetadata.before', { key, options: (0, omit_1.default)(options, 'data') });
474
461
  const where = {
@@ -479,11 +466,14 @@ class ObjectSpace {
479
466
  debug('updateMetadata.before', JSON.stringify({ key, options: (0, omit_1.default)(options, 'data'), where }));
480
467
  const oldTree = yield this.options.treeRepository.findOne({
481
468
  where,
469
+ attributes: ['meta'],
470
+ raw: true,
482
471
  });
483
472
  debug('updateMetadata.$oldTree', JSON.stringify(oldTree));
484
473
  if (!(0, isEmpty_1.default)(options.metadata)) {
485
474
  yield oldTree.update({
486
475
  meta: Object.assign(Object.assign({}, oldTree.meta), options.metadata),
476
+ updatedAt: new Date().toISOString(),
487
477
  });
488
478
  }
489
479
  });
@@ -501,40 +491,54 @@ class ObjectSpace {
501
491
  throw new Error(`Object ${key} cannot be deleted`);
502
492
  }
503
493
  const isDir = key.endsWith('/');
504
- if (isDir) {
505
- // 删除文件夹
506
- const whereForDeleteFolder = {
494
+ try {
495
+ if (isDir) {
496
+ // 删除文件夹
497
+ const whereForDeleteFolder = {
498
+ spaceDid: this.options.spaceDid,
499
+ // 删除以 key 开头的记录
500
+ key: {
501
+ [sequelize_1.Op.like]: `${key}%`,
502
+ },
503
+ };
504
+ debug('deleteAsOwner.$whereForDeleteFolder', JSON.stringify(whereForDeleteFolder));
505
+ const trees = yield this.options.treeRepository.findAll({
506
+ where: whereForDeleteFolder,
507
+ attributes: ['objectId'],
508
+ raw: true,
509
+ });
510
+ yield this.options.treeRepository.destroy({
511
+ where: whereForDeleteFolder,
512
+ });
513
+ yield this.globalSpace.mark(...trees.map((x) => x.objectId));
514
+ }
515
+ else {
516
+ const where = {
517
+ spaceDid: this.options.spaceDid,
518
+ key,
519
+ };
520
+ const tree = yield this.options.treeRepository.findOne({
521
+ where,
522
+ attributes: ['objectId'],
523
+ raw: true,
524
+ });
525
+ yield this.options.treeRepository.destroy({
526
+ where,
527
+ });
528
+ yield this.globalSpace.mark(tree.objectId);
529
+ }
530
+ }
531
+ catch (err) {
532
+ utils_1.logger.error('deleteAsOwner.$key', key);
533
+ utils_1.logger.error('deleteAsOwner.$error', err);
534
+ throw err;
535
+ }
536
+ finally {
537
+ this.emit('space.deleteAsOwner.after', {
507
538
  spaceDid: this.options.spaceDid,
508
- // 删除以 key 开头的记录
509
- key: {
510
- [skypesky_sequelize_1.Op.like]: `${key}%`,
511
- },
512
- };
513
- debug('deleteAsOwner.$whereForDeleteFolder', JSON.stringify(whereForDeleteFolder));
514
- const trees = yield this.options.treeRepository.findAll({
515
- where: whereForDeleteFolder,
516
- attributes: ['objectId'],
517
- raw: true,
518
- });
519
- yield this.options.treeRepository.destroy({
520
- where: whereForDeleteFolder,
539
+ key,
521
540
  });
522
- yield this.globalSpace.mark(...trees.map((x) => x.objectId));
523
- return;
524
541
  }
525
- const where = {
526
- spaceDid: this.options.spaceDid,
527
- key,
528
- };
529
- const tree = yield this.options.treeRepository.findOne({
530
- where,
531
- attributes: ['objectId'],
532
- raw: true,
533
- });
534
- yield this.options.treeRepository.destroy({
535
- where,
536
- });
537
- yield this.globalSpace.mark(tree.objectId);
538
542
  });
539
543
  }
540
544
  readAsOwner(key, options) {
@@ -547,11 +551,15 @@ class ObjectSpace {
547
551
  debug('readAsOwner.$where', JSON.stringify(where));
548
552
  const tree = yield this.options.treeRepository.findOne({
549
553
  where,
554
+ attributes: ['objectId'],
555
+ raw: true,
550
556
  });
551
557
  if (!tree) {
552
558
  throw new Error(`Object(${key}) not exists`);
553
559
  }
554
- return this.driver.readAsOwner((0, utils_1.getHashPath)(tree.objectId), { useGlobal: true });
560
+ return this.driver.readAsOwner((0, utils_1.getHashPath)(tree.objectId), {
561
+ useGlobal: true,
562
+ });
555
563
  });
556
564
  }
557
565
  existsAsOwner(key) {
@@ -570,38 +578,31 @@ class ObjectSpace {
570
578
  }
571
579
  getStatusAsOwner(key) {
572
580
  return __awaiter(this, void 0, void 0, function* () {
573
- debug('getStatusAsOwner.before', JSON.stringify({
574
- spaceDid: this.options.spaceDid,
575
- key,
576
- }));
577
581
  const { error } = schemas_1.OwnerOperatorKeySchema.validate(key);
578
582
  if (error) {
579
583
  throw error;
580
584
  }
581
585
  const where = {
582
586
  spaceDid: this.options.spaceDid,
583
- key: {
584
- [skypesky_sequelize_1.Op.like]: `${key}%`,
585
- },
586
- type: model_1.TreeModelType.FILE,
587
+ key,
588
+ type: model_1.TreeModelType.FOLDER,
587
589
  };
588
- // @FIXME: 可能存在性能问题 @jianchao
589
- const objects = yield this.options.treeRepository.count({ where });
590
- const lastModified = yield this.options.treeRepository.max('updatedAt', {
590
+ const tree = yield this.options.treeRepository.findOne({
591
591
  where,
592
+ attributes: ['updatedAt', 'size', 'count'],
593
+ raw: true,
592
594
  });
593
- // @FIXME: 没有正确关联
594
- // @FIXME: 可能存在性能问题 @jianchao
595
- const objectRecords = yield this.options.objectRepository.sequelize.query(`SELECT SUM(Object.size) as totalSize FROM Object JOIN Tree ON Object.id = Tree.objectId WHERE Tree.spaceDid = '${this.options.spaceDid}' AND Tree.type = ${model_1.TreeModelType.FILE} AND Tree.key LIKE '${key}%'`, { type: skypesky_sequelize_1.QueryTypes.SELECT });
596
- // @ts-expect-error
597
- const size = objectRecords[0].totalSize;
598
- debug('getStatusAsOwner.after', JSON.stringify({
599
- spaceDid: this.options.spaceDid,
600
- key,
601
- objects,
602
- size,
603
- lastModified,
604
- }));
595
+ if (!tree) {
596
+ return {
597
+ objects: 0,
598
+ size: 0,
599
+ lastModified: 0,
600
+ };
601
+ }
602
+ // @note: 我们采用了逐级冒泡的方式,从叶子节点自下而上的更新 folder 的更新时间,对象数,size
603
+ const objects = tree.count;
604
+ const lastModified = new Date(tree.updatedAt).getTime();
605
+ const { size } = tree;
605
606
  return {
606
607
  objects,
607
608
  size,
@@ -1,9 +1,11 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { Stream } from 'stream';
4
+ import EventEmitter from 'events';
3
5
  import { SpaceConfig } from '../configuration';
4
6
  import { Data, Object } from '../meta';
5
7
  import { WriteOptions, ReadOptions, SpaceProtocol, DriverProtocol, AppSpaceOptions, PermissionOptions, DeleteOptions, ListOptions, ListsOptions, GetHashOptions, KeyStatus, ReadAsOwnerOptions, ExistsAsOwnerOptions } from '../protocols';
6
- export declare class Space implements SpaceProtocol {
8
+ export declare class Space extends EventEmitter implements SpaceProtocol {
7
9
  readonly driver: DriverProtocol;
8
10
  static readonly READONLY_OBJECT_KEYS: string[];
9
11
  constructor(driver: DriverProtocol);
@@ -14,8 +14,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.Space = void 0;
16
16
  const xbytes_1 = __importDefault(require("xbytes"));
17
- class Space {
17
+ const events_1 = __importDefault(require("events"));
18
+ class Space extends events_1.default {
18
19
  constructor(driver) {
20
+ super();
19
21
  this.driver = driver;
20
22
  }
21
23
  createSpace(spaceConfiguration) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@did-space/core",
3
- "version": "0.5.18",
3
+ "version": "0.5.20",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -39,7 +39,7 @@
39
39
  "mime-types": "^2.1.35",
40
40
  "multiformats": "9",
41
41
  "p-all": "3.0.0",
42
- "skypesky-sequelize": "^6.32.2",
42
+ "sequelize": "^6.37.3",
43
43
  "xbytes": "^1.9.1"
44
44
  },
45
45
  "devDependencies": {
@@ -53,5 +53,5 @@
53
53
  "ts-jest": "^28.0.8",
54
54
  "typescript": "^4.9.5"
55
55
  },
56
- "gitHead": "900a897491e39c8b0eeabcf27883f7d067a05de0"
56
+ "gitHead": "81b6a0d179194b4fe9c2411b24b74a3015a4dac0"
57
57
  }