This commit is contained in:
Robin Townsend
2022-06-27 17:41:07 -04:00
parent 122ffeeab5
commit d5e638c8f7
5 changed files with 121 additions and 30 deletions

View File

@@ -26,9 +26,10 @@ import React, {
import { useHistory } from "react-router-dom";
import { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { logger } from "matrix-js-sdk/src/logger";
import { ErrorView } from "./FullScreenView";
import { initClient, defaultHomeserver } from "./matrix-utils";
import { initClient, initMatroskaClient, defaultHomeserver } from "./matrix-utils";
declare global {
interface Window {
@@ -86,37 +87,52 @@ export const ClientProvider: FC = ({ children }) => {
});
useEffect(() => {
const restore = async (): Promise<
const init = async (): Promise<
Pick<ClientProviderState, "client" | "isPasswordlessUser">
> => {
try {
const session = loadSession();
const query = new URLSearchParams(window.location.search);
const widgetId = query.get("widgetId");
const parentUrl = query.get("parentUrl");
if (session) {
/* eslint-disable camelcase */
const { user_id, device_id, access_token, passwordlessUser } =
session;
if (widgetId && parentUrl) {
// We're inside a widget, so let's engage *Matroska mode*
logger.log("Using a Matroska client");
const client = await initClient({
baseUrl: defaultHomeserver,
accessToken: access_token,
userId: user_id,
deviceId: device_id,
});
/* eslint-enable camelcase */
return {
client: await initMatroskaClient(widgetId, parentUrl),
isPasswordlessUser: false,
};
} else {
// We're running as a standalone application
try {
const session = loadSession();
return { client, isPasswordlessUser: passwordlessUser };
if (session) {
/* eslint-disable camelcase */
const { user_id, device_id, access_token, passwordlessUser } =
session;
logger.log("Using a standalone client");
const client = await initClient({
baseUrl: defaultHomeserver,
accessToken: access_token,
userId: user_id,
deviceId: device_id,
});
/* eslint-enable camelcase */
return { client, isPasswordlessUser: passwordlessUser };
}
return { client: undefined, isPasswordlessUser: false };
} catch (err) {
clearSession();
throw err;
}
return { client: undefined, isPasswordlessUser: false };
} catch (err) {
console.error(err);
clearSession();
throw err;
}
};
restore()
init()
.then(({ client, isPasswordlessUser }) => {
setState({
client,
@@ -126,7 +142,8 @@ export const ClientProvider: FC = ({ children }) => {
userName: client?.getUserIdLocalpart(),
});
})
.catch(() => {
.catch((err) => {
logger.error(err);
setState({
client: undefined,
loading: false,

View File

@@ -5,15 +5,17 @@ import { MemoryStore } from "matrix-js-sdk/src/store/memory";
import { IndexedDBCryptoStore } from "matrix-js-sdk/src/crypto/store/indexeddb-crypto-store";
import { LocalStorageCryptoStore } from "matrix-js-sdk/src/crypto/store/localStorage-crypto-store";
import { MemoryCryptoStore } from "matrix-js-sdk/src/crypto/store/memory-crypto-store";
import { createClient, MatrixClient } from "matrix-js-sdk/src/matrix";
import { createClient, createRoomWidgetClient, MatrixClient } from "matrix-js-sdk/src/matrix";
import { ICreateClientOpts } from "matrix-js-sdk/src/matrix";
import { ClientEvent } from "matrix-js-sdk/src/client";
import { EventType } from "matrix-js-sdk/src/@types/event";
import { Visibility, Preset } from "matrix-js-sdk/src/@types/partials";
import {
GroupCallIntent,
GroupCallType,
} from "matrix-js-sdk/src/webrtc/groupCall";
import { ISyncStateData, SyncState } from "matrix-js-sdk/src/sync";
import { WidgetApi } from "matrix-widget-api";
import IndexedDBWorker from "./IndexedDBWorker?worker";
@@ -42,6 +44,63 @@ function waitForSync(client: MatrixClient) {
});
}
// The event types that the app needs to be able to send/receive in Matroska
// mode in order to function
const SEND_RECV_STATE = [
{ eventType: EventType.RoomMember },
{ eventType: EventType.GroupCallPrefix },
{ eventType: EventType.GroupCallMemberPrefix },
];
const SEND_RECV_TO_DEVICE = [
EventType.CallInvite,
EventType.CallCandidates,
EventType.CallAnswer,
EventType.CallHangup,
EventType.CallReject,
EventType.CallSelectAnswer,
EventType.CallNegotiate,
EventType.CallSDPStreamMetadataChanged,
EventType.CallSDPStreamMetadataChangedPrefix,
EventType.CallReplaces,
"org.matrix.call_duplicate_session",
];
export async function initMatroskaClient(
widgetId: string, parentUrl: string,
): Promise<MatrixClient> {
// In this mode, we use a special client which routes all requests through
// the host application via the widget API
// The rest of the data we need is encoded in the fragment so as to avoid
// leaking it to the server
const fragmentQueryStart = window.location.hash.indexOf("?");
const roomId = window.location.hash.substring(0, fragmentQueryStart);
const fragmentQuery = new URLSearchParams(window.location.hash.substring(fragmentQueryStart));
// Since all data should be coming from the host application, there's no
// need to persist anything, and therefore we can use the default stores
// We don't even need to set up crypto!
const client = createRoomWidgetClient(
new WidgetApi(widgetId, new URL(parentUrl).origin),
{
sendState: SEND_RECV_STATE,
receiveState: SEND_RECV_STATE,
sendToDevice: SEND_RECV_TO_DEVICE,
receiveToDevice: SEND_RECV_TO_DEVICE,
},
roomId,
{
baseUrl: "",
userId: fragmentQuery.get("userId"),
deviceId: fragmentQuery.get("deviceId"),
timelineSupport: true,
},
);
await client.startClient();
return client;
}
export async function initClient(
clientOptions: ICreateClientOpts
): Promise<MatrixClient> {
@@ -83,7 +142,7 @@ export async function initClient(
...storeOpts,
...clientOptions,
useAuthorizationHeader: true,
// Use a relatively low timeout for API calls: this is a realtime application
// Use a relatively low timeout for API calls: this is a realtime app
// so we don't want API calls taking ages, we'd rather they just fail.
localTimeoutMs: 5000,
});

View File

@@ -23,7 +23,8 @@ async function fetchGroupCall(
viaServers = undefined,
timeout = 5000
) {
const { roomId } = await client.joinRoom(roomIdOrAlias, { viaServers });
//const { roomId } = await client.joinRoom(roomIdOrAlias, { viaServers });
const roomId = roomIdOrAlias;
return new Promise((resolve, reject) => {
let timeoutId;