如何:连接到 Azure Fluid Relay 服务

本文逐步介绍如何预配并准备好使用 Azure Fluid Relay 服务。

重要

在将应用连接到 Azure Fluid Relay 服务器之前,必须在 Azure 帐户上预配 Azure Fluid Relay 服务器资源。

Azure Fluid Relay 服务是一种云托管的 Fluid 服务。 可以使用 @fluidframework/azure-client 包中的 AzureClient 将 Fluid 应用程序连接到 Azure Fluid Relay 实例。 AzureClient 负责处理将 Fluid 容器连接到服务的逻辑,同时保持容器对象本身与服务无关。 你可以使用此客户端的一个实例来管理多个容器。

以下部分将说明如何在你自己的应用程序中使用 AzureClient

连接到服务

若要连接到 Azure Fluid Relay 实例,首先需要创建一个 AzureClient。 你必须提供一些配置参数(包括租户 ID、服务 URL 和令牌提供程序)来生成 JSON Web 令牌 (JWT),其中 JWT 将用于针对服务向当前用户授权。 @fluidframework/test-client-utils 包提供了一个 InsecureTokenProvider,可用于开发目的。

注意

InsecureTokenProvider 只能用于开发目的,因为使用它会在客户端代码捆绑包中公开租户密钥。必须将其替换为 ITokenProvider 的实现,后者将从你自己的后端服务提取令牌,该服务负责使用租户密钥对令牌进行签名。 一个示例实现是 AzureFunctionTokenProvider。 有关详细信息,请参阅如何:使用 Azure 函数编写 TokenProvider。 请注意,idname 字段是任意字段。

const user = { id: "userId", name: "userName" };

const config = {
  tenantId: "myTenantId",
  tokenProvider: new InsecureTokenProvider("myTenantKey", user),
  endpoint: "https://myServiceEndpointUrl",
  type: "remote",
};

const clientProps = {
  connection: config,
};

const client = new AzureClient(clientProps);

你已经拥有 AzureClient 的实例,现在可以开始使用它创建或加载 Fluid 容器!

令牌提供程序

AzureFunctionTokenProvider 是 ITokenProvider 的实现,可确保租户密钥不在客户端捆绑代码中公开。 AzureFunctionTokenProvider 接受追加了 /api/GetAzureToken 以及当前用户对象的 Azure 函数 URL。 稍后,它通过将 tenantId、documentId 和 userId/userName 作为可选参数传入,向 Azure 函数发出 GET 请求。

const config = {
  tenantId: "myTenantId",
  tokenProvider: new AzureFunctionTokenProvider(
    "myAzureFunctionUrl" + "/api/GetAzureToken",
    { userId: "userId", userName: "Test User" }
  ),
  endpoint: "https://myServiceEndpointUrl",
  type: "remote",
};

const clientProps = {
  connection: config,
};

const client = new AzureClient(clientProps);

向令牌添加自定义数据

用户对象还可以保存可选的附加用户详细信息。 例如:

const userDetails = {
  email: "xyz@outlook.com",
  address: "Redmond",
};

const config = {
  tenantId: "myTenantId",
  tokenProvider: new AzureFunctionTokenProvider(
    "myAzureFunctionUrl" + "/api/GetAzureToken",
    { userId: "UserId", userName: "Test User", additionalDetails: userDetails }
  ),
  endpoint: "https://myServiceEndpointUrl",
  type: "remote",
};

Azure 函数将为给定用户生成使用租户密钥签名的令牌,并将其返回给客户端,而不会公开密钥本身。

管理容器

AzureClient API 公开 createContainer 和 getContainer 函数以分别创建和获取容器。 这两个函数都采用容器架构来定义容器数据模型。 对于 getContainer 函数,你希望提取的容器的容器 id 有一个附加参数。

在容器创建方案中,可以使用以下模式:

const schema = {
  initialObjects: {
    /* ... */
  },
  dynamicObjectTypes: [
    /*...*/
  ],
};
const azureClient = new AzureClient(clientProps);
const { container, services } = await azureClient.createContainer(
  schema
);
const id = await container.attach();

container.attach() 调用是容器实际连接到服务并记录在其 blob 存储中的时间。 它返回一个 id,后者是此容器实例的唯一标识符。

任何想要加入同一协作会话的客户端都需要使用同一容器 id 来调用 getContainer

const { container, services } = await azureClient.getContainer(
  id,
  schema
);

要进一步了解如何开始记录 Fluid 发出的日志,请参阅 Logging and telemetry(日志记录和遥测)。

取回的容器将保存容器架构中定义的 initialObjects。 请参阅 fluidframework.com 上的 Data modeling(数据建模),详细了解如何建立架构和使用 container 对象。

获取受众详细信息

createContainergetContainer 的调用会返回两个值:container(如上所述)和一个服务对象。

container 包含 Fluid 数据模型并且与服务无关。 针对 AzureClient 返回的此容器对象编写的任何代码都可重用于其他服务的客户端。 例如,如果你使用 TinyliciousClient 为自己的方案制作原型,那么在转为使用 AzureClient 时,所有与 Fluid 容器内的共享对象交互的代码都可以重复使用。

services 对象包含特定于 Azure Fluid Relay 服务的数据。 此对象包含一个受众值,可用于管理当前连接到容器的用户的名单。

以下代码演示如何使用 audience 对象来维护容器中当前所有成员的更新视图。

const { audience } = containerServices;
const audienceDiv = document.createElement("div");

const onAudienceChanged = () => {
  const members = audience.getMembers();
  const self = audience.getMyself();
  const memberStrings = [];
  const useAzure = process.env.FLUID_CLIENT === "azure";

  members.forEach((member) => {
    if (member.userId !== (self ? self.userId : "")) {
      if (useAzure) {
        const memberString = `${member.userName}: {Email: ${member.additionalDetails ? member.additionalDetails.email : ""},
                        Address: ${member.additionalDetails ? member.additionalDetails.address : ""}}`;
        memberStrings.push(memberString);
      } else {
        memberStrings.push(member.userName);
      }
    }
  });
  audienceDiv.innerHTML = `
            Current User: ${self ? self.userName : ""} <br />
            Other Users: ${memberStrings.join(", ")}
        `;
};

onAudienceChanged();
audience.on("membersChanged", onAudienceChanged);

audience 提供两个函数,它们将返回具有用户 ID 和用户名的 AzureMember 对象:

  • getMembers 返回连接到容器的所有用户的映射。 这些值将在成员加入或离开容器时发生变化。
  • getMyself 返回此客户端上的当前用户。

audience 还会在成员名单更改时发出事件。 membersChanged 将针对任何名单更改触发,而 memberAddedmemberRemoved 将针对已修改的 clientIdmember 值的相应更改触发。 在这些事件中的任何一个触发后,对 getMembers 的新调用将返回更新的成员名单。

AzureMember 对象示例如下所示:

{
  "userId": "0e662aca-9d7d-4ff0-8faf-9f8672b70f15",
  "userName": "Test User",
  "connections": [
    {
      "id": "c699c3d1-a4a0-4e9e-aeb4-b33b00544a71",
      "mode": "write"
    },
    {
      "id": "0e662aca-9d7d-4ff0-8faf-9f8672b70f15",
      "mode": "write"
    }
  ],
  "additionalDetails": {
    "email": "xyz@outlook.com",
    "address": "Redmond"
  }
}

除了用户 ID、姓名和其他详细信息外,AzureMember 对象还保存一个连接数组。 如果用户仅使用一个客户端登录会话,connections 将只有一个包含客户端 ID 的值,并且处于读/写模式。 但是,如果同一用户从多个客户端登录(即,从不同的设备登录或使用同一容器打开多个浏览器选项卡),则此处的 connections 将为每个客户端保存多个值。 在上面的示例数据中,我们可以看到名称为“Test User”且 ID 为“0e662aca-9d7d-4ff0-8faf-9f8672b70f15”的用户当前从两个不同的客户端打开了容器。 additionalDetails 字段中的值与 AzureFunctionTokenProvider 令牌生成中提供的值匹配。

这些函数和事件可以结合起来,呈现当前会话中用户的实时视图。

祝贺你! 你现在已成功将 Fluid 容器连接到 Azure Fluid Relay 服务,并为协作会话中的成员取回了用户详细信息!