Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for passing client display name used when attributing changes to the current client in the collab session #23422

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface ICacheEntry extends IEntry {

// @alpha (undocumented)
export interface ICollabSessionOptions {
displayName?: string;
// @deprecated
forceAccessTokenViaAuthorizationHeader?: boolean;
// @deprecated
Expand Down
5 changes: 5 additions & 0 deletions packages/drivers/odsp-driver-definitions/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ export interface ICollabSessionOptions {
* @deprecated Due to security reasons we will be passing the token via Authorization header only.
*/
forceAccessTokenViaAuthorizationHeader?: boolean;
/**
* Value indicating the client display name for current session.
* This name will be used in attribution associated with edits made during session.
*/
displayName?: string;
AndreiZe marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
13 changes: 11 additions & 2 deletions packages/drivers/odsp-driver/src/odspDelayLoadedDeltaStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export class OdspDelayLoadedDeltaStream {
| undefined,
private readonly mc: MonitoringContext,
private readonly cache: IOdspCache,
_hostPolicy: HostStoragePolicy,
private readonly hostPolicy: HostStoragePolicy,
private readonly epochTracker: EpochTracker,
private readonly opsReceived: (ops: ISequencedDocumentMessage[]) => void,
private readonly metadataUpdateHandler: (metadata: Record<string, string>) => void,
Expand Down Expand Up @@ -156,6 +156,8 @@ export class OdspDelayLoadedDeltaStream {
requestWebsocketTokenFromJoinSession,
options,
false /* isRefreshingJoinSession */,
undefined /* clientId */,
this.hostPolicy.sessionOptions?.displayName,
);
const [websocketEndpoint, websocketToken] = await Promise.all([
joinSessionPromise.catch(annotateAndRethrowConnectionError("joinSession")),
Expand Down Expand Up @@ -273,6 +275,7 @@ export class OdspDelayLoadedDeltaStream {
delta: number,
requestSocketToken: boolean,
clientId: string | undefined,
displayName: string | undefined,
): Promise<void> {
if (this.joinSessionRefreshTimer !== undefined) {
this.clearJoinSessionTimer();
Expand Down Expand Up @@ -301,6 +304,7 @@ export class OdspDelayLoadedDeltaStream {
options,
true /* isRefreshingJoinSession */,
clientId,
displayName,
);
resolve();
}).catch((error) => {
Expand All @@ -314,7 +318,8 @@ export class OdspDelayLoadedDeltaStream {
requestSocketToken: boolean,
options: TokenFetchOptionsEx,
isRefreshingJoinSession: boolean,
clientId?: string,
clientId: string | undefined,
displayName: string | undefined
): Promise<ISocketStorageDiscovery> {
// If this call is to refresh the join session for the current connection but we are already disconnected in
// the meantime or disconnected and then reconnected then do not make the call. However, we should not have
Expand Down Expand Up @@ -342,6 +347,7 @@ export class OdspDelayLoadedDeltaStream {
requestSocketToken,
options,
isRefreshingJoinSession,
displayName,
).catch((error) => {
if (hasFacetCodes(error) && error.facetCodes !== undefined) {
for (const code of error.facetCodes) {
Expand Down Expand Up @@ -378,6 +384,7 @@ export class OdspDelayLoadedDeltaStream {
requestSocketToken: boolean,
options: TokenFetchOptionsEx,
isRefreshingJoinSession: boolean,
displayName: string | undefined,
): Promise<ISocketStorageDiscovery> {
const disableJoinSessionRefresh = this.mc.config.getBoolean(
"Fluid.Driver.Odsp.disableJoinSessionRefresh",
Expand All @@ -397,6 +404,7 @@ export class OdspDelayLoadedDeltaStream {
options,
disableJoinSessionRefresh,
isRefreshingJoinSession,
displayName,
);
// Emit event only in case it is fetched from the network.
if (joinSessionResponse.sensitivityLabelsInfo !== undefined) {
Expand Down Expand Up @@ -450,6 +458,7 @@ export class OdspDelayLoadedDeltaStream {
response.refreshAfterDeltaMs,
requestSocketToken,
this.currentConnection?.clientId,
displayName,
).catch((error) => {
// Log the error and do nothing as the reconnection would fetch the join session.
this.mc.logger.sendTelemetryEvent(
Expand Down
22 changes: 14 additions & 8 deletions packages/drivers/odsp-driver/src/vroom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import { TokenFetchOptionsEx } from "./odspUtils.js";
import { runWithRetry } from "./retryUtils.js";

interface IJoinSessionBody {
requestSocketToken: boolean;
guestDisplayName?: string;
requestSocketToken?: boolean;
displayName?: string;
}

/**
Expand All @@ -38,8 +38,9 @@ interface IJoinSessionBody {
* @param options - Options to fetch the token.
* @param disableJoinSessionRefresh - Whether the caller wants to disable refreshing join session periodically.
* @param isRefreshingJoinSession - whether call is to refresh the session before expiry.
* @param guestDisplayName - display name used to identify guest user joining a session.
* This is optional and used only when collab session is being joined via invite.
* @param displayName - display name used to identify client joining a session.
* This is optional and used only when collab session is being joined in app-only mode.
AndreiZe marked this conversation as resolved.
Show resolved Hide resolved
* If not specified app display name is extracted from the access token that is used to join session.
*/
export async function fetchJoinSession(
urlParts: IOdspUrlParts,
Expand All @@ -52,6 +53,7 @@ export async function fetchJoinSession(
options: TokenFetchOptionsEx,
disableJoinSessionRefresh: boolean | undefined,
isRefreshingJoinSession: boolean,
displayName: string | undefined
): Promise<ISocketStorageDiscovery> {
const apiRoot = getApiRoot(new URL(urlParts.siteUrl));
const url = `${apiRoot}/drives/${urlParts.driveId}/items/${urlParts.itemId}/${path}?ump=1`;
Expand Down Expand Up @@ -89,11 +91,15 @@ export async function fetchJoinSession(
}
postBody += `_post: 1\r\n`;

let requestBody: IJoinSessionBody | undefined;
if (requestSocketToken) {
const body: IJoinSessionBody = {
requestSocketToken: true,
};
postBody += `\r\n${JSON.stringify(body)}\r\n`;
requestBody = { ...requestBody, requestSocketToken: true };
}
if (displayName) {
requestBody = { ...requestBody, displayName };
}
if (requestBody) {
postBody += `\r\n${JSON.stringify(requestBody)}\r\n`;
}
postBody += `\r\n--${formBoundary}--`;
const headers: { [index: string]: string } = {
Expand Down
1 change: 1 addition & 0 deletions packages/test/test-drivers/src/odspDriverApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const odspOpsCaching: OptionsMatrix<IOpsCachingPolicy> = {
const odspSessionOptions: OptionsMatrix<ICollabSessionOptions> = {
unauthenticatedUserDisplayName: [undefined],
forceAccessTokenViaAuthorizationHeader: [undefined],
displayName: [undefined],
};

/**
Expand Down
Loading