@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.
- package/dist/model/object-collection.d.ts +1 -1
- package/dist/model/object-collection.js +2 -2
- package/dist/model/object.d.ts +1 -1
- package/dist/model/object.js +2 -2
- package/dist/model/space.d.ts +21 -0
- package/dist/model/space.js +7 -0
- package/dist/model/tree.d.ts +11 -9
- package/dist/model/tree.js +3 -3
- package/dist/protocols/space.d.ts +3 -1
- package/dist/space/global-space.js +5 -5
- package/dist/space/object-space.d.ts +8 -5
- package/dist/space/object-space.js +138 -137
- package/dist/space/space.d.ts +3 -1
- package/dist/space/space.js +3 -1
- package/package.json +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ObjectCollectionRepositoryClass = void 0;
|
|
4
|
-
const
|
|
5
|
-
class ObjectCollectionRepositoryClass extends
|
|
4
|
+
const sequelize_1 = require("sequelize");
|
|
5
|
+
class ObjectCollectionRepositoryClass extends sequelize_1.Model {
|
|
6
6
|
}
|
|
7
7
|
exports.ObjectCollectionRepositoryClass = ObjectCollectionRepositoryClass;
|
package/dist/model/object.d.ts
CHANGED
package/dist/model/object.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ObjectRepositoryClass = void 0;
|
|
4
|
-
const
|
|
5
|
-
class ObjectRepositoryClass extends
|
|
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;
|
package/dist/model/tree.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Model } from '
|
|
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:
|
|
84
|
-
updatedAt:
|
|
83
|
+
createdAt: Date;
|
|
84
|
+
updatedAt: Date;
|
|
85
|
+
size: number;
|
|
86
|
+
count: number;
|
|
85
87
|
Object: ObjectModel;
|
|
86
|
-
static deepCreate(
|
|
88
|
+
static deepCreate(_data: CreationTreeModel): Promise<TreeModel>;
|
|
87
89
|
[key: string]: any;
|
|
88
90
|
}
|
|
89
91
|
export type TreeRepository = typeof TreeRepositoryClass;
|
package/dist/model/tree.js
CHANGED
|
@@ -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
|
|
5
|
-
class TreeRepositoryClass extends
|
|
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(
|
|
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
|
|
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
|
|
121
|
+
const treeRefCount = yield this.treeRepository.count({
|
|
122
122
|
where,
|
|
123
123
|
});
|
|
124
|
-
debug('delete.$
|
|
125
|
-
if (
|
|
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
|
-
[
|
|
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
|
|
79
|
-
private
|
|
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
|
|
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
|
-
|
|
63
|
-
key: '/config.yml',
|
|
63
|
+
did: this.options.spaceDid,
|
|
64
64
|
};
|
|
65
65
|
debug('isSpaceCreated.before', JSON.stringify(where));
|
|
66
|
-
const created =
|
|
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({
|
|
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
|
-
[
|
|
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
|
|
302
|
+
const tree = yield this.options.treeRepository.findOne({
|
|
331
303
|
where,
|
|
332
304
|
include: this.options.objectRepository,
|
|
333
305
|
});
|
|
334
306
|
return {
|
|
335
|
-
key:
|
|
336
|
-
name: (0, path_1.basename)(
|
|
337
|
-
isDir:
|
|
338
|
-
size:
|
|
339
|
-
lastModified: new Date(
|
|
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:
|
|
342
|
-
absolutePath: (0, path_1.join)(
|
|
343
|
-
metadata:
|
|
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
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
-
|
|
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), {
|
|
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
|
-
|
|
585
|
-
},
|
|
586
|
-
type: model_1.TreeModelType.FILE,
|
|
587
|
+
key,
|
|
588
|
+
type: model_1.TreeModelType.FOLDER,
|
|
587
589
|
};
|
|
588
|
-
|
|
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
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
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,
|
package/dist/space/space.d.ts
CHANGED
|
@@ -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);
|
package/dist/space/space.js
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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
|
-
"
|
|
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": "
|
|
56
|
+
"gitHead": "81b6a0d179194b4fe9c2411b24b74a3015a4dac0"
|
|
57
57
|
}
|