@fluidframework/presence 2.10.0-307399
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/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/alpha.d.ts +58 -0
- package/dist/baseTypes.d.ts +24 -0
- package/dist/baseTypes.d.ts.map +1 -0
- package/dist/baseTypes.js +7 -0
- package/dist/baseTypes.js.map +1 -0
- package/dist/container-definitions/containerExtensions.d.ts +137 -0
- package/dist/container-definitions/containerExtensions.d.ts.map +1 -0
- package/dist/container-definitions/containerExtensions.js +7 -0
- package/dist/container-definitions/containerExtensions.js.map +1 -0
- package/dist/container-definitions/index.d.ts +7 -0
- package/dist/container-definitions/index.d.ts.map +1 -0
- package/dist/container-definitions/index.js +7 -0
- package/dist/container-definitions/index.js.map +1 -0
- package/dist/container-definitions/runtime.d.ts +12 -0
- package/dist/container-definitions/runtime.d.ts.map +1 -0
- package/dist/container-definitions/runtime.js +7 -0
- package/dist/container-definitions/runtime.js.map +1 -0
- package/dist/core-interfaces/exposedUtilityTypes.d.ts +446 -0
- package/dist/core-interfaces/exposedUtilityTypes.d.ts.map +1 -0
- package/dist/core-interfaces/exposedUtilityTypes.js +11 -0
- package/dist/core-interfaces/exposedUtilityTypes.js.map +1 -0
- package/dist/core-interfaces/index.d.ts +10 -0
- package/dist/core-interfaces/index.d.ts.map +1 -0
- package/dist/core-interfaces/index.js +7 -0
- package/dist/core-interfaces/index.js.map +1 -0
- package/dist/core-interfaces/jsonDeserialized.d.ts +109 -0
- package/dist/core-interfaces/jsonDeserialized.d.ts.map +1 -0
- package/dist/core-interfaces/jsonDeserialized.js +7 -0
- package/dist/core-interfaces/jsonDeserialized.js.map +1 -0
- package/dist/core-interfaces/jsonSerializable.d.ts +120 -0
- package/dist/core-interfaces/jsonSerializable.d.ts.map +1 -0
- package/dist/core-interfaces/jsonSerializable.js +7 -0
- package/dist/core-interfaces/jsonSerializable.js.map +1 -0
- package/dist/core-interfaces/jsonSerializationErrors.d.ts +31 -0
- package/dist/core-interfaces/jsonSerializationErrors.d.ts.map +1 -0
- package/dist/core-interfaces/jsonSerializationErrors.js +7 -0
- package/dist/core-interfaces/jsonSerializationErrors.js.map +1 -0
- package/dist/core-interfaces/jsonType.d.ts +29 -0
- package/dist/core-interfaces/jsonType.d.ts.map +1 -0
- package/dist/core-interfaces/jsonType.js +7 -0
- package/dist/core-interfaces/jsonType.js.map +1 -0
- package/dist/datastorePresenceManagerFactory.d.ts +48 -0
- package/dist/datastorePresenceManagerFactory.d.ts.map +1 -0
- package/dist/datastorePresenceManagerFactory.js +79 -0
- package/dist/datastorePresenceManagerFactory.js.map +1 -0
- package/dist/datastoreSupport.d.ts +31 -0
- package/dist/datastoreSupport.d.ts.map +1 -0
- package/dist/datastoreSupport.js +82 -0
- package/dist/datastoreSupport.js.map +1 -0
- package/dist/events/events.d.ts +198 -0
- package/dist/events/events.d.ts.map +1 -0
- package/dist/events/events.js +157 -0
- package/dist/events/events.js.map +1 -0
- package/dist/experimentalAccess.d.ts +15 -0
- package/dist/experimentalAccess.d.ts.map +1 -0
- package/dist/experimentalAccess.js +46 -0
- package/dist/experimentalAccess.js.map +1 -0
- package/dist/exposedInternalTypes.d.ts +100 -0
- package/dist/exposedInternalTypes.d.ts.map +1 -0
- package/dist/exposedInternalTypes.js +19 -0
- package/dist/exposedInternalTypes.js.map +1 -0
- package/dist/exposedUtilityTypes.d.ts +63 -0
- package/dist/exposedUtilityTypes.d.ts.map +1 -0
- package/dist/exposedUtilityTypes.js +7 -0
- package/dist/exposedUtilityTypes.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/internalTypes.d.ts +39 -0
- package/dist/internalTypes.d.ts.map +1 -0
- package/dist/internalTypes.js +14 -0
- package/dist/internalTypes.js.map +1 -0
- package/dist/latestMapValueManager.d.ts +182 -0
- package/dist/latestMapValueManager.d.ts.map +1 -0
- package/dist/latestMapValueManager.js +206 -0
- package/dist/latestMapValueManager.js.map +1 -0
- package/dist/latestValueControls.d.ts +44 -0
- package/dist/latestValueControls.d.ts.map +1 -0
- package/dist/latestValueControls.js +28 -0
- package/dist/latestValueControls.js.map +1 -0
- package/dist/latestValueManager.d.ts +69 -0
- package/dist/latestValueManager.d.ts.map +1 -0
- package/dist/latestValueManager.js +100 -0
- package/dist/latestValueManager.js.map +1 -0
- package/dist/latestValueTypes.d.ts +44 -0
- package/dist/latestValueTypes.d.ts.map +1 -0
- package/dist/latestValueTypes.js +7 -0
- package/dist/latestValueTypes.js.map +1 -0
- package/dist/notificationsManager.d.ts +101 -0
- package/dist/notificationsManager.d.ts.map +1 -0
- package/dist/notificationsManager.js +82 -0
- package/dist/notificationsManager.js.map +1 -0
- package/dist/package.json +15 -0
- package/dist/presence.d.ts +180 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +23 -0
- package/dist/presence.js.map +1 -0
- package/dist/presenceDatastoreManager.d.ts +91 -0
- package/dist/presenceDatastoreManager.d.ts.map +1 -0
- package/dist/presenceDatastoreManager.js +248 -0
- package/dist/presenceDatastoreManager.js.map +1 -0
- package/dist/presenceManager.d.ts +20 -0
- package/dist/presenceManager.d.ts.map +1 -0
- package/dist/presenceManager.js +104 -0
- package/dist/presenceManager.js.map +1 -0
- package/dist/presenceStates.d.ts +78 -0
- package/dist/presenceStates.d.ts.map +1 -0
- package/dist/presenceStates.js +182 -0
- package/dist/presenceStates.js.map +1 -0
- package/dist/stateDatastore.d.ts +35 -0
- package/dist/stateDatastore.d.ts.map +1 -0
- package/dist/stateDatastore.js +26 -0
- package/dist/stateDatastore.js.map +1 -0
- package/dist/systemWorkspace.d.ts +51 -0
- package/dist/systemWorkspace.d.ts.map +1 -0
- package/dist/systemWorkspace.js +180 -0
- package/dist/systemWorkspace.js.map +1 -0
- package/dist/types.d.ts +92 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/valueManager.d.ts +19 -0
- package/dist/valueManager.d.ts.map +1 -0
- package/dist/valueManager.js +26 -0
- package/dist/valueManager.js.map +1 -0
- package/lib/alpha.d.ts +58 -0
- package/lib/baseTypes.d.ts +24 -0
- package/lib/baseTypes.d.ts.map +1 -0
- package/lib/baseTypes.js +6 -0
- package/lib/baseTypes.js.map +1 -0
- package/lib/container-definitions/containerExtensions.d.ts +137 -0
- package/lib/container-definitions/containerExtensions.d.ts.map +1 -0
- package/lib/container-definitions/containerExtensions.js +6 -0
- package/lib/container-definitions/containerExtensions.js.map +1 -0
- package/lib/container-definitions/index.d.ts +7 -0
- package/lib/container-definitions/index.d.ts.map +1 -0
- package/lib/container-definitions/index.js +6 -0
- package/lib/container-definitions/index.js.map +1 -0
- package/lib/container-definitions/runtime.d.ts +12 -0
- package/lib/container-definitions/runtime.d.ts.map +1 -0
- package/lib/container-definitions/runtime.js +6 -0
- package/lib/container-definitions/runtime.js.map +1 -0
- package/lib/core-interfaces/exposedUtilityTypes.d.ts +446 -0
- package/lib/core-interfaces/exposedUtilityTypes.d.ts.map +1 -0
- package/lib/core-interfaces/exposedUtilityTypes.js +10 -0
- package/lib/core-interfaces/exposedUtilityTypes.js.map +1 -0
- package/lib/core-interfaces/index.d.ts +10 -0
- package/lib/core-interfaces/index.d.ts.map +1 -0
- package/lib/core-interfaces/index.js +6 -0
- package/lib/core-interfaces/index.js.map +1 -0
- package/lib/core-interfaces/jsonDeserialized.d.ts +109 -0
- package/lib/core-interfaces/jsonDeserialized.d.ts.map +1 -0
- package/lib/core-interfaces/jsonDeserialized.js +6 -0
- package/lib/core-interfaces/jsonDeserialized.js.map +1 -0
- package/lib/core-interfaces/jsonSerializable.d.ts +120 -0
- package/lib/core-interfaces/jsonSerializable.d.ts.map +1 -0
- package/lib/core-interfaces/jsonSerializable.js +6 -0
- package/lib/core-interfaces/jsonSerializable.js.map +1 -0
- package/lib/core-interfaces/jsonSerializationErrors.d.ts +31 -0
- package/lib/core-interfaces/jsonSerializationErrors.d.ts.map +1 -0
- package/lib/core-interfaces/jsonSerializationErrors.js +6 -0
- package/lib/core-interfaces/jsonSerializationErrors.js.map +1 -0
- package/lib/core-interfaces/jsonType.d.ts +29 -0
- package/lib/core-interfaces/jsonType.d.ts.map +1 -0
- package/lib/core-interfaces/jsonType.js +6 -0
- package/lib/core-interfaces/jsonType.js.map +1 -0
- package/lib/datastorePresenceManagerFactory.d.ts +48 -0
- package/lib/datastorePresenceManagerFactory.d.ts.map +1 -0
- package/lib/datastorePresenceManagerFactory.js +75 -0
- package/lib/datastorePresenceManagerFactory.js.map +1 -0
- package/lib/datastoreSupport.d.ts +31 -0
- package/lib/datastoreSupport.d.ts.map +1 -0
- package/lib/datastoreSupport.js +77 -0
- package/lib/datastoreSupport.js.map +1 -0
- package/lib/events/events.d.ts +198 -0
- package/lib/events/events.d.ts.map +1 -0
- package/lib/events/events.js +152 -0
- package/lib/events/events.js.map +1 -0
- package/lib/experimentalAccess.d.ts +15 -0
- package/lib/experimentalAccess.d.ts.map +1 -0
- package/lib/experimentalAccess.js +42 -0
- package/lib/experimentalAccess.js.map +1 -0
- package/lib/exposedInternalTypes.d.ts +100 -0
- package/lib/exposedInternalTypes.d.ts.map +1 -0
- package/lib/exposedInternalTypes.js +16 -0
- package/lib/exposedInternalTypes.js.map +1 -0
- package/lib/exposedUtilityTypes.d.ts +63 -0
- package/lib/exposedUtilityTypes.d.ts.map +1 -0
- package/lib/exposedUtilityTypes.js +6 -0
- package/lib/exposedUtilityTypes.js.map +1 -0
- package/lib/index.d.ts +22 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +11 -0
- package/lib/index.js.map +1 -0
- package/lib/internalTypes.d.ts +39 -0
- package/lib/internalTypes.d.ts.map +1 -0
- package/lib/internalTypes.js +11 -0
- package/lib/internalTypes.js.map +1 -0
- package/lib/latestMapValueManager.d.ts +182 -0
- package/lib/latestMapValueManager.d.ts.map +1 -0
- package/lib/latestMapValueManager.js +202 -0
- package/lib/latestMapValueManager.js.map +1 -0
- package/lib/latestValueControls.d.ts +44 -0
- package/lib/latestValueControls.d.ts.map +1 -0
- package/lib/latestValueControls.js +24 -0
- package/lib/latestValueControls.js.map +1 -0
- package/lib/latestValueManager.d.ts +69 -0
- package/lib/latestValueManager.d.ts.map +1 -0
- package/lib/latestValueManager.js +96 -0
- package/lib/latestValueManager.js.map +1 -0
- package/lib/latestValueTypes.d.ts +44 -0
- package/lib/latestValueTypes.d.ts.map +1 -0
- package/lib/latestValueTypes.js +6 -0
- package/lib/latestValueTypes.js.map +1 -0
- package/lib/notificationsManager.d.ts +101 -0
- package/lib/notificationsManager.d.ts.map +1 -0
- package/lib/notificationsManager.js +78 -0
- package/lib/notificationsManager.js.map +1 -0
- package/lib/presence.d.ts +180 -0
- package/lib/presence.d.ts.map +1 -0
- package/lib/presence.js +20 -0
- package/lib/presence.js.map +1 -0
- package/lib/presenceDatastoreManager.d.ts +91 -0
- package/lib/presenceDatastoreManager.d.ts.map +1 -0
- package/lib/presenceDatastoreManager.js +244 -0
- package/lib/presenceDatastoreManager.js.map +1 -0
- package/lib/presenceManager.d.ts +20 -0
- package/lib/presenceManager.d.ts.map +1 -0
- package/lib/presenceManager.js +100 -0
- package/lib/presenceManager.js.map +1 -0
- package/lib/presenceStates.d.ts +78 -0
- package/lib/presenceStates.d.ts.map +1 -0
- package/lib/presenceStates.js +177 -0
- package/lib/presenceStates.js.map +1 -0
- package/lib/stateDatastore.d.ts +35 -0
- package/lib/stateDatastore.d.ts.map +1 -0
- package/lib/stateDatastore.js +21 -0
- package/lib/stateDatastore.js.map +1 -0
- package/lib/systemWorkspace.d.ts +51 -0
- package/lib/systemWorkspace.d.ts.map +1 -0
- package/lib/systemWorkspace.js +176 -0
- package/lib/systemWorkspace.js.map +1 -0
- package/lib/tsdoc-metadata.json +11 -0
- package/lib/types.d.ts +92 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +7 -0
- package/lib/types.js.map +1 -0
- package/lib/valueManager.d.ts +19 -0
- package/lib/valueManager.d.ts.map +1 -0
- package/lib/valueManager.js +21 -0
- package/lib/valueManager.js.map +1 -0
- package/package.json +175 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import type { SessionId } from "@fluidframework/id-compressor";
|
|
6
|
+
import type { ClientConnectionId } from "./baseTypes.js";
|
|
7
|
+
import type { PresenceNotifications, PresenceNotificationsSchema, PresenceStates, PresenceStatesSchema, PresenceWorkspaceAddress } from "./types.js";
|
|
8
|
+
import type { ISubscribable } from "@fluidframework/presence/internal/events";
|
|
9
|
+
/**
|
|
10
|
+
* A Fluid client session identifier.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* Each client once connected to a session is given a unique identifier for the
|
|
14
|
+
* duration of the session. If a client disconnects and reconnects, it will
|
|
15
|
+
* retain its identifier. Prefer use of {@link ISessionClient} as a way to
|
|
16
|
+
* identify clients in a session. {@link ISessionClient.sessionId} will provide
|
|
17
|
+
* the session ID.
|
|
18
|
+
*
|
|
19
|
+
* @alpha
|
|
20
|
+
*/
|
|
21
|
+
export type ClientSessionId = SessionId & {
|
|
22
|
+
readonly ClientSessionId: "ClientSessionId";
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The connection status of the {@link ISessionClient}.
|
|
26
|
+
*
|
|
27
|
+
* @alpha
|
|
28
|
+
*/
|
|
29
|
+
export declare const SessionClientStatus: {
|
|
30
|
+
/**
|
|
31
|
+
* The session client is connected to the Fluid service.
|
|
32
|
+
*/
|
|
33
|
+
readonly Connected: "Connected";
|
|
34
|
+
/**
|
|
35
|
+
* The session client is not connected to the Fluid service.
|
|
36
|
+
*/
|
|
37
|
+
readonly Disconnected: "Disconnected";
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Represents the connection status of an {@link ISessionClient}.
|
|
41
|
+
*
|
|
42
|
+
* This type can be either `'Connected'` or `'Disconnected'`, indicating whether
|
|
43
|
+
* the session client is currently connected to the Fluid service.
|
|
44
|
+
*
|
|
45
|
+
* When `'Disconnected'`:
|
|
46
|
+
* - State changes are kept locally and communicated to others upon reconnect.
|
|
47
|
+
* - Notification requests are discarded (silently).
|
|
48
|
+
*
|
|
49
|
+
* @alpha
|
|
50
|
+
*/
|
|
51
|
+
export type SessionClientStatus = (typeof SessionClientStatus)[keyof typeof SessionClientStatus];
|
|
52
|
+
/**
|
|
53
|
+
* A client within a Fluid session (period of container connectivity to service).
|
|
54
|
+
*
|
|
55
|
+
* @remarks
|
|
56
|
+
* Note: This is very preliminary session client representation.
|
|
57
|
+
*
|
|
58
|
+
* `ISessionClient` should be used as key to distinguish between different
|
|
59
|
+
* clients as they join, rejoin, and disconnect from a session. While a
|
|
60
|
+
* client's {@link ClientConnectionId} from {@link ISessionClient.getConnectionStatus}
|
|
61
|
+
* may change over time, `ISessionClient` will be fixed.
|
|
62
|
+
*
|
|
63
|
+
* @privateRemarks
|
|
64
|
+
* As this is evolved, pay attention to how this relates to Audience, Service
|
|
65
|
+
* Audience, and Quorum representations of clients and users.
|
|
66
|
+
*
|
|
67
|
+
* @sealed
|
|
68
|
+
* @alpha
|
|
69
|
+
*/
|
|
70
|
+
export interface ISessionClient<SpecificSessionClientId extends ClientSessionId = ClientSessionId> {
|
|
71
|
+
/**
|
|
72
|
+
* The session ID of the client that is stable over all connections.
|
|
73
|
+
*/
|
|
74
|
+
readonly sessionId: SpecificSessionClientId;
|
|
75
|
+
/**
|
|
76
|
+
* Get current client connection ID.
|
|
77
|
+
*
|
|
78
|
+
* @returns Current client connection ID.
|
|
79
|
+
*
|
|
80
|
+
* @remarks
|
|
81
|
+
* Connection ID will change on reconnect.
|
|
82
|
+
*
|
|
83
|
+
* If {@link ISessionClient.getConnectionStatus} is {@link (SessionClientStatus:variable).Disconnected}, this will represent the last known connection ID.
|
|
84
|
+
*/
|
|
85
|
+
getConnectionId(): ClientConnectionId;
|
|
86
|
+
/**
|
|
87
|
+
* Get connection status of session client.
|
|
88
|
+
*
|
|
89
|
+
* @returns Connection status of session client.
|
|
90
|
+
*
|
|
91
|
+
*/
|
|
92
|
+
getConnectionStatus(): SessionClientStatus;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Utility type limiting to a specific session client. (A session client with
|
|
96
|
+
* a specific session ID - not just any session ID.)
|
|
97
|
+
*
|
|
98
|
+
* @internal
|
|
99
|
+
*/
|
|
100
|
+
export type SpecificSessionClient<SpecificSessionClientId extends ClientSessionId> = string extends SpecificSessionClientId ? never : ISessionClient<SpecificSessionClientId>;
|
|
101
|
+
/**
|
|
102
|
+
* @sealed
|
|
103
|
+
* @alpha
|
|
104
|
+
*/
|
|
105
|
+
export interface PresenceEvents {
|
|
106
|
+
/**
|
|
107
|
+
* Raised when new client joins session.
|
|
108
|
+
*
|
|
109
|
+
* @eventProperty
|
|
110
|
+
*/
|
|
111
|
+
attendeeJoined: (attendee: ISessionClient) => void;
|
|
112
|
+
/**
|
|
113
|
+
* Raised when client appears disconnected from session.
|
|
114
|
+
*
|
|
115
|
+
* @eventProperty
|
|
116
|
+
*/
|
|
117
|
+
attendeeDisconnected: (attendee: ISessionClient) => void;
|
|
118
|
+
/**
|
|
119
|
+
* Raised when a workspace is activated within the session.
|
|
120
|
+
*
|
|
121
|
+
* "Activated" means that a workspace is being used by a client and this
|
|
122
|
+
* client is seeing information for the first time.
|
|
123
|
+
*
|
|
124
|
+
* @remarks
|
|
125
|
+
* Local workspaces may be passively acquired/registered when this event
|
|
126
|
+
* is raised. For a notifications workspace, that lazy registration must
|
|
127
|
+
* be done before the event handler returns to ensure no notifications
|
|
128
|
+
* are missed.
|
|
129
|
+
*/
|
|
130
|
+
workspaceActivated: (workspaceAddress: PresenceWorkspaceAddress, type: "States" | "Notifications" | "Unknown") => void;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Presence represents known clients within a session and their custom states and notifications.
|
|
134
|
+
*
|
|
135
|
+
* @sealed
|
|
136
|
+
* @alpha
|
|
137
|
+
*/
|
|
138
|
+
export interface IPresence {
|
|
139
|
+
/**
|
|
140
|
+
* Events for Notifications manager.
|
|
141
|
+
*/
|
|
142
|
+
readonly events: ISubscribable<PresenceEvents>;
|
|
143
|
+
/**
|
|
144
|
+
* Get all attendees in the session.
|
|
145
|
+
*
|
|
146
|
+
* @remarks
|
|
147
|
+
* Attendee states are dynamic and will change as clients join and leave
|
|
148
|
+
* the session.
|
|
149
|
+
*/
|
|
150
|
+
getAttendees(): ReadonlySet<ISessionClient>;
|
|
151
|
+
/**
|
|
152
|
+
* Lookup a specific attendee in the session.
|
|
153
|
+
*
|
|
154
|
+
* @param clientId - Client connection or session ID
|
|
155
|
+
*/
|
|
156
|
+
getAttendee(clientId: ClientConnectionId | ClientSessionId): ISessionClient;
|
|
157
|
+
/**
|
|
158
|
+
* Get this client's session client.
|
|
159
|
+
*
|
|
160
|
+
* @returns This client's session client.
|
|
161
|
+
*/
|
|
162
|
+
getMyself(): ISessionClient;
|
|
163
|
+
/**
|
|
164
|
+
* Acquires a PresenceStates workspace from store or adds new one.
|
|
165
|
+
*
|
|
166
|
+
* @param workspaceAddress - Address of the requested PresenceStates Workspace
|
|
167
|
+
* @param requestedContent - Requested states for the workspace
|
|
168
|
+
* @returns A PresenceStates workspace
|
|
169
|
+
*/
|
|
170
|
+
getStates<StatesSchema extends PresenceStatesSchema>(workspaceAddress: PresenceWorkspaceAddress, requestedContent: StatesSchema): PresenceStates<StatesSchema>;
|
|
171
|
+
/**
|
|
172
|
+
* Acquires a Notifications workspace from store or adds new one.
|
|
173
|
+
*
|
|
174
|
+
* @param workspaceAddress - Address of the requested Notifications Workspace
|
|
175
|
+
* @param requestedContent - Requested notifications for the workspace
|
|
176
|
+
* @returns A Notifications workspace
|
|
177
|
+
*/
|
|
178
|
+
getNotifications<NotificationsSchema extends PresenceNotificationsSchema>(notificationsId: PresenceWorkspaceAddress, requestedContent: NotificationsSchema): PresenceNotifications<NotificationsSchema>;
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=presence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EACX,qBAAqB,EACrB,2BAA2B,EAC3B,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG;IAAE,QAAQ,CAAC,eAAe,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAE1F;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;IAC/B;;OAEG;;IAGH;;OAEG;;CAEM,CAAC;AAEX;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,mBAAmB,GAC9B,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAc,CAC9B,uBAAuB,SAAS,eAAe,GAAG,eAAe;IAEjE;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,uBAAuB,CAAC;IAE5C;;;;;;;;;OASG;IACH,eAAe,IAAI,kBAAkB,CAAC;IAEtC;;;;;OAKG;IACH,mBAAmB,IAAI,mBAAmB,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,CAAC,uBAAuB,SAAS,eAAe,IAChF,MAAM,SAAS,uBAAuB,GAAG,KAAK,GAAG,cAAc,CAAC,uBAAuB,CAAC,CAAC;AAE1F;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;OAIG;IACH,cAAc,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;IAEnD;;;;OAIG;IACH,oBAAoB,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;IAEzD;;;;;;;;;;;OAWG;IACH,kBAAkB,EAAE,CACnB,gBAAgB,EAAE,wBAAwB,EAC1C,IAAI,EAAE,QAAQ,GAAG,eAAe,GAAG,SAAS,KACxC,IAAI,CAAC;CACV;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IAE/C;;;;;;OAMG;IACH,YAAY,IAAI,WAAW,CAAC,cAAc,CAAC,CAAC;IAE5C;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,kBAAkB,GAAG,eAAe,GAAG,cAAc,CAAC;IAE5E;;;;OAIG;IACH,SAAS,IAAI,cAAc,CAAC;IAE5B;;;;;;OAMG;IACH,SAAS,CAAC,YAAY,SAAS,oBAAoB,EAClD,gBAAgB,EAAE,wBAAwB,EAC1C,gBAAgB,EAAE,YAAY,GAC5B,cAAc,CAAC,YAAY,CAAC,CAAC;IAEhC;;;;;;OAMG;IACH,gBAAgB,CAAC,mBAAmB,SAAS,2BAA2B,EACvE,eAAe,EAAE,wBAAwB,EACzC,gBAAgB,EAAE,mBAAmB,GACnC,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;CAC9C"}
|
package/dist/presence.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.SessionClientStatus = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* The connection status of the {@link ISessionClient}.
|
|
10
|
+
*
|
|
11
|
+
* @alpha
|
|
12
|
+
*/
|
|
13
|
+
exports.SessionClientStatus = {
|
|
14
|
+
/**
|
|
15
|
+
* The session client is connected to the Fluid service.
|
|
16
|
+
*/
|
|
17
|
+
Connected: "Connected",
|
|
18
|
+
/**
|
|
19
|
+
* The session client is not connected to the Fluid service.
|
|
20
|
+
*/
|
|
21
|
+
Disconnected: "Disconnected",
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=presence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presence.js","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AA6BH;;;;GAIG;AACU,QAAA,mBAAmB,GAAG;IAClC;;OAEG;IACH,SAAS,EAAE,WAAW;IAEtB;;OAEG;IACH,YAAY,EAAE,cAAc;CACnB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { SessionId } from \"@fluidframework/id-compressor\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type {\n\tPresenceNotifications,\n\tPresenceNotificationsSchema,\n\tPresenceStates,\n\tPresenceStatesSchema,\n\tPresenceWorkspaceAddress,\n} from \"./types.js\";\n\nimport type { ISubscribable } from \"@fluidframework/presence/internal/events\";\n\n/**\n * A Fluid client session identifier.\n *\n * @remarks\n * Each client once connected to a session is given a unique identifier for the\n * duration of the session. If a client disconnects and reconnects, it will\n * retain its identifier. Prefer use of {@link ISessionClient} as a way to\n * identify clients in a session. {@link ISessionClient.sessionId} will provide\n * the session ID.\n *\n * @alpha\n */\nexport type ClientSessionId = SessionId & { readonly ClientSessionId: \"ClientSessionId\" };\n\n/**\n * The connection status of the {@link ISessionClient}.\n *\n * @alpha\n */\nexport const SessionClientStatus = {\n\t/**\n\t * The session client is connected to the Fluid service.\n\t */\n\tConnected: \"Connected\",\n\n\t/**\n\t * The session client is not connected to the Fluid service.\n\t */\n\tDisconnected: \"Disconnected\",\n} as const;\n\n/**\n * Represents the connection status of an {@link ISessionClient}.\n *\n * This type can be either `'Connected'` or `'Disconnected'`, indicating whether\n * the session client is currently connected to the Fluid service.\n *\n * When `'Disconnected'`:\n * - State changes are kept locally and communicated to others upon reconnect.\n * - Notification requests are discarded (silently).\n *\n * @alpha\n */\nexport type SessionClientStatus =\n\t(typeof SessionClientStatus)[keyof typeof SessionClientStatus];\n\n/**\n * A client within a Fluid session (period of container connectivity to service).\n *\n * @remarks\n * Note: This is very preliminary session client representation.\n *\n * `ISessionClient` should be used as key to distinguish between different\n * clients as they join, rejoin, and disconnect from a session. While a\n * client's {@link ClientConnectionId} from {@link ISessionClient.getConnectionStatus}\n * may change over time, `ISessionClient` will be fixed.\n *\n * @privateRemarks\n * As this is evolved, pay attention to how this relates to Audience, Service\n * Audience, and Quorum representations of clients and users.\n *\n * @sealed\n * @alpha\n */\nexport interface ISessionClient<\n\tSpecificSessionClientId extends ClientSessionId = ClientSessionId,\n> {\n\t/**\n\t * The session ID of the client that is stable over all connections.\n\t */\n\treadonly sessionId: SpecificSessionClientId;\n\n\t/**\n\t * Get current client connection ID.\n\t *\n\t * @returns Current client connection ID.\n\t *\n\t * @remarks\n\t * Connection ID will change on reconnect.\n\t *\n\t * If {@link ISessionClient.getConnectionStatus} is {@link (SessionClientStatus:variable).Disconnected}, this will represent the last known connection ID.\n\t */\n\tgetConnectionId(): ClientConnectionId;\n\n\t/**\n\t * Get connection status of session client.\n\t *\n\t * @returns Connection status of session client.\n\t *\n\t */\n\tgetConnectionStatus(): SessionClientStatus;\n}\n\n/**\n * Utility type limiting to a specific session client. (A session client with\n * a specific session ID - not just any session ID.)\n *\n * @internal\n */\nexport type SpecificSessionClient<SpecificSessionClientId extends ClientSessionId> =\n\tstring extends SpecificSessionClientId ? never : ISessionClient<SpecificSessionClientId>;\n\n/**\n * @sealed\n * @alpha\n */\nexport interface PresenceEvents {\n\t/**\n\t * Raised when new client joins session.\n\t *\n\t * @eventProperty\n\t */\n\tattendeeJoined: (attendee: ISessionClient) => void;\n\n\t/**\n\t * Raised when client appears disconnected from session.\n\t *\n\t * @eventProperty\n\t */\n\tattendeeDisconnected: (attendee: ISessionClient) => void;\n\n\t/**\n\t * Raised when a workspace is activated within the session.\n\t *\n\t * \"Activated\" means that a workspace is being used by a client and this\n\t * client is seeing information for the first time.\n\t *\n\t * @remarks\n\t * Local workspaces may be passively acquired/registered when this event\n\t * is raised. For a notifications workspace, that lazy registration must\n\t * be done before the event handler returns to ensure no notifications\n\t * are missed.\n\t */\n\tworkspaceActivated: (\n\t\tworkspaceAddress: PresenceWorkspaceAddress,\n\t\ttype: \"States\" | \"Notifications\" | \"Unknown\",\n\t) => void;\n}\n\n/**\n * Presence represents known clients within a session and their custom states and notifications.\n *\n * @sealed\n * @alpha\n */\nexport interface IPresence {\n\t/**\n\t * Events for Notifications manager.\n\t */\n\treadonly events: ISubscribable<PresenceEvents>;\n\n\t/**\n\t * Get all attendees in the session.\n\t *\n\t * @remarks\n\t * Attendee states are dynamic and will change as clients join and leave\n\t * the session.\n\t */\n\tgetAttendees(): ReadonlySet<ISessionClient>;\n\n\t/**\n\t * Lookup a specific attendee in the session.\n\t *\n\t * @param clientId - Client connection or session ID\n\t */\n\tgetAttendee(clientId: ClientConnectionId | ClientSessionId): ISessionClient;\n\n\t/**\n\t * Get this client's session client.\n\t *\n\t * @returns This client's session client.\n\t */\n\tgetMyself(): ISessionClient;\n\n\t/**\n\t * Acquires a PresenceStates workspace from store or adds new one.\n\t *\n\t * @param workspaceAddress - Address of the requested PresenceStates Workspace\n\t * @param requestedContent - Requested states for the workspace\n\t * @returns A PresenceStates workspace\n\t */\n\tgetStates<StatesSchema extends PresenceStatesSchema>(\n\t\tworkspaceAddress: PresenceWorkspaceAddress,\n\t\trequestedContent: StatesSchema,\n\t): PresenceStates<StatesSchema>;\n\n\t/**\n\t * Acquires a Notifications workspace from store or adds new one.\n\t *\n\t * @param workspaceAddress - Address of the requested Notifications Workspace\n\t * @param requestedContent - Requested notifications for the workspace\n\t * @returns A Notifications workspace\n\t */\n\tgetNotifications<NotificationsSchema extends PresenceNotificationsSchema>(\n\t\tnotificationsId: PresenceWorkspaceAddress,\n\t\trequestedContent: NotificationsSchema,\n\t): PresenceNotifications<NotificationsSchema>;\n}\n"]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import type { IInboundSignalMessage } from "@fluidframework/runtime-definitions/internal";
|
|
6
|
+
import type { ITelemetryLoggerExt } from "@fluidframework/telemetry-utils/internal";
|
|
7
|
+
import type { ClientConnectionId } from "./baseTypes.js";
|
|
8
|
+
import type { IEphemeralRuntime } from "./internalTypes.js";
|
|
9
|
+
import type { ClientSessionId, ISessionClient } from "./presence.js";
|
|
10
|
+
import type { ClientUpdateEntry, PresenceStatesInternal } from "./presenceStates.js";
|
|
11
|
+
import type { SystemWorkspaceDatastore } from "./systemWorkspace.js";
|
|
12
|
+
import type { PresenceStates, PresenceStatesSchema, PresenceWorkspaceAddress } from "./types.js";
|
|
13
|
+
import type { IExtensionMessage } from "@fluidframework/presence/internal/container-definitions/internal";
|
|
14
|
+
interface PresenceStatesEntry<TSchema extends PresenceStatesSchema> {
|
|
15
|
+
public: PresenceStates<TSchema>;
|
|
16
|
+
internal: PresenceStatesInternal;
|
|
17
|
+
}
|
|
18
|
+
interface SystemDatastore {
|
|
19
|
+
"system:presence": SystemWorkspaceDatastore;
|
|
20
|
+
}
|
|
21
|
+
type InternalWorkspaceAddress = `${"s" | "n"}:${PresenceWorkspaceAddress}`;
|
|
22
|
+
interface GeneralDatastoreMessageContent {
|
|
23
|
+
[WorkspaceAddress: string]: {
|
|
24
|
+
[StateValueManagerKey: string]: {
|
|
25
|
+
[ClientSessionId: ClientSessionId]: ClientUpdateEntry;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
type DatastoreMessageContent = SystemDatastore & GeneralDatastoreMessageContent;
|
|
30
|
+
declare const datastoreUpdateMessageType = "Pres:DatastoreUpdate";
|
|
31
|
+
interface DatastoreUpdateMessage extends IInboundSignalMessage {
|
|
32
|
+
type: typeof datastoreUpdateMessageType;
|
|
33
|
+
content: {
|
|
34
|
+
sendTimestamp: number;
|
|
35
|
+
avgLatency: number;
|
|
36
|
+
isComplete?: true;
|
|
37
|
+
data: DatastoreMessageContent;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
declare const joinMessageType = "Pres:ClientJoin";
|
|
41
|
+
interface ClientJoinMessage extends IInboundSignalMessage {
|
|
42
|
+
type: typeof joinMessageType;
|
|
43
|
+
content: {
|
|
44
|
+
updateProviders: ClientConnectionId[];
|
|
45
|
+
sendTimestamp: number;
|
|
46
|
+
avgLatency: number;
|
|
47
|
+
data: DatastoreMessageContent;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
export interface PresenceDatastoreManager {
|
|
54
|
+
joinSession(clientId: ClientConnectionId): void;
|
|
55
|
+
getWorkspace<TSchema extends PresenceStatesSchema>(internalWorkspaceAddress: InternalWorkspaceAddress, requestedContent: TSchema): PresenceStates<TSchema>;
|
|
56
|
+
processSignal(message: IExtensionMessage, local: boolean): void;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Manages singleton datastore for all Presence.
|
|
60
|
+
*/
|
|
61
|
+
export declare class PresenceDatastoreManagerImpl implements PresenceDatastoreManager {
|
|
62
|
+
private readonly clientSessionId;
|
|
63
|
+
private readonly runtime;
|
|
64
|
+
private readonly lookupClient;
|
|
65
|
+
private readonly logger;
|
|
66
|
+
private readonly datastore;
|
|
67
|
+
private averageLatency;
|
|
68
|
+
private returnedMessages;
|
|
69
|
+
private refreshBroadcastRequested;
|
|
70
|
+
private readonly workspaces;
|
|
71
|
+
constructor(clientSessionId: ClientSessionId, runtime: IEphemeralRuntime, lookupClient: (clientId: ClientSessionId) => ISessionClient, logger: ITelemetryLoggerExt | undefined, systemWorkspaceDatastore: SystemWorkspaceDatastore, systemWorkspace: PresenceStatesEntry<PresenceStatesSchema>);
|
|
72
|
+
joinSession(clientId: ClientConnectionId): void;
|
|
73
|
+
getWorkspace<TSchema extends PresenceStatesSchema>(internalWorkspaceAddress: InternalWorkspaceAddress, requestedContent: TSchema): PresenceStates<TSchema>;
|
|
74
|
+
private localUpdate;
|
|
75
|
+
private broadcastAllKnownState;
|
|
76
|
+
processSignal(message: IInboundSignalMessage | DatastoreUpdateMessage | ClientJoinMessage, local: boolean): void;
|
|
77
|
+
/**
|
|
78
|
+
* Handles responding to another client joining the session.
|
|
79
|
+
*
|
|
80
|
+
* @param updateProviders - list of client connection id's that requestor selected
|
|
81
|
+
* to provide response
|
|
82
|
+
* @param requestor - `requestor` is only used in telemetry. While it is the requestor's
|
|
83
|
+
* client connection id, that is not most important. It is important that this is a
|
|
84
|
+
* unique shared id across all clients that might respond as we want to monitor the
|
|
85
|
+
* response patterns. The convenience of being client connection id will allow
|
|
86
|
+
* correlation with other telemetry where it is often called just `clientId`.
|
|
87
|
+
*/
|
|
88
|
+
private prepareJoinResponse;
|
|
89
|
+
}
|
|
90
|
+
export {};
|
|
91
|
+
//# sourceMappingURL=presenceDatastoreManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presenceDatastoreManager.d.ts","sourceRoot":"","sources":["../src/presenceDatastoreManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.PresenceDatastoreManagerImpl = void 0;
|
|
8
|
+
const internal_1 = require("@fluidframework/core-utils/internal");
|
|
9
|
+
const presenceStates_js_1 = require("./presenceStates.js");
|
|
10
|
+
const datastoreUpdateMessageType = "Pres:DatastoreUpdate";
|
|
11
|
+
const joinMessageType = "Pres:ClientJoin";
|
|
12
|
+
function isPresenceMessage(message) {
|
|
13
|
+
return message.type.startsWith("Pres:");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Manages singleton datastore for all Presence.
|
|
17
|
+
*/
|
|
18
|
+
class PresenceDatastoreManagerImpl {
|
|
19
|
+
constructor(clientSessionId, runtime, lookupClient, logger, systemWorkspaceDatastore, systemWorkspace) {
|
|
20
|
+
this.clientSessionId = clientSessionId;
|
|
21
|
+
this.runtime = runtime;
|
|
22
|
+
this.lookupClient = lookupClient;
|
|
23
|
+
this.logger = logger;
|
|
24
|
+
this.averageLatency = 0;
|
|
25
|
+
this.returnedMessages = 0;
|
|
26
|
+
this.refreshBroadcastRequested = false;
|
|
27
|
+
this.workspaces = new Map();
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
29
|
+
this.datastore = { "system:presence": systemWorkspaceDatastore };
|
|
30
|
+
this.workspaces.set("system:presence", systemWorkspace);
|
|
31
|
+
}
|
|
32
|
+
joinSession(clientId) {
|
|
33
|
+
// Broadcast join message to all clients
|
|
34
|
+
const updateProviders = [...this.runtime.getQuorum().getMembers().keys()].filter((quorumClientId) => quorumClientId !== clientId);
|
|
35
|
+
// Limit to three providers to prevent flooding the network.
|
|
36
|
+
// If none respond, others present will (should) after a delay.
|
|
37
|
+
if (updateProviders.length > 3) {
|
|
38
|
+
updateProviders.length = 3;
|
|
39
|
+
}
|
|
40
|
+
this.runtime.submitSignal(joinMessageType, {
|
|
41
|
+
sendTimestamp: Date.now(),
|
|
42
|
+
avgLatency: this.averageLatency,
|
|
43
|
+
data: this.datastore,
|
|
44
|
+
updateProviders,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
getWorkspace(internalWorkspaceAddress, requestedContent) {
|
|
48
|
+
const existing = this.workspaces.get(internalWorkspaceAddress);
|
|
49
|
+
if (existing) {
|
|
50
|
+
return existing.internal.ensureContent(requestedContent);
|
|
51
|
+
}
|
|
52
|
+
let workspaceDatastore = this.datastore[internalWorkspaceAddress];
|
|
53
|
+
if (workspaceDatastore === undefined) {
|
|
54
|
+
workspaceDatastore = this.datastore[internalWorkspaceAddress] = {};
|
|
55
|
+
}
|
|
56
|
+
const localUpdate = (states, forceBroadcast) => {
|
|
57
|
+
// Check for connectivity before sending updates.
|
|
58
|
+
if (!this.runtime.connected) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const clientConnectionId = this.runtime.clientId;
|
|
62
|
+
(0, internal_1.assert)(clientConnectionId !== undefined, 0xa59 /* Client connected without clientId */);
|
|
63
|
+
const currentClientToSessionValueState = this.datastore["system:presence"].clientToSessionId[clientConnectionId];
|
|
64
|
+
const updates = {};
|
|
65
|
+
for (const [key, value] of Object.entries(states)) {
|
|
66
|
+
updates[key] = { [this.clientSessionId]: value };
|
|
67
|
+
}
|
|
68
|
+
this.localUpdate({
|
|
69
|
+
// Always send current connection mapping for some resiliency against
|
|
70
|
+
// lost signals. This ensures that client session id found in `updates`
|
|
71
|
+
// (which is this client's client session id) is always represented in
|
|
72
|
+
// system workspace of recipient clients.
|
|
73
|
+
"system:presence": {
|
|
74
|
+
clientToSessionId: {
|
|
75
|
+
[clientConnectionId]: { ...currentClientToSessionValueState },
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
[internalWorkspaceAddress]: updates,
|
|
79
|
+
}, forceBroadcast);
|
|
80
|
+
};
|
|
81
|
+
const entry = (0, presenceStates_js_1.createPresenceStates)({
|
|
82
|
+
clientSessionId: this.clientSessionId,
|
|
83
|
+
lookupClient: this.lookupClient,
|
|
84
|
+
localUpdate,
|
|
85
|
+
}, workspaceDatastore, requestedContent);
|
|
86
|
+
this.workspaces.set(internalWorkspaceAddress, entry);
|
|
87
|
+
return entry.public;
|
|
88
|
+
}
|
|
89
|
+
localUpdate(data, _forceBroadcast) {
|
|
90
|
+
const content = {
|
|
91
|
+
sendTimestamp: Date.now(),
|
|
92
|
+
avgLatency: this.averageLatency,
|
|
93
|
+
// isComplete: false,
|
|
94
|
+
data,
|
|
95
|
+
};
|
|
96
|
+
this.runtime.submitSignal(datastoreUpdateMessageType, content);
|
|
97
|
+
}
|
|
98
|
+
broadcastAllKnownState() {
|
|
99
|
+
this.runtime.submitSignal(datastoreUpdateMessageType, {
|
|
100
|
+
sendTimestamp: Date.now(),
|
|
101
|
+
avgLatency: this.averageLatency,
|
|
102
|
+
isComplete: true,
|
|
103
|
+
data: this.datastore,
|
|
104
|
+
});
|
|
105
|
+
this.refreshBroadcastRequested = false;
|
|
106
|
+
}
|
|
107
|
+
processSignal(
|
|
108
|
+
// Note: IInboundSignalMessage is used here in place of IExtensionMessage
|
|
109
|
+
// as IExtensionMessage's strictly JSON `content` creates type compatibility
|
|
110
|
+
// issues with `ClientSessionId` keys and really unknown value content.
|
|
111
|
+
// IExtensionMessage is a subset of IInboundSignalMessage so this is safe.
|
|
112
|
+
// Change types of DatastoreUpdateMessage | ClientJoinMessage to
|
|
113
|
+
// IExtensionMessage<> derivatives to see the issues.
|
|
114
|
+
message, local) {
|
|
115
|
+
const received = Date.now();
|
|
116
|
+
(0, internal_1.assert)(message.clientId !== null, 0xa3a /* Map received signal without clientId */);
|
|
117
|
+
if (!isPresenceMessage(message)) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (local) {
|
|
121
|
+
const deliveryDelta = received - message.content.sendTimestamp;
|
|
122
|
+
// Limit returnedMessages count to 256 such that newest message
|
|
123
|
+
// always contributes at least 1/256th to the average. Older
|
|
124
|
+
// messages have more weight, but that diminishes as new messages
|
|
125
|
+
// contribute.
|
|
126
|
+
this.returnedMessages = Math.min(this.returnedMessages + 1, 256);
|
|
127
|
+
this.averageLatency =
|
|
128
|
+
(this.averageLatency * (this.returnedMessages - 1) + deliveryDelta) /
|
|
129
|
+
this.returnedMessages;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const timeModifier = received -
|
|
133
|
+
(this.averageLatency + message.content.avgLatency + message.content.sendTimestamp);
|
|
134
|
+
if (message.type === joinMessageType) {
|
|
135
|
+
// It is possible for some signals to come in while client is not connected due
|
|
136
|
+
// to how work is scheduled. If we are not connected, we can't respond to the
|
|
137
|
+
// join request. We will make our own Join request once we are connected.
|
|
138
|
+
if (this.runtime.connected) {
|
|
139
|
+
this.prepareJoinResponse(message.content.updateProviders, message.clientId);
|
|
140
|
+
}
|
|
141
|
+
// It is okay to continue processing the contained updates even if we are not
|
|
142
|
+
// connected.
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
(0, internal_1.assert)(message.type === datastoreUpdateMessageType, 0xa3b /* Unexpected message type */);
|
|
146
|
+
if (message.content.isComplete) {
|
|
147
|
+
this.refreshBroadcastRequested = false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const [workspaceAddress, remoteDatastore] of Object.entries(message.content.data)) {
|
|
151
|
+
// Direct to the appropriate Presence Workspace, if present.
|
|
152
|
+
const workspace = this.workspaces.get(workspaceAddress);
|
|
153
|
+
if (workspace) {
|
|
154
|
+
workspace.internal.processUpdate(received, timeModifier, remoteDatastore, message.clientId);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// All broadcast state is kept even if not currently registered, unless a value
|
|
158
|
+
// notes itself to be ignored.
|
|
159
|
+
let workspaceDatastore = this.datastore[workspaceAddress];
|
|
160
|
+
if (workspaceDatastore === undefined) {
|
|
161
|
+
workspaceDatastore = this.datastore[workspaceAddress] = {};
|
|
162
|
+
if (!workspaceAddress.startsWith("system:")) {
|
|
163
|
+
// TODO: Emit workspaceActivated event for PresenceEvents
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const [key, remoteAllKnownState] of Object.entries(remoteDatastore)) {
|
|
167
|
+
(0, presenceStates_js_1.mergeUntrackedDatastore)(key, remoteAllKnownState, workspaceDatastore, timeModifier);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Handles responding to another client joining the session.
|
|
174
|
+
*
|
|
175
|
+
* @param updateProviders - list of client connection id's that requestor selected
|
|
176
|
+
* to provide response
|
|
177
|
+
* @param requestor - `requestor` is only used in telemetry. While it is the requestor's
|
|
178
|
+
* client connection id, that is not most important. It is important that this is a
|
|
179
|
+
* unique shared id across all clients that might respond as we want to monitor the
|
|
180
|
+
* response patterns. The convenience of being client connection id will allow
|
|
181
|
+
* correlation with other telemetry where it is often called just `clientId`.
|
|
182
|
+
*/
|
|
183
|
+
prepareJoinResponse(updateProviders, requestor) {
|
|
184
|
+
this.refreshBroadcastRequested = true;
|
|
185
|
+
// We must be connected to receive this message, so clientId should be defined.
|
|
186
|
+
// If it isn't then, not really a problem; just won't be in provider or quorum list.
|
|
187
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
188
|
+
const clientId = this.runtime.clientId;
|
|
189
|
+
// const requestor = message.clientId;
|
|
190
|
+
if (updateProviders.includes(clientId)) {
|
|
191
|
+
// Send all current state to the new client
|
|
192
|
+
this.broadcastAllKnownState();
|
|
193
|
+
this.logger?.sendTelemetryEvent({
|
|
194
|
+
eventName: "JoinResponse",
|
|
195
|
+
details: {
|
|
196
|
+
type: "broadcastAll",
|
|
197
|
+
requestor,
|
|
198
|
+
role: "primary",
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// Schedule a broadcast to the new client after a delay only to send if
|
|
204
|
+
// another broadcast hasn't been seen in the meantime. The delay is based
|
|
205
|
+
// on the position in the quorum list. It doesn't have to be a stable
|
|
206
|
+
// list across all clients. We need something to provide suggested order
|
|
207
|
+
// to prevent a flood of broadcasts.
|
|
208
|
+
let relativeResponseOrder;
|
|
209
|
+
const quorumMembers = this.runtime.getQuorum().getMembers();
|
|
210
|
+
const self = quorumMembers.get(clientId);
|
|
211
|
+
if (self) {
|
|
212
|
+
// Compute order quorum join order (indicated by sequenceNumber)
|
|
213
|
+
relativeResponseOrder = 0;
|
|
214
|
+
for (const { sequenceNumber } of quorumMembers.values()) {
|
|
215
|
+
if (sequenceNumber < self.sequenceNumber) {
|
|
216
|
+
relativeResponseOrder++;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
// Order past quorum members + arbitrary additional offset up to 10
|
|
222
|
+
relativeResponseOrder = quorumMembers.size + Math.random() * 10;
|
|
223
|
+
}
|
|
224
|
+
// These numbers have been chosen arbitrarily to start with.
|
|
225
|
+
// 20 is minimum wait time, 20 is the additional wait time per provider
|
|
226
|
+
// given an chance before us with named providers given more time.
|
|
227
|
+
const waitTime = 20 + 20 * (3 * updateProviders.length + relativeResponseOrder);
|
|
228
|
+
setTimeout(() => {
|
|
229
|
+
// Make sure a broadcast is still needed and we are currently connected.
|
|
230
|
+
// If not connected, nothing we can do.
|
|
231
|
+
if (this.refreshBroadcastRequested && this.runtime.connected) {
|
|
232
|
+
this.broadcastAllKnownState();
|
|
233
|
+
this.logger?.sendTelemetryEvent({
|
|
234
|
+
eventName: "JoinResponse",
|
|
235
|
+
details: {
|
|
236
|
+
type: "broadcastAll",
|
|
237
|
+
requestor,
|
|
238
|
+
role: "secondary",
|
|
239
|
+
order: relativeResponseOrder,
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}, waitTime);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
exports.PresenceDatastoreManagerImpl = PresenceDatastoreManagerImpl;
|
|
248
|
+
//# sourceMappingURL=presenceDatastoreManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presenceDatastoreManager.js","sourceRoot":"","sources":["../src/presenceDatastoreManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert } from \"@fluidframework/core-utils/internal\";\nimport type { IInboundSignalMessage } from \"@fluidframework/runtime-definitions/internal\";\nimport type { ITelemetryLoggerExt } from \"@fluidframework/telemetry-utils/internal\";\n\nimport type { ClientConnectionId } from \"./baseTypes.js\";\nimport type { IEphemeralRuntime } from \"./internalTypes.js\";\nimport type { ClientSessionId, ISessionClient } from \"./presence.js\";\nimport type {\n\tClientUpdateEntry,\n\tPresenceStatesInternal,\n\tValueElementMap,\n} from \"./presenceStates.js\";\nimport { createPresenceStates, mergeUntrackedDatastore } from \"./presenceStates.js\";\nimport type { SystemWorkspaceDatastore } from \"./systemWorkspace.js\";\nimport type {\n\tPresenceStates,\n\tPresenceStatesSchema,\n\tPresenceWorkspaceAddress,\n} from \"./types.js\";\n\nimport type { IExtensionMessage } from \"@fluidframework/presence/internal/container-definitions/internal\";\n\ninterface PresenceStatesEntry<TSchema extends PresenceStatesSchema> {\n\tpublic: PresenceStates<TSchema>;\n\tinternal: PresenceStatesInternal;\n}\n\ninterface SystemDatastore {\n\t\"system:presence\": SystemWorkspaceDatastore;\n}\n\ntype InternalWorkspaceAddress = `${\"s\" | \"n\"}:${PresenceWorkspaceAddress}`;\n\ntype PresenceDatastore = SystemDatastore & {\n\t[WorkspaceAddress: string]: ValueElementMap<PresenceStatesSchema>;\n};\n\ninterface GeneralDatastoreMessageContent {\n\t[WorkspaceAddress: string]: {\n\t\t[StateValueManagerKey: string]: {\n\t\t\t[ClientSessionId: ClientSessionId]: ClientUpdateEntry;\n\t\t};\n\t};\n}\n\ntype DatastoreMessageContent = SystemDatastore & GeneralDatastoreMessageContent;\n\nconst datastoreUpdateMessageType = \"Pres:DatastoreUpdate\";\ninterface DatastoreUpdateMessage extends IInboundSignalMessage {\n\ttype: typeof datastoreUpdateMessageType;\n\tcontent: {\n\t\tsendTimestamp: number;\n\t\tavgLatency: number;\n\t\tisComplete?: true;\n\t\tdata: DatastoreMessageContent;\n\t};\n}\n\nconst joinMessageType = \"Pres:ClientJoin\";\ninterface ClientJoinMessage extends IInboundSignalMessage {\n\ttype: typeof joinMessageType;\n\tcontent: {\n\t\tupdateProviders: ClientConnectionId[];\n\t\tsendTimestamp: number;\n\t\tavgLatency: number;\n\t\tdata: DatastoreMessageContent;\n\t};\n}\n\nfunction isPresenceMessage(\n\tmessage: IInboundSignalMessage,\n): message is DatastoreUpdateMessage | ClientJoinMessage {\n\treturn message.type.startsWith(\"Pres:\");\n}\n\n/**\n * @internal\n */\nexport interface PresenceDatastoreManager {\n\tjoinSession(clientId: ClientConnectionId): void;\n\tgetWorkspace<TSchema extends PresenceStatesSchema>(\n\t\tinternalWorkspaceAddress: InternalWorkspaceAddress,\n\t\trequestedContent: TSchema,\n\t): PresenceStates<TSchema>;\n\tprocessSignal(message: IExtensionMessage, local: boolean): void;\n}\n\n/**\n * Manages singleton datastore for all Presence.\n */\nexport class PresenceDatastoreManagerImpl implements PresenceDatastoreManager {\n\tprivate readonly datastore: PresenceDatastore;\n\tprivate averageLatency = 0;\n\tprivate returnedMessages = 0;\n\tprivate refreshBroadcastRequested = false;\n\n\tprivate readonly workspaces = new Map<string, PresenceStatesEntry<PresenceStatesSchema>>();\n\n\tpublic constructor(\n\t\tprivate readonly clientSessionId: ClientSessionId,\n\t\tprivate readonly runtime: IEphemeralRuntime,\n\t\tprivate readonly lookupClient: (clientId: ClientSessionId) => ISessionClient,\n\t\tprivate readonly logger: ITelemetryLoggerExt | undefined,\n\t\tsystemWorkspaceDatastore: SystemWorkspaceDatastore,\n\t\tsystemWorkspace: PresenceStatesEntry<PresenceStatesSchema>,\n\t) {\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\tthis.datastore = { \"system:presence\": systemWorkspaceDatastore } as PresenceDatastore;\n\t\tthis.workspaces.set(\"system:presence\", systemWorkspace);\n\t}\n\n\tpublic joinSession(clientId: ClientConnectionId): void {\n\t\t// Broadcast join message to all clients\n\t\tconst updateProviders = [...this.runtime.getQuorum().getMembers().keys()].filter(\n\t\t\t(quorumClientId) => quorumClientId !== clientId,\n\t\t);\n\t\t// Limit to three providers to prevent flooding the network.\n\t\t// If none respond, others present will (should) after a delay.\n\t\tif (updateProviders.length > 3) {\n\t\t\tupdateProviders.length = 3;\n\t\t}\n\t\tthis.runtime.submitSignal(joinMessageType, {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\tdata: this.datastore,\n\t\t\tupdateProviders,\n\t\t} satisfies ClientJoinMessage[\"content\"]);\n\t}\n\n\tpublic getWorkspace<TSchema extends PresenceStatesSchema>(\n\t\tinternalWorkspaceAddress: InternalWorkspaceAddress,\n\t\trequestedContent: TSchema,\n\t): PresenceStates<TSchema> {\n\t\tconst existing = this.workspaces.get(internalWorkspaceAddress);\n\t\tif (existing) {\n\t\t\treturn existing.internal.ensureContent(requestedContent);\n\t\t}\n\n\t\tlet workspaceDatastore = this.datastore[internalWorkspaceAddress];\n\t\tif (workspaceDatastore === undefined) {\n\t\t\tworkspaceDatastore = this.datastore[internalWorkspaceAddress] = {};\n\t\t}\n\n\t\tconst localUpdate = (\n\t\t\tstates: { [key: string]: ClientUpdateEntry },\n\t\t\tforceBroadcast: boolean,\n\t\t): void => {\n\t\t\t// Check for connectivity before sending updates.\n\t\t\tif (!this.runtime.connected) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst clientConnectionId = this.runtime.clientId;\n\t\t\tassert(clientConnectionId !== undefined, 0xa59 /* Client connected without clientId */);\n\t\t\tconst currentClientToSessionValueState =\n\t\t\t\tthis.datastore[\"system:presence\"].clientToSessionId[clientConnectionId];\n\n\t\t\tconst updates: GeneralDatastoreMessageContent[InternalWorkspaceAddress] = {};\n\t\t\tfor (const [key, value] of Object.entries(states)) {\n\t\t\t\tupdates[key] = { [this.clientSessionId]: value };\n\t\t\t}\n\t\t\tthis.localUpdate(\n\t\t\t\t{\n\t\t\t\t\t// Always send current connection mapping for some resiliency against\n\t\t\t\t\t// lost signals. This ensures that client session id found in `updates`\n\t\t\t\t\t// (which is this client's client session id) is always represented in\n\t\t\t\t\t// system workspace of recipient clients.\n\t\t\t\t\t\"system:presence\": {\n\t\t\t\t\t\tclientToSessionId: {\n\t\t\t\t\t\t\t[clientConnectionId]: { ...currentClientToSessionValueState },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t[internalWorkspaceAddress]: updates,\n\t\t\t\t},\n\t\t\t\tforceBroadcast,\n\t\t\t);\n\t\t};\n\n\t\tconst entry = createPresenceStates(\n\t\t\t{\n\t\t\t\tclientSessionId: this.clientSessionId,\n\t\t\t\tlookupClient: this.lookupClient,\n\t\t\t\tlocalUpdate,\n\t\t\t},\n\t\t\tworkspaceDatastore,\n\t\t\trequestedContent,\n\t\t);\n\n\t\tthis.workspaces.set(internalWorkspaceAddress, entry);\n\t\treturn entry.public;\n\t}\n\n\tprivate localUpdate(data: DatastoreMessageContent, _forceBroadcast: boolean): void {\n\t\tconst content = {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\t// isComplete: false,\n\t\t\tdata,\n\t\t} satisfies DatastoreUpdateMessage[\"content\"];\n\t\tthis.runtime.submitSignal(datastoreUpdateMessageType, content);\n\t}\n\n\tprivate broadcastAllKnownState(): void {\n\t\tthis.runtime.submitSignal(datastoreUpdateMessageType, {\n\t\t\tsendTimestamp: Date.now(),\n\t\t\tavgLatency: this.averageLatency,\n\t\t\tisComplete: true,\n\t\t\tdata: this.datastore,\n\t\t} satisfies DatastoreUpdateMessage[\"content\"]);\n\t\tthis.refreshBroadcastRequested = false;\n\t}\n\n\tpublic processSignal(\n\t\t// Note: IInboundSignalMessage is used here in place of IExtensionMessage\n\t\t// as IExtensionMessage's strictly JSON `content` creates type compatibility\n\t\t// issues with `ClientSessionId` keys and really unknown value content.\n\t\t// IExtensionMessage is a subset of IInboundSignalMessage so this is safe.\n\t\t// Change types of DatastoreUpdateMessage | ClientJoinMessage to\n\t\t// IExtensionMessage<> derivatives to see the issues.\n\t\tmessage: IInboundSignalMessage | DatastoreUpdateMessage | ClientJoinMessage,\n\t\tlocal: boolean,\n\t): void {\n\t\tconst received = Date.now();\n\t\tassert(message.clientId !== null, 0xa3a /* Map received signal without clientId */);\n\t\tif (!isPresenceMessage(message)) {\n\t\t\treturn;\n\t\t}\n\t\tif (local) {\n\t\t\tconst deliveryDelta = received - message.content.sendTimestamp;\n\t\t\t// Limit returnedMessages count to 256 such that newest message\n\t\t\t// always contributes at least 1/256th to the average. Older\n\t\t\t// messages have more weight, but that diminishes as new messages\n\t\t\t// contribute.\n\t\t\tthis.returnedMessages = Math.min(this.returnedMessages + 1, 256);\n\t\t\tthis.averageLatency =\n\t\t\t\t(this.averageLatency * (this.returnedMessages - 1) + deliveryDelta) /\n\t\t\t\tthis.returnedMessages;\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeModifier =\n\t\t\treceived -\n\t\t\t(this.averageLatency + message.content.avgLatency + message.content.sendTimestamp);\n\n\t\tif (message.type === joinMessageType) {\n\t\t\t// It is possible for some signals to come in while client is not connected due\n\t\t\t// to how work is scheduled. If we are not connected, we can't respond to the\n\t\t\t// join request. We will make our own Join request once we are connected.\n\t\t\tif (this.runtime.connected) {\n\t\t\t\tthis.prepareJoinResponse(message.content.updateProviders, message.clientId);\n\t\t\t}\n\t\t\t// It is okay to continue processing the contained updates even if we are not\n\t\t\t// connected.\n\t\t} else {\n\t\t\tassert(message.type === datastoreUpdateMessageType, 0xa3b /* Unexpected message type */);\n\t\t\tif (message.content.isComplete) {\n\t\t\t\tthis.refreshBroadcastRequested = false;\n\t\t\t}\n\t\t}\n\n\t\tfor (const [workspaceAddress, remoteDatastore] of Object.entries(message.content.data)) {\n\t\t\t// Direct to the appropriate Presence Workspace, if present.\n\t\t\tconst workspace = this.workspaces.get(workspaceAddress);\n\t\t\tif (workspace) {\n\t\t\t\tworkspace.internal.processUpdate(\n\t\t\t\t\treceived,\n\t\t\t\t\ttimeModifier,\n\t\t\t\t\tremoteDatastore,\n\t\t\t\t\tmessage.clientId,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// All broadcast state is kept even if not currently registered, unless a value\n\t\t\t\t// notes itself to be ignored.\n\t\t\t\tlet workspaceDatastore = this.datastore[workspaceAddress];\n\t\t\t\tif (workspaceDatastore === undefined) {\n\t\t\t\t\tworkspaceDatastore = this.datastore[workspaceAddress] = {};\n\t\t\t\t\tif (!workspaceAddress.startsWith(\"system:\")) {\n\t\t\t\t\t\t// TODO: Emit workspaceActivated event for PresenceEvents\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (const [key, remoteAllKnownState] of Object.entries(remoteDatastore)) {\n\t\t\t\t\tmergeUntrackedDatastore(key, remoteAllKnownState, workspaceDatastore, timeModifier);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handles responding to another client joining the session.\n\t *\n\t * @param updateProviders - list of client connection id's that requestor selected\n\t * to provide response\n\t * @param requestor - `requestor` is only used in telemetry. While it is the requestor's\n\t * client connection id, that is not most important. It is important that this is a\n\t * unique shared id across all clients that might respond as we want to monitor the\n\t * response patterns. The convenience of being client connection id will allow\n\t * correlation with other telemetry where it is often called just `clientId`.\n\t */\n\tprivate prepareJoinResponse(\n\t\tupdateProviders: ClientConnectionId[],\n\t\trequestor: ClientConnectionId,\n\t): void {\n\t\tthis.refreshBroadcastRequested = true;\n\t\t// We must be connected to receive this message, so clientId should be defined.\n\t\t// If it isn't then, not really a problem; just won't be in provider or quorum list.\n\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\tconst clientId = this.runtime.clientId!;\n\t\t// const requestor = message.clientId;\n\t\tif (updateProviders.includes(clientId)) {\n\t\t\t// Send all current state to the new client\n\t\t\tthis.broadcastAllKnownState();\n\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\teventName: \"JoinResponse\",\n\t\t\t\tdetails: {\n\t\t\t\t\ttype: \"broadcastAll\",\n\t\t\t\t\trequestor,\n\t\t\t\t\trole: \"primary\",\n\t\t\t\t},\n\t\t\t});\n\t\t} else {\n\t\t\t// Schedule a broadcast to the new client after a delay only to send if\n\t\t\t// another broadcast hasn't been seen in the meantime. The delay is based\n\t\t\t// on the position in the quorum list. It doesn't have to be a stable\n\t\t\t// list across all clients. We need something to provide suggested order\n\t\t\t// to prevent a flood of broadcasts.\n\t\t\tlet relativeResponseOrder;\n\t\t\tconst quorumMembers = this.runtime.getQuorum().getMembers();\n\t\t\tconst self = quorumMembers.get(clientId);\n\t\t\tif (self) {\n\t\t\t\t// Compute order quorum join order (indicated by sequenceNumber)\n\t\t\t\trelativeResponseOrder = 0;\n\t\t\t\tfor (const { sequenceNumber } of quorumMembers.values()) {\n\t\t\t\t\tif (sequenceNumber < self.sequenceNumber) {\n\t\t\t\t\t\trelativeResponseOrder++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Order past quorum members + arbitrary additional offset up to 10\n\t\t\t\trelativeResponseOrder = quorumMembers.size + Math.random() * 10;\n\t\t\t}\n\t\t\t// These numbers have been chosen arbitrarily to start with.\n\t\t\t// 20 is minimum wait time, 20 is the additional wait time per provider\n\t\t\t// given an chance before us with named providers given more time.\n\t\t\tconst waitTime = 20 + 20 * (3 * updateProviders.length + relativeResponseOrder);\n\t\t\tsetTimeout(() => {\n\t\t\t\t// Make sure a broadcast is still needed and we are currently connected.\n\t\t\t\t// If not connected, nothing we can do.\n\t\t\t\tif (this.refreshBroadcastRequested && this.runtime.connected) {\n\t\t\t\t\tthis.broadcastAllKnownState();\n\t\t\t\t\tthis.logger?.sendTelemetryEvent({\n\t\t\t\t\t\teventName: \"JoinResponse\",\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\ttype: \"broadcastAll\",\n\t\t\t\t\t\t\trequestor,\n\t\t\t\t\t\t\trole: \"secondary\",\n\t\t\t\t\t\t\torder: relativeResponseOrder,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}, waitTime);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import type { IEphemeralRuntime } from "./internalTypes.js";
|
|
6
|
+
import type { ClientSessionId, IPresence } from "./presence.js";
|
|
7
|
+
import type { IContainerExtension } from "@fluidframework/presence/internal/container-definitions/internal";
|
|
8
|
+
/**
|
|
9
|
+
* Portion of the container extension requirements ({@link IContainerExtension}) that are delegated to presence manager.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export type PresenceExtensionInterface = Required<Pick<IContainerExtension<never>, "processSignal">>;
|
|
14
|
+
/**
|
|
15
|
+
* Instantiates Presence Manager
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export declare function createPresenceManager(runtime: IEphemeralRuntime, clientSessionId?: ClientSessionId): IPresence & PresenceExtensionInterface;
|
|
20
|
+
//# sourceMappingURL=presenceManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presenceManager.d.ts","sourceRoot":"","sources":["../src/presenceManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EACX,eAAe,EACf,SAAS,EAGT,MAAM,eAAe,CAAC;AAWvB,OAAO,KAAK,EACX,mBAAmB,EAEnB,MAAM,kEAAkE,CAAC;AAI1E;;;;GAIG;AACH,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAChD,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC,CACjD,CAAC;AAoIF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,iBAAiB,EAC1B,eAAe,GAAE,eAAsD,GACrE,SAAS,GAAG,0BAA0B,CAExC"}
|