@did-space/core 0.2.172 → 0.3.0

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 (41) hide show
  1. package/dist/drivers/base.d.ts +5 -5
  2. package/dist/drivers/base.js +8 -8
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +1 -0
  5. package/dist/meta/object.d.ts +5 -0
  6. package/dist/model/index.d.ts +3 -0
  7. package/dist/model/index.js +19 -0
  8. package/dist/model/object-collection.d.ts +28 -0
  9. package/dist/model/object-collection.js +7 -0
  10. package/dist/model/object.d.ts +59 -0
  11. package/dist/model/object.js +7 -0
  12. package/dist/model/tree.d.ts +94 -0
  13. package/dist/model/tree.js +18 -0
  14. package/dist/protocols/space-operator.d.ts +2 -0
  15. package/dist/protocols/space-owner-operator.d.ts +30 -4
  16. package/dist/schemas/global-space.d.ts +2 -0
  17. package/dist/schemas/global-space.js +21 -0
  18. package/dist/schemas/index.d.ts +1 -0
  19. package/dist/schemas/index.js +1 -0
  20. package/dist/schemas/object-space.d.ts +6 -0
  21. package/dist/schemas/object-space.js +39 -0
  22. package/dist/space/global-space.d.ts +43 -0
  23. package/dist/space/global-space.js +153 -0
  24. package/dist/space/index.d.ts +3 -45
  25. package/dist/space/index.js +16 -187
  26. package/dist/space/object-space.d.ts +111 -0
  27. package/dist/space/object-space.js +652 -0
  28. package/dist/space/space.d.ts +45 -0
  29. package/dist/space/space.js +190 -0
  30. package/dist/utils/common.d.ts +3 -0
  31. package/dist/utils/common.js +17 -0
  32. package/dist/utils/hash.d.ts +20 -0
  33. package/dist/utils/hash.js +60 -0
  34. package/dist/utils/index.d.ts +3 -2
  35. package/dist/utils/index.js +3 -2
  36. package/dist/utils/{string-to-stream.d.ts → stream.d.ts} +2 -0
  37. package/dist/utils/stream.js +23 -0
  38. package/package.json +11 -2
  39. package/dist/utils/stream-to-string.d.ts +0 -1
  40. package/dist/utils/stream-to-string.js +0 -10
  41. package/dist/utils/string-to-stream.js +0 -11
@@ -0,0 +1,652 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ObjectSpace = void 0;
16
+ const debug_1 = __importDefault(require("debug"));
17
+ const skypesky_sequelize_1 = require("skypesky-sequelize");
18
+ const js_yaml_1 = __importDefault(require("js-yaml"));
19
+ const path_1 = require("path");
20
+ const lodash_1 = require("lodash");
21
+ const configuration_1 = require("../configuration");
22
+ const model_1 = require("../model");
23
+ const utils_1 = require("../utils");
24
+ const schemas_1 = require("../schemas");
25
+ const constants_1 = require("../constants");
26
+ const stream_1 = require("../utils/stream");
27
+ const global_space_1 = require("./global-space");
28
+ const debug = (0, debug_1.default)('@did-space/core:ObjectSpace');
29
+ class ObjectSpace {
30
+ constructor(options) {
31
+ const { error } = schemas_1.ObjectSpaceOptionsSchema.validate(options, {
32
+ allowUnknown: true,
33
+ stripUnknown: true,
34
+ });
35
+ if (error) {
36
+ throw error;
37
+ }
38
+ this.driver = options.driver;
39
+ this.spaceDid = options.spaceDid;
40
+ this.treeRepository = options.treeRepository;
41
+ this.objectRepository = options.objectRepository;
42
+ this.objectCollectionRepository = options.objectCollectionRepository;
43
+ this.globalSpace = new global_space_1.GlobalSpace({
44
+ driver: options.driver,
45
+ treeRepository: options.treeRepository,
46
+ objectRepository: options.objectRepository,
47
+ objectCollectionRepository: options.objectCollectionRepository,
48
+ });
49
+ }
50
+ createSpace(spaceConfig) {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ debug('createSpace.before', JSON.stringify(spaceConfig));
53
+ yield this.writeAsOwner('/', null, null);
54
+ yield this.createConfig(spaceConfig);
55
+ debug('createSpace.after', JSON.stringify(spaceConfig));
56
+ });
57
+ }
58
+ isSpaceCreated() {
59
+ return __awaiter(this, void 0, void 0, function* () {
60
+ const where = {
61
+ spaceDid: this.spaceDid,
62
+ key: '/config.yml',
63
+ };
64
+ debug('isSpaceCreated.before', JSON.stringify(where));
65
+ const created = Boolean(yield this.treeRepository.count({
66
+ where,
67
+ }));
68
+ debug('isSpaceCreated.after', JSON.stringify({ created }));
69
+ return created;
70
+ });
71
+ }
72
+ /**
73
+ *
74
+ * @description
75
+ * @return {*} {Promise<void>}
76
+ * @memberof ObjectSpace
77
+ */
78
+ destroySpace() {
79
+ return __awaiter(this, void 0, void 0, function* () {
80
+ yield this.deleteAsOwner('/');
81
+ });
82
+ }
83
+ getSpaceSize() {
84
+ return __awaiter(this, void 0, void 0, function* () {
85
+ const { size } = yield this.getStatusAsOwner('/');
86
+ return size;
87
+ });
88
+ }
89
+ createAppSpace(options) {
90
+ return __awaiter(this, void 0, void 0, function* () {
91
+ debug('createAppSpace.before', JSON.stringify({ options }));
92
+ yield this.writeAsOwner(yield this.getAppSpacePath(options), null);
93
+ debug('createAppSpace.after', JSON.stringify({ options }));
94
+ });
95
+ }
96
+ /**
97
+ * @description
98
+ * @param {AppSpaceOptions} options
99
+ * @return {Promise<void>} {Promise<void>}
100
+ * @memberof ObjectSpace
101
+ */
102
+ destroyAppSpace(options) {
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ debug('destroyAppSpace.before', JSON.stringify({ options }));
105
+ yield this.deleteAsOwner(yield this.getAppSpacePath(options));
106
+ debug('destroyAppSpace.after', JSON.stringify({ options }));
107
+ });
108
+ }
109
+ getAppSpacePath(options) {
110
+ // @ts-expect-error
111
+ return (0, path_1.join)(`/${constants_1.APPS}`, `${options.appDid}/`);
112
+ }
113
+ write(options) {
114
+ return __awaiter(this, void 0, void 0, function* () {
115
+ debug('write.before', JSON.stringify((0, lodash_1.omit)(options, 'data')));
116
+ const { error } = schemas_1.WriteOptionsSchema.validate(options, {
117
+ allowUnknown: true,
118
+ stripUnknown: true,
119
+ });
120
+ if (error) {
121
+ throw error;
122
+ }
123
+ const { data } = options;
124
+ const key = (0, path_1.join)(yield this.getAppSpacePath(options), options.key);
125
+ // @ts-expect-error
126
+ yield this.writeAsOwner(key, data, options);
127
+ debug('write.after', JSON.stringify({ key }));
128
+ });
129
+ }
130
+ delete(options) {
131
+ return __awaiter(this, void 0, void 0, function* () {
132
+ debug('delete.before', JSON.stringify({ options }));
133
+ const key = (0, path_1.join)(yield this.getAppSpacePath(options), options.key);
134
+ yield this.deleteAsOwner(key);
135
+ debug('delete.after', JSON.stringify({ key }));
136
+ });
137
+ }
138
+ read(options) {
139
+ return __awaiter(this, void 0, void 0, function* () {
140
+ debug('read.before', JSON.stringify({ options }));
141
+ const key = (0, path_1.join)(yield this.getAppSpacePath(options), options.key);
142
+ debug('read.$key', key);
143
+ return this.readAsOwner(key);
144
+ });
145
+ }
146
+ getHash(options) {
147
+ return __awaiter(this, void 0, void 0, function* () {
148
+ debug('getHash.before', JSON.stringify({ options }));
149
+ const key = (0, path_1.join)(yield this.getAppSpacePath(options), options.key);
150
+ const where = {
151
+ spaceDid: this.spaceDid,
152
+ key,
153
+ };
154
+ debug('getHash.$key', key);
155
+ debug('getHash.$where', JSON.stringify({ where }));
156
+ if (!(yield this.exists(options))) {
157
+ throw new Error(`Object(${key}) not exists`);
158
+ }
159
+ const tree = yield this.treeRepository.findOne({ where });
160
+ return tree.objectId;
161
+ });
162
+ }
163
+ exists(options) {
164
+ return __awaiter(this, void 0, void 0, function* () {
165
+ debug('exists.before', JSON.stringify({ options }));
166
+ const key = (0, path_1.join)(yield this.getAppSpacePath(options), options.key);
167
+ return this.existsAsOwner(key);
168
+ });
169
+ }
170
+ listsOneLevelAsOwner(options) {
171
+ return __awaiter(this, void 0, void 0, function* () {
172
+ const where = {
173
+ spaceDid: this.spaceDid,
174
+ key: options.key,
175
+ };
176
+ debug('listsOneLevel.before', JSON.stringify(options));
177
+ const parentTree = yield this.treeRepository.findOne({
178
+ where,
179
+ raw: true,
180
+ });
181
+ debug('listsOneLevel.$parentTree', JSON.stringify(parentTree, null, 2));
182
+ const trees = yield this.treeRepository.findAll({
183
+ where: {
184
+ spaceDid: this.spaceDid,
185
+ parentId: parentTree.id,
186
+ },
187
+ include: this.objectRepository,
188
+ });
189
+ return Promise.all(trees.map((x) => __awaiter(this, void 0, void 0, function* () {
190
+ if (x.type === model_1.TreeModelType.FOLDER) {
191
+ const { size, lastModified } = yield this.getStatusAsOwner(x.key);
192
+ return {
193
+ key: x.key,
194
+ name: (0, path_1.basename)(x.key),
195
+ isDir: true,
196
+ size,
197
+ lastModified: lastModified || new Date(x.updatedAt).getTime(),
198
+ editable: true,
199
+ mimeType: null,
200
+ };
201
+ }
202
+ return {
203
+ key: x.key,
204
+ name: (0, path_1.basename)(x.key),
205
+ isDir: x.type === model_1.TreeModelType.FOLDER,
206
+ size: x.Object.size,
207
+ lastModified: new Date(x.updatedAt).getTime(),
208
+ editable: true,
209
+ mimeType: x.Object.meta.mimeType,
210
+ };
211
+ })));
212
+ });
213
+ }
214
+ listsRecursiveAsOwner(options) {
215
+ return __awaiter(this, void 0, void 0, function* () {
216
+ debug('listsRecursiveAsOwner.before', JSON.stringify(options));
217
+ const where = {
218
+ spaceDid: this.spaceDid,
219
+ key: {
220
+ [skypesky_sequelize_1.Op.like]: `${options.key}%`,
221
+ },
222
+ type: model_1.TreeModelType.FILE,
223
+ };
224
+ const trees = yield this.treeRepository.findAll({
225
+ where,
226
+ include: this.objectRepository,
227
+ });
228
+ return trees.map((x) => {
229
+ return {
230
+ key: x.key,
231
+ name: (0, path_1.basename)(x.key),
232
+ isDir: x.type === model_1.TreeModelType.FOLDER,
233
+ size: x.Object.size,
234
+ lastModified: new Date(x.updatedAt).getTime(),
235
+ editable: true,
236
+ mimeType: x.Object.meta.mimeType,
237
+ };
238
+ });
239
+ });
240
+ }
241
+ /**
242
+ * @description 后续改名为 listsAsOwner 更合适
243
+ * @param {ListsOptions} options
244
+ * @return {*} {Promise<Object[]>}
245
+ * @memberof ObjectSpace
246
+ */
247
+ lists(options) {
248
+ return __awaiter(this, void 0, void 0, function* () {
249
+ debug('lists.before', JSON.stringify(options));
250
+ if (!(yield this.existsAsOwner(options.key))) {
251
+ return [];
252
+ }
253
+ // 以 非递归的方式 && 显示文件夹 的方式列出当前文件
254
+ if (!options.recursive) {
255
+ return this.listsOneLevelAsOwner(options);
256
+ }
257
+ if (options.recursive && options.ignoreDirectories) {
258
+ const objects = yield this.listsRecursiveAsOwner(options);
259
+ return objects.map((x) => {
260
+ return Object.assign(Object.assign({}, x), { key: x.key.replace(options.key, '/') });
261
+ });
262
+ }
263
+ debug('lists.after', JSON.stringify(options));
264
+ throw new Error(`Filter methods not yet supported:\n ${JSON.stringify(options, null, 2)}`);
265
+ });
266
+ }
267
+ /**
268
+ * @FIXME: 接口的功能实际应该是 listAsOwner 实现的,属于技术债 @jianchao
269
+ * @description
270
+ * @param {ListOptions} options
271
+ * @return {*} {Promise<Object>}
272
+ * @memberof ObjectSpace
273
+ */
274
+ list(options) {
275
+ return __awaiter(this, void 0, void 0, function* () {
276
+ debug('list.before', JSON.stringify(options));
277
+ const where = {
278
+ spaceDid: this.spaceDid,
279
+ key: options.key,
280
+ };
281
+ const x = yield this.treeRepository.findOne({
282
+ where,
283
+ include: this.objectRepository,
284
+ });
285
+ return {
286
+ key: x.key,
287
+ name: (0, path_1.basename)(x.key),
288
+ isDir: x.type === model_1.TreeModelType.FOLDER,
289
+ size: x.type === model_1.TreeModelType.FOLDER ? 0 : x.Object.size,
290
+ lastModified: new Date(x.updatedAt).getTime(),
291
+ // FIXME: 需要后续处理一下
292
+ editable: true,
293
+ mimeType: x.type === model_1.TreeModelType.FOLDER ? null : x.Object.meta.mimeType,
294
+ };
295
+ });
296
+ }
297
+ // private async _addToGlobalStorage(key: string, data: Data, options: WriteAsOwnerOptions): Promise<void> {
298
+ // // @note: 注意此处必须存储到全局存储区
299
+ // // eslint-disable-next-line no-param-reassign
300
+ // options = merge(options, { useGlobal: true });
301
+ // const where: WhereOptions<ObjectModel> = {
302
+ // id: options.hash,
303
+ // };
304
+ // debug('_addToGlobalStorage.before', JSON.stringify({ key, options, where }));
305
+ // const objectRecord: ObjectModel = await this.objectRepository.findOne({
306
+ // where,
307
+ // raw: true,
308
+ // });
309
+ // debug('_addToGlobalStorage.$objectRecord', JSON.stringify(objectRecord));
310
+ // if (objectRecord) {
311
+ // return;
312
+ // }
313
+ // // 存储新对象到全局存储区
314
+ // const newKey = getHashPath(options.hash);
315
+ // await this.driver.writeAsOwner(newKey, data, options);
316
+ // // 添加 object 记录
317
+ // await this.objectRepository.create({
318
+ // id: options.hash,
319
+ // size: options.size,
320
+ // meta: {
321
+ // mimeType: <string>mimeTypes.lookup(key) || 'unknown',
322
+ // key,
323
+ // },
324
+ // });
325
+ // debug('_addToGlobalStorage.after', JSON.stringify({ objectRecord }));
326
+ // }
327
+ _updateAsOwner(key, data, options) {
328
+ return __awaiter(this, void 0, void 0, function* () {
329
+ debug('_updateAsOwner.before', JSON.stringify({ key, options }));
330
+ if ((0, utils_1.isDirectory)(key)) {
331
+ return;
332
+ }
333
+ const where = {
334
+ spaceDid: this.spaceDid,
335
+ key,
336
+ };
337
+ debug('_updateAsOwner.before', JSON.stringify({ key, options, where }));
338
+ const oldTree = yield this.treeRepository.findOne({
339
+ where,
340
+ raw: true,
341
+ });
342
+ debug('_updateAsOwner.$oldTree', JSON.stringify(oldTree));
343
+ if (oldTree.objectId === options.hash) {
344
+ // 内容不变,不需要再次存储对象,只需要更新对象的事件即可
345
+ yield this.treeRepository.update({
346
+ updatedAt: new Date().toISOString(),
347
+ }, {
348
+ where: {
349
+ id: oldTree.id,
350
+ },
351
+ });
352
+ return;
353
+ }
354
+ yield this.globalSpace.add(key, data, options);
355
+ // 更新 tree 记录
356
+ yield this.treeRepository.update({
357
+ updatedAt: new Date().toISOString(),
358
+ objectId: options.hash,
359
+ }, {
360
+ where: {
361
+ id: oldTree.id,
362
+ },
363
+ });
364
+ // 标记清除
365
+ yield this.globalSpace.mark(oldTree.objectId);
366
+ });
367
+ }
368
+ _createAsOwner(key, data, options) {
369
+ return __awaiter(this, void 0, void 0, function* () {
370
+ debug('_createAsOwner.before', JSON.stringify({ key, options }));
371
+ const isDir = key.endsWith('/');
372
+ if (isDir) {
373
+ // 添加 tree 记录
374
+ yield this.treeRepository.deepCreate({
375
+ spaceDid: this.spaceDid,
376
+ objectId: null,
377
+ parentId: null,
378
+ key,
379
+ type: model_1.TreeModelType.FOLDER,
380
+ });
381
+ return;
382
+ }
383
+ // 存储新对象到全局存储区
384
+ yield this.globalSpace.add(key, data, options);
385
+ // 添加 tree 记录
386
+ yield this.treeRepository.deepCreate({
387
+ spaceDid: this.spaceDid,
388
+ objectId: options.hash,
389
+ parentId: null,
390
+ key,
391
+ type: key.endsWith('/') ? model_1.TreeModelType.FOLDER : model_1.TreeModelType.FILE,
392
+ });
393
+ });
394
+ }
395
+ /**
396
+ * @refactor: @jianchao 后续让 write 的接口参数保持一致,即 key, data 都在 options 里面,目前改动收益比较小
397
+ * @description
398
+ * @param {string} key
399
+ * @param {Data} data
400
+ * @param {WriteAsOwnerOptions} options
401
+ * @return {*} {Promise<void>}
402
+ * @memberof ObjectSpace
403
+ */
404
+ writeAsOwner(key, data, options = { hash: null, size: null }) {
405
+ return __awaiter(this, void 0, void 0, function* () {
406
+ debug('writeAsOwner.before', JSON.stringify({ key, options: (0, lodash_1.omit)(options, 'data') }));
407
+ const { error } = schemas_1.WriteAsOwnerOptionsSchema.validate(Object.assign(Object.assign({}, options), { key,
408
+ data }), {
409
+ allowUnknown: true,
410
+ stripUnknown: true,
411
+ });
412
+ if (error) {
413
+ throw error;
414
+ }
415
+ if (!(0, utils_1.isDirectory)(key) && !(0, stream_1.isStream)(data)) {
416
+ options.hash = options.hash || (yield (0, utils_1.getHash)(data));
417
+ options.size = options.size || (0, utils_1.getSize)(data);
418
+ if (!options.hash || !options.size) {
419
+ throw new Error('Hash and size cannot be empty');
420
+ }
421
+ }
422
+ const exists = yield this.existsAsOwner(key);
423
+ debug('writeAsOwner.$exists', exists);
424
+ if (exists) {
425
+ // 更新对象
426
+ yield this._updateAsOwner(key, data, options);
427
+ }
428
+ else {
429
+ // 添加新对象
430
+ yield this._createAsOwner(key, data, options);
431
+ }
432
+ });
433
+ }
434
+ deleteAsOwner(key) {
435
+ return __awaiter(this, void 0, void 0, function* () {
436
+ debug('deleteAsOwner.before', JSON.stringify({ key }));
437
+ const { error } = schemas_1.DeleteAsOwnerOptionsSchema.validate({
438
+ key,
439
+ });
440
+ if (error) {
441
+ throw error;
442
+ }
443
+ const isDir = key.endsWith('/');
444
+ if (isDir) {
445
+ // 删除文件夹
446
+ const whereForDeleteFolder = {
447
+ spaceDid: this.spaceDid,
448
+ // 删除以 key 开头的记录
449
+ key: {
450
+ [skypesky_sequelize_1.Op.like]: `${key}%`,
451
+ },
452
+ };
453
+ debug('deleteAsOwner.$whereForDeleteFolder', JSON.stringify(whereForDeleteFolder));
454
+ const trees = yield this.treeRepository.findAll({
455
+ where: whereForDeleteFolder,
456
+ attributes: ['objectId'],
457
+ raw: true,
458
+ });
459
+ yield this.treeRepository.destroy({
460
+ where: whereForDeleteFolder,
461
+ });
462
+ yield this.globalSpace.mark(...trees.map((x) => x.objectId));
463
+ return;
464
+ }
465
+ const where = {
466
+ spaceDid: this.spaceDid,
467
+ key,
468
+ };
469
+ const tree = yield this.treeRepository.findOne({
470
+ where,
471
+ attributes: ['objectId'],
472
+ raw: true,
473
+ });
474
+ yield this.treeRepository.destroy({
475
+ where,
476
+ });
477
+ yield this.globalSpace.mark(tree.objectId);
478
+ });
479
+ }
480
+ readAsOwner(key, options) {
481
+ return __awaiter(this, void 0, void 0, function* () {
482
+ debug('readAsOwner.before', JSON.stringify({ key, options }));
483
+ const where = {
484
+ spaceDid: this.spaceDid,
485
+ key,
486
+ };
487
+ debug('readAsOwner.$where', JSON.stringify(where));
488
+ const tree = yield this.treeRepository.findOne({
489
+ where,
490
+ });
491
+ if (!tree) {
492
+ throw new Error(`Object(${key}) not exists`);
493
+ }
494
+ return this.driver.readAsOwner((0, utils_1.getHashPath)(tree.objectId), { useGlobal: true });
495
+ });
496
+ }
497
+ existsAsOwner(key) {
498
+ return __awaiter(this, void 0, void 0, function* () {
499
+ const where = {
500
+ spaceDid: this.spaceDid,
501
+ key,
502
+ };
503
+ debug('existsAsOwner.before', JSON.stringify({ where }));
504
+ const exists = Boolean(yield this.treeRepository.count({
505
+ where,
506
+ }));
507
+ debug('existsAsOwner.after', JSON.stringify({ exists }));
508
+ return exists;
509
+ });
510
+ }
511
+ getStatusAsOwner(key) {
512
+ return __awaiter(this, void 0, void 0, function* () {
513
+ debug('getStatusAsOwner.before', JSON.stringify({
514
+ spaceDid: this.spaceDid,
515
+ key,
516
+ }));
517
+ const { error } = schemas_1.KeySchema.validate(key);
518
+ if (error) {
519
+ throw error;
520
+ }
521
+ const where = {
522
+ spaceDid: this.spaceDid,
523
+ key: {
524
+ [skypesky_sequelize_1.Op.like]: `${key}%`,
525
+ },
526
+ type: model_1.TreeModelType.FILE,
527
+ };
528
+ const objects = yield this.treeRepository.count({ where });
529
+ const lastModified = yield this.treeRepository.max('updatedAt', {
530
+ where,
531
+ });
532
+ // @FIXME: 没有正确关联
533
+ const objectRecords = yield this.objectRepository.sequelize.query(`SELECT SUM(Object.size) as totalSize FROM Object JOIN Tree ON Object.id = Tree.objectId WHERE Tree.key LIKE '${key}%' AND Tree.spaceDid = '${this.spaceDid}'`, { type: skypesky_sequelize_1.QueryTypes.SELECT });
534
+ // @ts-expect-error
535
+ const size = objectRecords[0].totalSize;
536
+ debug('getStatusAsOwner.after', JSON.stringify({
537
+ spaceDid: this.spaceDid,
538
+ key,
539
+ objects,
540
+ size,
541
+ lastModified,
542
+ }));
543
+ return {
544
+ objects,
545
+ size,
546
+ lastModified,
547
+ };
548
+ });
549
+ }
550
+ createConfig(spaceConfig) {
551
+ return __awaiter(this, void 0, void 0, function* () {
552
+ const data = js_yaml_1.default.dump(spaceConfig);
553
+ const hash = yield (0, utils_1.getHash)(data);
554
+ const size = (0, utils_1.getSize)(data);
555
+ debug('createSpace.$data', data);
556
+ debug('createSpace.$hash', hash);
557
+ debug('createSpace.$size', size);
558
+ yield this.writeAsOwner('/config.yml', data, {
559
+ hash,
560
+ size,
561
+ useGlobal: true,
562
+ });
563
+ });
564
+ }
565
+ destroyConfig() {
566
+ return this.deleteAsOwner('/config.yml');
567
+ }
568
+ set(key, value) {
569
+ return __awaiter(this, void 0, void 0, function* () {
570
+ debug('set.before', JSON.stringify({ key, value }));
571
+ const configData = yield this.readAsOwner('/config.yml');
572
+ const data = js_yaml_1.default.load(yield (0, stream_1.streamToString)(configData));
573
+ data[key] = value;
574
+ yield this.createConfig(data);
575
+ });
576
+ }
577
+ get(key, defaultValue = undefined) {
578
+ var _a;
579
+ return __awaiter(this, void 0, void 0, function* () {
580
+ debug('get.before', JSON.stringify({ key }));
581
+ const configData = yield this.readAsOwner('/config.yml');
582
+ const data = js_yaml_1.default.load(yield (0, stream_1.streamToString)(configData));
583
+ return (_a = data[key]) !== null && _a !== void 0 ? _a : defaultValue;
584
+ });
585
+ }
586
+ getPermission({ fromAppDid, toAppDid }) {
587
+ var _a;
588
+ return __awaiter(this, void 0, void 0, function* () {
589
+ const permissions = yield this.get('permissions');
590
+ return ((_a = permissions === null || permissions === void 0 ? void 0 : permissions[fromAppDid]) === null || _a === void 0 ? void 0 : _a[toAppDid]) || 0;
591
+ });
592
+ }
593
+ /**
594
+ *
595
+ * @see https://blog.csdn.net/a1173537204/article/details/89765932
596
+ * @private
597
+ * @param {PermissionOptions} { fromAppDid, toAppDid }
598
+ * @param {number} permission
599
+ * @param {boolean} status
600
+ * @return {*} {Promise<void>}
601
+ * @memberof S3SpaceConfig
602
+ */
603
+ setPermission({ fromAppDid, toAppDid }, permission, status) {
604
+ var _a, _b;
605
+ return __awaiter(this, void 0, void 0, function* () {
606
+ const permissions = yield this.get('permissions', {});
607
+ // 我想知道原来的权限是啥样的?
608
+ const oldPermission = ((_a = permissions === null || permissions === void 0 ? void 0 : permissions[fromAppDid]) === null || _a === void 0 ? void 0 : _a[toAppDid]) || 0;
609
+ permissions[fromAppDid] = Object.assign((_b = permissions === null || permissions === void 0 ? void 0 : permissions[fromAppDid]) !== null && _b !== void 0 ? _b : {}, Object.assign(Object.assign({}, permissions === null || permissions === void 0 ? void 0 : permissions[fromAppDid]), {
610
+ // eslint-disable-next-line no-bitwise
611
+ [toAppDid]: status ? oldPermission | permission : oldPermission & ~permission }));
612
+ yield this.set('permissions', permissions);
613
+ });
614
+ }
615
+ /**
616
+ *
617
+ * @refactor 这部分的实现大同小异,之后可以抽象到上层实现,这样可以减少代码量 @jianchao
618
+ * @description
619
+ * @param {PermissionOptions} options
620
+ * @param {boolean} value
621
+ * @return {*} {Promise<void>}
622
+ * @memberof ObjectSpace
623
+ */
624
+ setListable(options, value) {
625
+ return this.setPermission(options, configuration_1.Scopes['list:object'], value);
626
+ }
627
+ setReadable(options, value) {
628
+ return this.setPermission(options, configuration_1.Scopes['read:object'], value);
629
+ }
630
+ setWritable(options, value) {
631
+ return this.setPermission(options, configuration_1.Scopes['write:object'], value);
632
+ }
633
+ isListable(options) {
634
+ return __awaiter(this, void 0, void 0, function* () {
635
+ const permission = yield this.getPermission(options);
636
+ return Boolean((permission & configuration_1.Scopes['list:object']) === configuration_1.Scopes['list:object']);
637
+ });
638
+ }
639
+ isReadable(options) {
640
+ return __awaiter(this, void 0, void 0, function* () {
641
+ const permission = yield this.getPermission(options);
642
+ return Boolean((permission & configuration_1.Scopes['read:object']) === configuration_1.Scopes['read:object']);
643
+ });
644
+ }
645
+ isWritable(options) {
646
+ return __awaiter(this, void 0, void 0, function* () {
647
+ const permission = yield this.getPermission(options);
648
+ return Boolean((permission & configuration_1.Scopes['write:object']) === configuration_1.Scopes['write:object']);
649
+ });
650
+ }
651
+ }
652
+ exports.ObjectSpace = ObjectSpace;
@@ -0,0 +1,45 @@
1
+ /// <reference types="node" />
2
+ import { Stream } from 'stream';
3
+ import { SpaceConfig } from '../configuration';
4
+ import { Data, Object } from '../meta';
5
+ import { WriteOptions, ReadOptions, SpaceProtocol, DriverProtocol, AppSpaceOptions, PermissionOptions, DeleteOptions, ListOptions, ListsOptions, GetHashOptions, KeyStatus, ReadAsOwnerOptions, ExistsAsOwnerOptions } from '../protocols';
6
+ export declare class Space implements SpaceProtocol {
7
+ readonly driver: DriverProtocol;
8
+ static readonly READONLY_OBJECT_KEYS: string[];
9
+ constructor(driver: DriverProtocol);
10
+ createSpace(spaceConfiguration: SpaceConfig): Promise<void>;
11
+ destroySpace(): Promise<void>;
12
+ isSpaceCreated(): Promise<boolean>;
13
+ getSpaceSize(): Promise<number>;
14
+ createAppSpace(options: AppSpaceOptions): Promise<void>;
15
+ destroyAppSpace(options: AppSpaceOptions): Promise<void>;
16
+ getAppSpacePath(options: AppSpaceOptions): Promise<string>;
17
+ createConfig(spaceConfig: SpaceConfig): Promise<void>;
18
+ destroyConfig(): Promise<void>;
19
+ set<T = any>(key: string, value: T): Promise<void>;
20
+ get<T = any>(key: string): Promise<T>;
21
+ setListable(options: PermissionOptions, value: boolean): Promise<void>;
22
+ setReadable(options: PermissionOptions, value: boolean): Promise<void>;
23
+ setWritable(options: PermissionOptions, value: boolean): Promise<void>;
24
+ isListable(options: PermissionOptions): Promise<boolean>;
25
+ isReadable(options: PermissionOptions): Promise<boolean>;
26
+ isWritable(options: PermissionOptions): Promise<boolean>;
27
+ getSpaceStatus(): Promise<{
28
+ totalCapacity: number;
29
+ usedCapacity: number;
30
+ isFull: boolean;
31
+ }>;
32
+ write(options: WriteOptions): Promise<void>;
33
+ delete(options: DeleteOptions): Promise<void>;
34
+ read(options: ReadOptions): Promise<Stream>;
35
+ getHash(options: GetHashOptions): Promise<string>;
36
+ exists(options: ReadOptions): Promise<boolean>;
37
+ lists(options: ListsOptions): Promise<Object[]>;
38
+ list(options: ListOptions): Promise<Object>;
39
+ writeAsOwner(key: string, data: Data): Promise<void>;
40
+ deleteAsOwner(key: string): Promise<void>;
41
+ readAsOwner(key: string, options?: ReadAsOwnerOptions): Promise<Stream>;
42
+ existsAsOwner(key: string, options?: ExistsAsOwnerOptions): Promise<boolean>;
43
+ getStatusAsOwner(key: string): Promise<KeyStatus>;
44
+ static editable(key: string): boolean;
45
+ }