@fluidframework/fluid-static 2.0.0-internal.3.0.1 → 2.0.0-internal.3.1.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/.eslintrc.js +8 -10
- package/.mocharc.js +2 -2
- package/CHANGELOG.md +48 -51
- package/api-extractor.json +2 -2
- package/dist/fluidContainer.d.ts.map +1 -1
- package/dist/fluidContainer.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/rootDataObject.d.ts.map +1 -1
- package/dist/rootDataObject.js +3 -1
- package/dist/rootDataObject.js.map +1 -1
- package/dist/serviceAudience.d.ts.map +1 -1
- package/dist/serviceAudience.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1 -4
- package/dist/utils.js.map +1 -1
- package/lib/fluidContainer.d.ts.map +1 -1
- package/lib/fluidContainer.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/rootDataObject.d.ts.map +1 -1
- package/lib/rootDataObject.js +3 -1
- package/lib/rootDataObject.js.map +1 -1
- package/lib/serviceAudience.d.ts.map +1 -1
- package/lib/serviceAudience.js.map +1 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js.map +1 -1
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +1 -4
- package/lib/utils.js.map +1 -1
- package/package.json +105 -104
- package/prettier.config.cjs +1 -1
- package/src/fluidContainer.ts +264 -260
- package/src/index.ts +6 -2
- package/src/rootDataObject.ts +152 -148
- package/src/serviceAudience.ts +137 -134
- package/src/types.ts +105 -101
- package/src/utils.ts +30 -42
- package/tsconfig.esnext.json +5 -5
- package/tsconfig.json +10 -16
package/src/rootDataObject.ts
CHANGED
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
BaseContainerRuntimeFactory,
|
|
7
|
+
DataObject,
|
|
8
|
+
DataObjectFactory,
|
|
9
|
+
defaultRouteRequestHandler,
|
|
10
10
|
} from "@fluidframework/aqueduct";
|
|
11
11
|
import { IContainerRuntime } from "@fluidframework/container-runtime-definitions";
|
|
12
12
|
import { IFluidLoadable } from "@fluidframework/core-interfaces";
|
|
13
13
|
import { FlushMode } from "@fluidframework/runtime-definitions";
|
|
14
14
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
ContainerSchema,
|
|
16
|
+
DataObjectClass,
|
|
17
|
+
IRootDataObject,
|
|
18
|
+
LoadableObjectClass,
|
|
19
|
+
LoadableObjectClassRecord,
|
|
20
|
+
LoadableObjectRecord,
|
|
21
|
+
SharedObjectClass,
|
|
22
22
|
} from "./types";
|
|
23
23
|
import { isDataObjectClass, isSharedObjectClass, parseDataObjectsFromSharedObjects } from "./utils";
|
|
24
24
|
|
|
@@ -26,111 +26,114 @@ import { isDataObjectClass, isSharedObjectClass, parseDataObjectsFromSharedObjec
|
|
|
26
26
|
* Input props for {@link RootDataObject.initializingFirstTime}.
|
|
27
27
|
*/
|
|
28
28
|
export interface RootDataObjectProps {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Initial object structure with which the {@link RootDataObject} will be first-time initialized.
|
|
31
|
+
*
|
|
32
|
+
* @see {@link RootDataObject.initializingFirstTime}
|
|
33
|
+
*/
|
|
34
|
+
initialObjects: LoadableObjectClassRecord;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* The entry-point/root collaborative object of the {@link IFluidContainer | Fluid Container}.
|
|
39
39
|
* Abstracts the dynamic code required to build a Fluid Container into a static representation for end customers.
|
|
40
40
|
*/
|
|
41
|
-
export class RootDataObject
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
41
|
+
export class RootDataObject
|
|
42
|
+
extends DataObject<{ InitialState: RootDataObjectProps }>
|
|
43
|
+
implements IRootDataObject
|
|
44
|
+
{
|
|
45
|
+
private readonly initialObjectsDirKey = "initial-objects-key";
|
|
46
|
+
private readonly _initialObjects: LoadableObjectRecord = {};
|
|
47
|
+
|
|
48
|
+
private get initialObjectsDir() {
|
|
49
|
+
const dir = this.root.getSubDirectory(this.initialObjectsDirKey);
|
|
50
|
+
if (dir === undefined) {
|
|
51
|
+
throw new Error("InitialObjects sub-directory was not initialized");
|
|
52
|
+
}
|
|
53
|
+
return dir;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The first time this object is initialized, creates each object identified in
|
|
58
|
+
* {@link RootDataObjectProps.initialObjects} and stores them as unique values in the root directory.
|
|
59
|
+
*
|
|
60
|
+
* @see {@link @fluidframework/aqueduct#PureDataObject.initializingFirstTime}
|
|
61
|
+
*/
|
|
62
|
+
protected async initializingFirstTime(props: RootDataObjectProps) {
|
|
63
|
+
this.root.createSubDirectory(this.initialObjectsDirKey);
|
|
64
|
+
|
|
65
|
+
// Create initial objects provided by the developer
|
|
66
|
+
const initialObjectsP: Promise<void>[] = [];
|
|
67
|
+
Object.entries(props.initialObjects).forEach(([id, objectClass]) => {
|
|
68
|
+
const createObject = async () => {
|
|
69
|
+
const obj = await this.create(objectClass);
|
|
70
|
+
this.initialObjectsDir.set(id, obj.handle);
|
|
71
|
+
};
|
|
72
|
+
initialObjectsP.push(createObject());
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await Promise.all(initialObjectsP);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Every time an instance is initialized, loads all of the initial objects in the root directory so they can be
|
|
80
|
+
* accessed immediately.
|
|
81
|
+
*
|
|
82
|
+
* @see {@link @fluidframework/aqueduct#PureDataObject.hasInitialized}
|
|
83
|
+
*/
|
|
84
|
+
protected async hasInitialized() {
|
|
85
|
+
// We will always load the initial objects so they are available to the developer
|
|
86
|
+
const loadInitialObjectsP: Promise<void>[] = [];
|
|
87
|
+
for (const [key, value] of Array.from(this.initialObjectsDir.entries())) {
|
|
88
|
+
const loadDir = async () => {
|
|
89
|
+
const obj = await value.get();
|
|
90
|
+
Object.assign(this._initialObjects, { [key]: obj });
|
|
91
|
+
};
|
|
92
|
+
loadInitialObjectsP.push(loadDir());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await Promise.all(loadInitialObjectsP);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* {@inheritDoc IRootDataObject.initialObjects}
|
|
100
|
+
*/
|
|
101
|
+
public get initialObjects(): LoadableObjectRecord {
|
|
102
|
+
if (Object.keys(this._initialObjects).length === 0) {
|
|
103
|
+
throw new Error("Initial Objects were not correctly initialized");
|
|
104
|
+
}
|
|
105
|
+
return this._initialObjects;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* {@inheritDoc IRootDataObject.create}
|
|
110
|
+
*/
|
|
111
|
+
public async create<T extends IFluidLoadable>(objectClass: LoadableObjectClass<T>): Promise<T> {
|
|
112
|
+
if (isDataObjectClass(objectClass)) {
|
|
113
|
+
return this.createDataObject<T>(objectClass);
|
|
114
|
+
} else if (isSharedObjectClass(objectClass)) {
|
|
115
|
+
return this.createSharedObject<T>(objectClass);
|
|
116
|
+
}
|
|
117
|
+
throw new Error("Could not create new Fluid object because an unknown object was passed");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private async createDataObject<T extends IFluidLoadable>(
|
|
121
|
+
dataObjectClass: DataObjectClass<T>,
|
|
122
|
+
): Promise<T> {
|
|
123
|
+
const factory = dataObjectClass.factory;
|
|
124
|
+
const packagePath = [...this.context.packagePath, factory.type];
|
|
125
|
+
const dataStore = await this.context.containerRuntime.createDataStore(packagePath);
|
|
126
|
+
const entryPoint = await dataStore.entryPoint?.get();
|
|
127
|
+
return entryPoint as unknown as T;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private createSharedObject<T extends IFluidLoadable>(
|
|
131
|
+
sharedObjectClass: SharedObjectClass<T>,
|
|
132
|
+
): T {
|
|
133
|
+
const factory = sharedObjectClass.getFactory();
|
|
134
|
+
const obj = this.runtime.createChannel(undefined, factory.type);
|
|
135
|
+
return obj as unknown as T;
|
|
136
|
+
}
|
|
134
137
|
}
|
|
135
138
|
|
|
136
139
|
const rootDataStoreId = "rootDOId";
|
|
@@ -144,42 +147,43 @@ const rootDataStoreId = "rootDOId";
|
|
|
144
147
|
* to the container runtime factory.
|
|
145
148
|
*/
|
|
146
149
|
export class DOProviderContainerRuntimeFactory extends BaseContainerRuntimeFactory {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
150
|
+
private readonly rootDataObjectFactory: DataObjectFactory<
|
|
151
|
+
RootDataObject,
|
|
152
|
+
{
|
|
153
|
+
InitialState: RootDataObjectProps;
|
|
154
|
+
}
|
|
155
|
+
>;
|
|
156
|
+
|
|
157
|
+
private readonly initialObjects: LoadableObjectClassRecord;
|
|
158
|
+
|
|
159
|
+
constructor(schema: ContainerSchema) {
|
|
160
|
+
const [registryEntries, sharedObjects] = parseDataObjectsFromSharedObjects(schema);
|
|
161
|
+
const rootDataObjectFactory = new DataObjectFactory(
|
|
162
|
+
"rootDO",
|
|
163
|
+
RootDataObject,
|
|
164
|
+
sharedObjects,
|
|
165
|
+
{},
|
|
166
|
+
registryEntries,
|
|
167
|
+
);
|
|
168
|
+
super(
|
|
169
|
+
[rootDataObjectFactory.registryEntry],
|
|
170
|
+
undefined,
|
|
171
|
+
[defaultRouteRequestHandler(rootDataStoreId)],
|
|
172
|
+
// temporary workaround to disable message batching until the message batch size issue is resolved
|
|
173
|
+
// resolution progress is tracked by the Feature 465 work item in AzDO
|
|
174
|
+
{ flushMode: FlushMode.Immediate },
|
|
175
|
+
);
|
|
176
|
+
this.rootDataObjectFactory = rootDataObjectFactory;
|
|
177
|
+
this.initialObjects = schema.initialObjects;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* {@inheritDoc @fluidframework/aqueduct#BaseContainerRuntimeFactory.containerInitializingFirstTime}
|
|
182
|
+
*/
|
|
183
|
+
protected async containerInitializingFirstTime(runtime: IContainerRuntime) {
|
|
184
|
+
// The first time we create the container we create the RootDataObject
|
|
185
|
+
await this.rootDataObjectFactory.createRootInstance(rootDataStoreId, runtime, {
|
|
186
|
+
initialObjects: this.initialObjects,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
185
189
|
}
|
package/src/serviceAudience.ts
CHANGED
|
@@ -19,138 +19,141 @@ import { IServiceAudience, IServiceAudienceEvents, IMember, Myself } from "./typ
|
|
|
19
19
|
* @typeParam M - A service-specific {@link IMember} implementation.
|
|
20
20
|
*/
|
|
21
21
|
export abstract class ServiceAudience<M extends IMember = IMember>
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
22
|
+
extends TypedEventEmitter<IServiceAudienceEvents<M>>
|
|
23
|
+
implements IServiceAudience<M>
|
|
24
|
+
{
|
|
25
|
+
/**
|
|
26
|
+
* Audience object which includes all the existing members of the {@link IFluidContainer | container}.
|
|
27
|
+
*/
|
|
28
|
+
protected readonly audience: IAudience;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Retain the most recent member list.
|
|
32
|
+
*
|
|
33
|
+
* @remarks
|
|
34
|
+
*
|
|
35
|
+
* This is so we have more information about a member leaving the audience in the `removeMember` event.
|
|
36
|
+
*
|
|
37
|
+
* It allows us to match the behavior of the `addMember` event where it only fires on a change to the members this
|
|
38
|
+
* class exposes (and would actually produce a change in what `getMembers` returns).
|
|
39
|
+
*
|
|
40
|
+
* It also allows us to provide the client details in the event which makes it easier to find that client connection
|
|
41
|
+
* in a map keyed on the `userId` and not `clientId`.
|
|
42
|
+
*
|
|
43
|
+
* This map will always be up-to-date in a `removeMember` event because it is set once at construction and in
|
|
44
|
+
* every `addMember` event. It is mapped `clientId` to `M` to be better work with what the {@link IServiceAudience}
|
|
45
|
+
* events provide.
|
|
46
|
+
*/
|
|
47
|
+
protected lastMembers: Map<string, M> = new Map();
|
|
48
|
+
|
|
49
|
+
constructor(
|
|
50
|
+
/**
|
|
51
|
+
* Fluid Container to read the audience from.
|
|
52
|
+
*/
|
|
53
|
+
protected readonly container: IContainer,
|
|
54
|
+
) {
|
|
55
|
+
super();
|
|
56
|
+
this.audience = container.audience;
|
|
57
|
+
|
|
58
|
+
// getMembers will assign lastMembers so the removeMember event has what it needs
|
|
59
|
+
// in case it would fire before getMembers otherwise gets called the first time
|
|
60
|
+
this.getMembers();
|
|
61
|
+
|
|
62
|
+
this.audience.on("addMember", (clientId: string, details: IClient) => {
|
|
63
|
+
if (this.shouldIncludeAsMember(details)) {
|
|
64
|
+
const member = this.getMember(clientId);
|
|
65
|
+
this.emit("memberAdded", clientId, member);
|
|
66
|
+
this.emit("membersChanged");
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
this.audience.on("removeMember", (clientId: string) => {
|
|
71
|
+
if (this.lastMembers.has(clientId)) {
|
|
72
|
+
this.emit("memberRemoved", clientId, this.lastMembers.get(clientId));
|
|
73
|
+
this.emit("membersChanged");
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
this.container.on("connected", () => this.emit("membersChanged"));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Provides ability for inheriting class to modify/extend the audience object.
|
|
82
|
+
*
|
|
83
|
+
* @param audienceMember - Record of a specific audience member.
|
|
84
|
+
*/
|
|
85
|
+
protected abstract createServiceMember(audienceMember: IClient): M;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* {@inheritDoc IServiceAudience.getMembers}
|
|
89
|
+
*/
|
|
90
|
+
public getMembers(): Map<string, M> {
|
|
91
|
+
const users = new Map<string, M>();
|
|
92
|
+
const clientMemberMap = new Map<string, M>();
|
|
93
|
+
// Iterate through the members and get the user specifics.
|
|
94
|
+
this.audience.getMembers().forEach((member: IClient, clientId: string) => {
|
|
95
|
+
if (this.shouldIncludeAsMember(member)) {
|
|
96
|
+
const userId = member.user.id;
|
|
97
|
+
// Ensure we're tracking the user
|
|
98
|
+
let user = users.get(userId);
|
|
99
|
+
if (user === undefined) {
|
|
100
|
+
user = this.createServiceMember(member);
|
|
101
|
+
users.set(userId, user);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Add this connection to their collection
|
|
105
|
+
user.connections.push({ id: clientId, mode: member.mode });
|
|
106
|
+
clientMemberMap.set(clientId, user);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
this.lastMembers = clientMemberMap;
|
|
110
|
+
return users;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* {@inheritDoc IServiceAudience.getMyself}
|
|
115
|
+
*/
|
|
116
|
+
public getMyself(): Myself<M> | undefined {
|
|
117
|
+
const clientId = this.container.clientId;
|
|
118
|
+
if (clientId === undefined) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const member = this.getMember(clientId);
|
|
123
|
+
if (member === undefined) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const myself: Myself<M> = { ...member, currentConnection: clientId };
|
|
128
|
+
|
|
129
|
+
return myself;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private getMember(clientId: string): M | undefined {
|
|
133
|
+
// Fetch the user ID assoicated with this client ID from the runtime
|
|
134
|
+
const internalAudienceMember = this.audience.getMember(clientId);
|
|
135
|
+
if (internalAudienceMember === undefined) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
// Return the member object with any other clients associated for this user
|
|
139
|
+
const allMembers = this.getMembers();
|
|
140
|
+
const member = allMembers.get(internalAudienceMember?.user.id);
|
|
141
|
+
if (member === undefined) {
|
|
142
|
+
throw Error(
|
|
143
|
+
`Attempted to fetch client ${clientId} that is not part of the current member list`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return member;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Provides ability for the inheriting class to include/omit specific members.
|
|
151
|
+
* An example use case is omitting the summarizer client.
|
|
152
|
+
*
|
|
153
|
+
* @param member - Member to be included/omitted.
|
|
154
|
+
*/
|
|
155
|
+
protected shouldIncludeAsMember(member: IClient): boolean {
|
|
156
|
+
// Include only human members
|
|
157
|
+
return member.details.capabilities.interactive;
|
|
158
|
+
}
|
|
156
159
|
}
|