mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-10 21:55:19 +00:00
Talk to a component host in callbacks, not observables
The component exposed the internal HostBridge to hosts as-is, which carried the host's requests as rxjs observables. That made rxjs part of the public API of a package that bundles its own copy of it, so a host would build bridges with a different rxjs than the one Element Call consumed them with — and asked every host to learn rxjs to change the theme. A component host now implements plain async callbacks for what Element Call tells it (`ElementCallHostBridge`, all optional), and makes its own requests through an imperative handle on the component's `ref` (`ElementCallHandle`: setTheme, join, hangUp, setDeviceMute), each resolving once Element Call has acted and rejecting when nothing in Element Call can. `component/host.ts` adapts that to the HostBridge the rest of Element Call still speaks, with a bridge whose identity never changes, so a host re-creating its callbacks on render restarts nothing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
d18e82c546
commit
8e8bc5ddde
@@ -5,61 +5,18 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { NEVER, Subject } from "rxjs";
|
||||
|
||||
import {
|
||||
type DeviceMuteRequest,
|
||||
type DeviceMuteState,
|
||||
type ElementCallHostBridge,
|
||||
type HostRequest,
|
||||
} from "../index";
|
||||
import { type ElementCallHostBridge } from "../index";
|
||||
|
||||
/**
|
||||
* A host bridge that reports everything it is told and can be driven by hand,
|
||||
* so that the harness can watch both directions of the conversation between
|
||||
* Element Call and its host.
|
||||
* A host bridge that reports everything it is told, so that the harness can
|
||||
* watch what Element Call says to its host. (What the host says to Element
|
||||
* Call goes through the component's handle, and is logged by the pane.)
|
||||
*/
|
||||
export interface DevHostBridge extends ElementCallHostBridge {
|
||||
/** Tells Element Call the host has changed theme. */
|
||||
requestTheme(name: string): void;
|
||||
/** Tells Element Call to leave the call. */
|
||||
requestHangUp(): void;
|
||||
/** Asks Element Call to change, and report back, its mute state. */
|
||||
requestDeviceMute(request: DeviceMuteRequest): void;
|
||||
}
|
||||
|
||||
export function createDevHostBridge(
|
||||
log: (message: string) => void,
|
||||
/** What the host does when Element Call asks to be closed. */
|
||||
onClose: () => void,
|
||||
): DevHostBridge {
|
||||
const themeChange$ = new Subject<HostRequest<{ name?: string }>>();
|
||||
const hangUp$ = new Subject<HostRequest<Record<string, never>>>();
|
||||
const deviceMute$ = new Subject<
|
||||
HostRequest<DeviceMuteRequest, DeviceMuteState>
|
||||
>();
|
||||
|
||||
const ask = <Data, Reply>(
|
||||
subject: Subject<HostRequest<Data, Reply>>,
|
||||
name: string,
|
||||
data: Data,
|
||||
): void => {
|
||||
// Worth saying out loud: a request nobody is subscribed to is silently
|
||||
// dropped, and that is exactly the sort of thing the harness is for.
|
||||
if (!subject.observed) {
|
||||
log(`← ${name}: nothing is listening`);
|
||||
return;
|
||||
}
|
||||
log(`← ${name}`);
|
||||
subject.next({
|
||||
data,
|
||||
reply: (reply): void =>
|
||||
log(
|
||||
`→ ${name} acknowledged${reply === undefined ? "" : `: ${JSON.stringify(reply)}`}`,
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
): ElementCallHostBridge {
|
||||
/**
|
||||
* Records something Element Call told the host. Nothing is sent anywhere, so
|
||||
* this is only asynchronous because a real host's answer would have to be.
|
||||
@@ -85,19 +42,5 @@ export function createDevHostBridge(
|
||||
await told("close");
|
||||
onClose();
|
||||
},
|
||||
|
||||
themeChange$,
|
||||
// The harness does not preload a call, so this is never asked for
|
||||
join$: NEVER,
|
||||
hangUp$,
|
||||
deviceMute$,
|
||||
|
||||
supportsReactions: true,
|
||||
|
||||
requestTheme: (name): void =>
|
||||
ask(themeChange$, `themeChange(${name})`, { name }),
|
||||
requestHangUp: (): void => ask(hangUp$, "hangUp", {}),
|
||||
requestDeviceMute: (request): void =>
|
||||
ask(deviceMute$, `deviceMute(${JSON.stringify(request)})`, request),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user