@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.
- package/dist/drivers/base.d.ts +5 -5
- package/dist/drivers/base.js +8 -8
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/meta/object.d.ts +5 -0
- package/dist/model/index.d.ts +3 -0
- package/dist/model/index.js +19 -0
- package/dist/model/object-collection.d.ts +28 -0
- package/dist/model/object-collection.js +7 -0
- package/dist/model/object.d.ts +59 -0
- package/dist/model/object.js +7 -0
- package/dist/model/tree.d.ts +94 -0
- package/dist/model/tree.js +18 -0
- package/dist/protocols/space-operator.d.ts +2 -0
- package/dist/protocols/space-owner-operator.d.ts +30 -4
- package/dist/schemas/global-space.d.ts +2 -0
- package/dist/schemas/global-space.js +21 -0
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/object-space.d.ts +6 -0
- package/dist/schemas/object-space.js +39 -0
- package/dist/space/global-space.d.ts +43 -0
- package/dist/space/global-space.js +153 -0
- package/dist/space/index.d.ts +3 -45
- package/dist/space/index.js +16 -187
- package/dist/space/object-space.d.ts +111 -0
- package/dist/space/object-space.js +652 -0
- package/dist/space/space.d.ts +45 -0
- package/dist/space/space.js +190 -0
- package/dist/utils/common.d.ts +3 -0
- package/dist/utils/common.js +17 -0
- package/dist/utils/hash.d.ts +20 -0
- package/dist/utils/hash.js +60 -0
- package/dist/utils/index.d.ts +3 -2
- package/dist/utils/index.js +3 -2
- package/dist/utils/{string-to-stream.d.ts → stream.d.ts} +2 -0
- package/dist/utils/stream.js +23 -0
- package/package.json +11 -2
- package/dist/utils/stream-to-string.d.ts +0 -1
- package/dist/utils/stream-to-string.js +0 -10
- 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
|
+
}
|