Skip to content
Merged
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
32 changes: 17 additions & 15 deletions packages/live-share/src/AzureLiveShareClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,25 +82,25 @@ export class AzureLiveShareClient extends BaseLiveShareClient {
* @param initialObjects Optional. Fluid ContainerSchema initialObjects.
* @returns New detached container instance along with associated services.
*/
public async createContainer(
fluidContainerSchema?: ContainerSchema
public async createContainer<T extends ContainerSchema>(
fluidContainerSchema?: T
): Promise<{
container: IFluidContainer;
container: IFluidContainer<T>;
services: AzureContainerServices;
}> {
const schema = this.getInjectedContainerSchema(fluidContainerSchema);
this._results = await this._client.createContainer(
const results = (this._results = await this._client.createContainer(
schema,
FluidCompatibilityMode
);
));
if (this._host instanceof AzureLiveShareHost) {
this._host.setAudience(this._results.services.audience);
}

await this.addTurboFolder(this._results.container);

await this._runtime.start();
return this._results;
return results;
}

/**
Expand All @@ -116,29 +116,31 @@ export class AzureLiveShareClient extends BaseLiveShareClient {
* @param host Optional. ILiveShareHost implementation to use when using Live Share DDS's.
* @returns Existing container instance along with associated services.
*/
public async getContainer(
public async getContainer<
TContainerSchema extends ContainerSchema = ContainerSchema,
>(
id: string,
fluidContainerSchema?: ContainerSchema
fluidContainerSchema?: TContainerSchema
): Promise<{
container: IFluidContainer;
container: IFluidContainer<TContainerSchema>;
services: AzureContainerServices;
}> {
const schema = this.getInjectedContainerSchema(fluidContainerSchema);
this._results = await this._client.getContainer(
const results = (this._results = await this._client.getContainer(
id,
schema,
FluidCompatibilityMode
);
));
if (this._host instanceof AzureLiveShareHost) {
this._host.setAudience(this._results.services.audience);
}
await this._runtime.start();
return this._results;
return results;
}

private getInjectedContainerSchema(
fluidContainerSchema?: ContainerSchema
): ContainerSchema {
private getInjectedContainerSchema<
TContainerSchema extends ContainerSchema,
>(fluidContainerSchema?: TContainerSchema): TContainerSchema {
return getLiveContainerSchema(
this.getContainerSchema(fluidContainerSchema),
this._runtime
Expand Down
44 changes: 28 additions & 16 deletions packages/live-share/src/LiveShareClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ export class LiveShareClient extends BaseLiveShareClient {
```ts
import { LiveShareClient, LivePresence, LiveState } from "@microsoft/live-share";
import { LiveShareHost } from "@microsoft/teams-js";
import { ContainerSchema } from "fluid-framework";

// Join the Fluid container
const host = LiveShareHost.create();
Expand All @@ -219,20 +220,22 @@ export class LiveShareClient extends BaseLiveShareClient {
initialObjects: {
presence: LivePresence
}
};
} as const satisfies ContainerSchema;
const { container } = await client.join(schema, (container) => {
console.log("First created container", container);
});
const presence = container.initialObjects.presence as unknown as LivePresence;
const presence = container.initialObjects.presence;

// Can still dynamically get DDS's that were not in schema
const counter = await client.getDDS("unique-id", LiveState<number>);
```
*/
public async join(
fluidContainerSchema?: ContainerSchema,
onContainerFirstCreated?: (container: IFluidContainer) => void
): Promise<ILiveShareJoinResults> {
public async join<const TContainerSchema extends ContainerSchema>(
fluidContainerSchema?: TContainerSchema,
onContainerFirstCreated?: (
container: IFluidContainer<TContainerSchema>
) => void
): Promise<ILiveShareJoinResults<TContainerSchema>> {
performance.mark(`TeamsSync: join container`);
try {
// Start runtime if needed
Expand Down Expand Up @@ -309,11 +312,12 @@ export class LiveShareClient extends BaseLiveShareClient {

performance.mark(`TeamsSync: container connecting`);

this._results = {
const results = {
...result[0],
timestampProvider: this._runtime.timestampProvider,
};
return this._results;
this._results = results;
return results;
} finally {
performance.measure(
`TeamsSync: container joined`,
Expand All @@ -322,13 +326,17 @@ export class LiveShareClient extends BaseLiveShareClient {
}
}

private async getOrCreateContainer(
private async getOrCreateContainer<
const TContainerSchema extends ContainerSchema,
>(
client: AzureClient,
fluidContainerSchema: ContainerSchema,
fluidContainerSchema: TContainerSchema,
tries: number,
onInitializeContainer?: (container: IFluidContainer) => void
onInitializeContainer?: (
container: IFluidContainer<TContainerSchema>
) => void
): Promise<{
container: IFluidContainer;
container: IFluidContainer<TContainerSchema>;
services: AzureContainerServices;
created: boolean;
}> {
Expand Down Expand Up @@ -370,13 +378,17 @@ export class LiveShareClient extends BaseLiveShareClient {
}
}

private async createNewContainer(
private async createNewContainer<
const TContainerSchema extends ContainerSchema,
>(
client: AzureClient,
fluidContainerSchema: ContainerSchema,
fluidContainerSchema: TContainerSchema,
tries: number,
onInitializeContainer?: (container: IFluidContainer) => void
onInitializeContainer?: (
container: IFluidContainer<TContainerSchema>
) => void
): Promise<{
container: IFluidContainer;
container: IFluidContainer<TContainerSchema>;
services: AzureContainerServices;
created: boolean;
}> {
Expand Down
8 changes: 5 additions & 3 deletions packages/live-share/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { IInboundSignalMessage } from "@fluidframework/runtime-definitions/legacy";
import { AzureContainerServices } from "@fluidframework/azure-client";
import { IFluidContainer } from "fluid-framework";
import type { IFluidContainer, ContainerSchema } from "fluid-framework";

/**
* Base interface for all event objects.
Expand Down Expand Up @@ -283,11 +283,13 @@ export interface ILiveShareHost {
/**
* Response object from `.join()` in `LiveShareClient`
*/
export interface ILiveShareJoinResults {
export interface ILiveShareJoinResults<
TContainerSchema extends ContainerSchema = ContainerSchema,
> {
/**
* Fluid container
*/
container: IFluidContainer;
container: IFluidContainer<TContainerSchema>;
/**
* Azure Container Services, which includes things like Fluid Audience
*/
Expand Down
8 changes: 5 additions & 3 deletions packages/live-share/src/internals/BaseLiveShareClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ export abstract class BaseLiveShareClient {
* @param initialObjects Optional. Initial objects to add to the schema
* @returns a `ContainerSchema` record to use in a Fluid container
*/
protected getContainerSchema(schema?: ContainerSchema): ContainerSchema {
protected getContainerSchema<
const TContainerSchema extends ContainerSchema,
>(schema?: TContainerSchema): TContainerSchema {
return {
initialObjects: {
...schema?.initialObjects,
Expand All @@ -209,8 +211,8 @@ export abstract class BaseLiveShareClient {
dynamicObjectTypes: [
...(schema?.dynamicObjectTypes ?? []),
...DynamicObjectRegistry.dynamicLoadableObjects.values(),
] as unknown as SharedObjectKind[],
};
],
} as TContainerSchema /* and added the dynamic object types */;
}

/**
Expand Down
9 changes: 4 additions & 5 deletions packages/live-share/src/internals/schema-injection-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ type LiveObjectClass<T extends IFluidLoadable> = {
* @param liveRuntime LiveShareRuntime instance
* @returns ContainerSchema with injected dependencies
*/
export function getLiveContainerSchema(
schema: ContainerSchema,
liveRuntime: LiveShareRuntime
): ContainerSchema {
export function getLiveContainerSchema<
const TContainerSchema extends ContainerSchema,
>(schema: TContainerSchema, liveRuntime: LiveShareRuntime): TContainerSchema {
// Each container must proxy LiveDataObject classes separately.
// This map is used to de-duplicate proxies for each class.
const injectedClasses = new Map<string, SharedObjectKind<any>>();
Expand All @@ -62,7 +61,7 @@ export function getLiveContainerSchema(
dynamicObjectTypes: schema.dynamicObjectTypes?.map((objectClass) =>
getLiveDataObjectKind(objectClass, liveRuntime, injectedClasses)
),
};
} as TContainerSchema;
}

/**
Expand Down
14 changes: 7 additions & 7 deletions packages/live-share/src/test/AzureLiveShareClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,17 @@ describe("AzureTurboClient", () => {

const testMapKey = "TEST-MAP-KEY";
const testLiveEventKey = "TEST-LIVE-EVENT-KEY";
const schema = {
initialObjects: {
[testLiveEventKey]: LiveEvent,
},
} as const satisfies ContainerSchema;
let results1: {
container: IFluidContainer;
container: IFluidContainer<typeof schema>;
services: AzureContainerServices;
};
let results2: {
container: IFluidContainer;
container: IFluidContainer<typeof schema>;
services: AzureContainerServices;
};

Expand All @@ -56,11 +61,6 @@ describe("AzureTurboClient", () => {
client2 = new AzureLiveShareClient({
connection: connectionProps,
});
const schema: ContainerSchema = {
initialObjects: {
[testLiveEventKey]: LiveEvent,
},
};
results1 = await client1.createContainer(schema);
const containerId = await results1.container.attach();
results2 = await client2.getContainer(containerId, schema);
Expand Down
4 changes: 2 additions & 2 deletions samples/typescript/31.live-canvas-tests/src/inking-surface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const containerSchema = {
export class InkingSurface {
private _hostElement: HTMLElement;
private _inkingManager!: InkingManager;
private _container!: IFluidContainer;
private _container!: IFluidContainer<typeof containerSchema>;

private async internalStart() {
const client = new LiveShareClient(TestLiveShareHost.create());
Expand All @@ -45,7 +45,7 @@ export class InkingSurface {
}

getLiveCanvas(): LiveCanvas {
return this._container.initialObjects.liveCanvas as LiveCanvas;
return this._container.initialObjects.liveCanvas;
}

async start() {
Expand Down