-
Notifications
You must be signed in to change notification settings - Fork 517
/
ownedMap.ts
115 lines (100 loc) · 3.65 KB
/
ownedMap.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*!
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { fromBase64ToUtf8 } from "@microsoft/fluid-core-utils";
import { ISharedMap, SharedMap } from "@microsoft/fluid-map";
import { FileMode, ISequencedDocumentMessage, ITree, TreeEntry } from "@microsoft/fluid-protocol-definitions";
import { IComponentRuntime, IObjectStorageService } from "@microsoft/fluid-runtime-definitions";
import { debug } from "./debug";
import { OwnedMapFactory } from "./ownedMapFactory";
const ownerPath = "owner";
/**
* Implementation of a map shared object
*/
export class OwnedSharedMap extends SharedMap implements ISharedMap {
/**
* Create a new owned shared map
*
* @param runtime - component runtime the new owned shared map belongs to
* @param id - optional name of the owned shared map
* @returns newly create owned shared map (but not attached yet)
*/
public static create(runtime: IComponentRuntime, id?: string) {
return runtime.createChannel(id, OwnedMapFactory.Type) as OwnedSharedMap;
}
/**
* Get a factory for OwnedSharedMap to register with the component.
*
* @returns a factory that creates and load OwnedSharedMap
*/
public static getFactory() {
return new OwnedMapFactory();
}
public owner: string;
public getOwner() {
return this.owner;
}
public snapshot(): ITree {
const tree = super.snapshot();
if (this.getOwner()) {
tree.entries.push({
mode: FileMode.File,
path: ownerPath,
type: TreeEntry[TreeEntry.Blob],
value: {
contents: this.getOwner(),
encoding: "utf-8",
},
});
}
return tree;
}
// This is a convenience method that should probably go
public isOwner(clientId: string): boolean {
if (clientId === undefined) {
return false;
}
const quorum = this.runtime.getQuorum();
const member = quorum.getMember(clientId);
return this.owner === member.client.user.id;
}
// eslint-disable-next-line @typescript-eslint/promise-function-async
protected processCore(message: ISequencedDocumentMessage, local: boolean): Promise<any> {
if (this.getMessageOwner(message) !== this.owner) {
debug("A non owner attempted to modify this object");
return;
} else {
super.processCore(message, local);
}
}
/**
* {@inheritDoc @microsoft/fluid-shared-object-base#SharedObject.loadCore}
*/
protected async loadCore(
branchId: string,
storage: IObjectStorageService) {
const owner = await storage.read(ownerPath);
this.owner = fromBase64ToUtf8(owner);
return super.loadCore(branchId, storage);
}
protected setOwner(): string | undefined {
if (this.owner !== undefined) {
return this.owner;
} else if (this.runtime.clientId === undefined) {
debug("Attempted to set owner, but no clientId");
return undefined;
}
const clientId = this.runtime.clientId;
const quorum = this.runtime.getQuorum();
const sequencedClient = quorum.getMember(clientId);
this.owner = sequencedClient.client.user.id;
debug(`Set Owner to ${this.owner}`);
return this.owner;
}
private getMessageOwner(message: ISequencedDocumentMessage): string {
const quorum = this.runtime.getQuorum();
const member = quorum.getMember(message.clientId);
return member.client.user.id;
}
}