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

Added co-presence worker script #703

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
162 changes: 162 additions & 0 deletions src/web/client/services/copresenceWorker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

import WebExtensionContext from "../WebExtensionContext";
import { telemetryEventNames } from "../telemetry/constants";

// eslint-disable-next-line no-undef
self.window = self;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fluid = require("fluid-framework");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { AzureClient } = require("@fluidframework/azure-client");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const DataverseTokenProvider = require("../common/DataverseTokenProvider");

const { SharedMap, ConnectionState } = fluid;

const objectTypes = [SharedMap];

const containerSchema = {
dynamicObjectTypes: objectTypes,
initialObjects: {
sharedState: SharedMap,
},
};

let initial = false;

class AzureFluidClient {
static _clientInstance;
static _container;
static _audience;
static _userSharedMap;

static getInstance(config) {
if (!this._clientInstance) {
const afrClientProps = {
connection: {
type: "remote",
tenantId: config.swptenantId,
tokenProvider: new DataverseTokenProvider(
config.swpAccessToken,
() => this.fetchAccessToken()
),
endpoint: config.discoveryendpoint,
},
};

AzureFluidClient._clientInstance = new AzureClient(afrClientProps);
}
return this._clientInstance;
}

static async fetchContainerAndService(config, id) {
if (this._container?.connectionState !== ConnectionState.Connected) {
const azureClient = this.getInstance(config);
const { container, services } = await azureClient.getContainer(
id,
containerSchema
);
if (container.connectionState !== ConnectionState.Connected) {
await new Promise((resolve) => {
container.once("connected", () => {
resolve();
});
});
}
this._container = container;
this._audience = services.audience;
this._userSharedMap = container.initialObjects.sharedState;
}
return {
container: this._container,
audience: this._audience,
map: this._userSharedMap,
};
}
}

async function loadContainer(config, id, swpId, file) {
try {
const { container, audience, map } =
await AzureFluidClient.fetchContainerAndService(config, swpId);

const existingMembers = audience.getMembers();

const myself = audience.getMyself();

const currentUser = {
containerId: id,
fileName: file.fileName,
filePath: file.filePath,
userName: myself.userName,
};

map.set(myself.userId, currentUser);

audience.on("memberRemoved", (clientId, member) => {
if (!existingMembers.get(member.userId)) {
self.postMessage({
type: "member-removed",
userId: member.userId,
});
}
});

if (!initial) {
existingMembers.forEach(async (value, key) => {
const otherUser = value;

self.postMessage({
type: "client-data",
userName: otherUser.userName,
userId: key,
containerId: swpId,
fileName:
otherUser.fileName === undefined
? "On Studio"
: otherUser.fileName,
filePath: otherUser.filePath,
});
});
initial = true;
}

map.on("valueChanged", async (changed, local) => {
if (!local) {
const otherUser = map.get(changed.key);
// eslint-disable-next-line no-undef
await self.postMessage({
type: "client-data",
userId: changed.key,
userName: otherUser.userName,
containerId: swpId,
fileName: otherUser.fileName,
filePath: otherUser.filePath,
});
}
});
} catch (error) {
// TODO: add telemetry
}
}

function runFluidApp() {
// Listen for messages from the extension
// eslint-disable-next-line no-undef
self.addEventListener("message", async (event) => {
const message = event.data;

await loadContainer(
message.afrConfig,
message.containerId,
message.afrConfig.swpId,
message.file
);
});
}

runFluidApp();
1 change: 1 addition & 0 deletions src/web/client/telemetry/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,5 @@ export enum telemetryEventNames {
WEB_EXTENSION_WEB_COPILOT_REGISTRATION_FAILED = 'webExtensionCopilotRegisterFailed',
WEB_EXTENSION_WEB_COPILOT_NOTIFICATION_SHOWN = 'webExtensionCopilotNotificationShown',
WEB_EXTENSION_WEB_COPILOT_NOTIFICATION_EVENT_CLICKED = 'webExtensionCopilotNotificationEventClicked',
WEB_EXTENSION_AZURE_FLUID_SERVICE_LOAD_ERROR = 'webExtensionAzureFluidServiceLoadError',
}