MSC3575 (Sliding Sync) add well-known proxy support (#12307)

* Initial commit

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Remove commented code

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Change function to reflect it's proxy not native support

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Re-add check for servers with native support

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Add native support check back in

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Re-add endpoint health check function

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Use inbuilt `getWellKnown` function

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Change the error message to the correct function

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Stop storing the proxyurl in the settings for now

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Make the logger messages more useful

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Start moving the checking logic directly into the controller

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Add missing import

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Get the client rather than passing it in to the functions

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* remove invalid `function` keyword

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Fix imports

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Our new functions are private

We shouldn't(?) have to use these check in future elsewhere

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Change our proxy check function to return a boolean

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Make `nativeSlidingSyncSupport` also return boolean, add in health check

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Disable the sliding sync option if the server doesn't support

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Only enable the setting if it passes (again)

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Update our comments to better match what's going on

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Remove unused dialog

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Add a well-known check on start-up, if sliding sync has been enabled

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Check against the correct endpoint...

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Extract baseUrl as we'll reuse it

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Make the logs differentiate between the types of proxy

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Grab the client well-known directly for use

Can't use the client object at this point, it hasn't read in the well-known

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Add myself to the copyright assignation

I wrote the majority of this file...

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Only return `true` if it's actually there

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Correct the `proxySlidingSyncSupport` function comment to match the code

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Correct the `nativeSlidingSyncSupport`function comment to match the code

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Another comment/functionality paring

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Remove duplicated types from the doc

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Move await to the previous line

Removes brackets, and corrects `wellKnown` from being a `Promise`
Signed-off-by: Ed Geraghty <ed@geraghty.family>

* use `waitForClientWellKnown` to avoid a race condition with the request

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Move getting the client out of the `if`, use `waitForClientWellKnown`

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Remove `beforeChange` override

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Move proxy setup logic into `SlidingSyncManager`

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Swap `configure` to private, we call it from `setup` which handles proxy

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Promises are always `true`

TIL.
Signed-off-by: Ed Geraghty <ed@geraghty.family>

* use `timeoutSignal`

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Change message when there's no server support

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Refactor `slidingSyncHealthCheck`

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Refactor `nativeSlidingSyncSupport` with try/catch

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Change comment to hotlink

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Try and make the toggle disabled when there's no endpoint

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Move the if statement outside the refactored fn to avoid an await

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Revert "Swap `configure` to private, we call it from `setup` which handles proxy"

This reverts commit c80a00b50c261becc9ad58e08d2a893d572d8426.

* Remove unused import

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Further refactor `slidingSyncHealthCheck`

`proxySlidingSyncSupport` already checks the client well-known is there
Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Make `proxySlidingSyncSupport` log on success

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Clarify log message for proxy being up

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Move the logic into SlidingSyncManager

All so we can set a static variable because the disabled check isn't asynchronous :)

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Obviously this isn't a return so don't overwrite with false!

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Remove outdated comment

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* No need to pass in the client

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Activating SS should probably be info level logs

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* If we've not enabled sliding sync, push the logs down a bit

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Update i18n error message

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Remove unused i18n strings

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Correct log message

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Prettier

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Remove many of the log messages

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Short out of `checkSupport` if it's `true`

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Add the endpoint back into the log when we're enabling it

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Note in the comment that `feature_sliding_sync_proxy_url` is legacy

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Expand the well-known liveness check log

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* No need to stall the client waiting for sliding sync support

* `AutoDiscovery.findClientConfig` throws if the baseUrl is blank

* Fix `getProxyFromWellKnown` (?)

* Add missing semicolon

Sorry, linter!
Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Pass our `MatrixClient` through instead of trying to grab it

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Add missing return in function comment

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Actually pass through our Client, not the Peg object

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Remove SonarCube smell complaint

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Neew to make our other two methods public to test

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* First passing test

Hurrah!
Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Two more tests, this time on `checkSupport`

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Reset our `serverSupportsSlidingSync` between tests

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Check the static member is being set

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Move the static assignation down to the relevant tests

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Pull getProxyFromWellKnown mocking up

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Check we /haven't/ shorted out

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Move our spy up so we can reuse it

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Check spidering  is being called

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Test the proxy is declared

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Test entered manually

Signed-off-by: Ed Geraghty <ed@geraghty.family>

* Sorry, linter

* I guess these strings are wrong?

* Replace any with string

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Ed Geraghty <ed@geraghty.family>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Ed Geraghty 2024-04-30 19:11:11 +01:00 committed by GitHub
parent 641a20ce63
commit bb4f57583f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 154 additions and 171 deletions

View File

@ -273,17 +273,9 @@ class MatrixClientPegClass implements IMatrixClientPeg {
opts.threadSupport = true; opts.threadSupport = true;
if (SettingsStore.getValue("feature_sliding_sync")) { if (SettingsStore.getValue("feature_sliding_sync")) {
const proxyUrl = SettingsStore.getValue("feature_sliding_sync_proxy_url"); opts.slidingSync = await SlidingSyncManager.instance.setup(this.matrixClient);
if (proxyUrl) { } else {
logger.log("Activating sliding sync using proxy at ", proxyUrl); SlidingSyncManager.instance.checkSupport(this.matrixClient);
} else {
logger.log("Activating sliding sync");
}
opts.slidingSync = SlidingSyncManager.instance.configure(
this.matrixClient,
proxyUrl || this.matrixClient.baseUrl,
);
SlidingSyncManager.instance.startSpidering(100, 50); // 100 rooms at a time, 50ms apart
} }
// Connect the matrix client to the dispatcher and setting handlers // Connect the matrix client to the dispatcher and setting handlers

View File

@ -44,7 +44,7 @@ limitations under the License.
* list ops) * list ops)
*/ */
import { MatrixClient, EventType } from "matrix-js-sdk/src/matrix"; import { MatrixClient, EventType, AutoDiscovery, Method, timeoutSignal } from "matrix-js-sdk/src/matrix";
import { import {
MSC3575Filter, MSC3575Filter,
MSC3575List, MSC3575List,
@ -56,6 +56,9 @@ import {
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { defer, sleep } from "matrix-js-sdk/src/utils"; import { defer, sleep } from "matrix-js-sdk/src/utils";
import SettingsStore from "./settings/SettingsStore";
import SlidingSyncController from "./settings/controllers/SlidingSyncController";
// how long to long poll for // how long to long poll for
const SLIDING_SYNC_TIMEOUT_MS = 20 * 1000; const SLIDING_SYNC_TIMEOUT_MS = 20 * 1000;
@ -323,4 +326,93 @@ export class SlidingSyncManager {
firstTime = false; firstTime = false;
} }
} }
/**
* Set up the Sliding Sync instance; configures the end point and starts spidering.
* The sliding sync endpoint is derived the following way:
* 1. The user-defined sliding sync proxy URL (legacy, for backwards compatibility)
* 2. The client `well-known` sliding sync proxy URL [declared at the unstable prefix](https://github.com/matrix-org/matrix-spec-proposals/blob/kegan/sync-v3/proposals/3575-sync.md#unstable-prefix)
* 3. The homeserver base url (for native server support)
* @param client The MatrixClient to use
* @returns A working Sliding Sync or undefined
*/
public async setup(client: MatrixClient): Promise<SlidingSync | undefined> {
const baseUrl = client.baseUrl;
const proxyUrl = SettingsStore.getValue("feature_sliding_sync_proxy_url");
const wellKnownProxyUrl = await this.getProxyFromWellKnown(client);
const slidingSyncEndpoint = proxyUrl || wellKnownProxyUrl || baseUrl;
this.configure(client, slidingSyncEndpoint);
logger.info("Sliding sync activated at", slidingSyncEndpoint);
this.startSpidering(100, 50); // 100 rooms at a time, 50ms apart
return this.slidingSync;
}
/**
* Get the sliding sync proxy URL from the client well known
* @param client The MatrixClient to use
* @return The proxy url
*/
public async getProxyFromWellKnown(client: MatrixClient): Promise<string | undefined> {
let proxyUrl: string | undefined;
try {
const clientWellKnown = await AutoDiscovery.findClientConfig(client.baseUrl);
proxyUrl = clientWellKnown?.["org.matrix.msc3575.proxy"]?.url;
} catch (e) {
// client.baseUrl is invalid, `AutoDiscovery.findClientConfig` has thrown
}
if (proxyUrl != undefined) {
logger.log("getProxyFromWellKnown: client well-known declares sliding sync proxy at", proxyUrl);
}
return proxyUrl;
}
/**
* Check if the server "natively" supports sliding sync (at the unstable endpoint).
* @param client The MatrixClient to use
* @return Whether the "native" (unstable) endpoint is up
*/
public async nativeSlidingSyncSupport(client: MatrixClient): Promise<boolean> {
try {
await client.http.authedRequest<void>(Method.Post, "/sync", undefined, undefined, {
localTimeoutMs: 10 * 1000, // 10s
prefix: "/_matrix/client/unstable/org.matrix.msc3575",
});
} catch (e) {
return false; // 404, M_UNRECOGNIZED
}
logger.log("nativeSlidingSyncSupport: sliding sync endpoint is up");
return true; // 200, OK
}
/**
* Check whether our homeserver has sliding sync support, that the endpoint is up, and
* is a sliding sync endpoint.
*
* Sets static member `SlidingSyncController.serverSupportsSlidingSync`
* @param client The MatrixClient to use
*/
public async checkSupport(client: MatrixClient): Promise<void> {
if (await this.nativeSlidingSyncSupport(client)) {
SlidingSyncController.serverSupportsSlidingSync = true;
return;
}
const proxyUrl = await this.getProxyFromWellKnown(client);
if (proxyUrl != undefined) {
const response = await fetch(proxyUrl + "/client/server.json", {
method: Method.Get,
signal: timeoutSignal(10 * 1000), // 10s
});
if (response.status === 200) {
logger.log("checkSupport: well-known sliding sync proxy is up at", proxyUrl);
SlidingSyncController.serverSupportsSlidingSync = true;
}
}
}
} }

View File

@ -1,142 +0,0 @@
/*
Copyright 2022 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import { MatrixClient, Method } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger";
import { _t } from "../../../languageHandler";
import SettingsStore from "../../../settings/SettingsStore";
import TextInputDialog from "./TextInputDialog";
import withValidation from "../elements/Validation";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { useAsyncMemo } from "../../../hooks/useAsyncMemo";
import { SettingLevel } from "../../../settings/SettingLevel";
/**
* Check that the server natively supports sliding sync.
* @param cli The MatrixClient of the logged in user.
* @throws if the proxy server is unreachable or not configured to the given homeserver
*/
async function syncHealthCheck(cli: MatrixClient): Promise<void> {
await cli.http.authedRequest(Method.Post, "/sync", undefined, undefined, {
localTimeoutMs: 10 * 1000, // 10s
prefix: "/_matrix/client/unstable/org.matrix.msc3575",
});
logger.info("server natively support sliding sync OK");
}
/**
* Check that the proxy url is in fact a sliding sync proxy endpoint and it is up.
* @param endpoint The proxy endpoint url
* @param hsUrl The homeserver url of the logged in user.
* @throws if the proxy server is unreachable or not configured to the given homeserver
*/
async function proxyHealthCheck(endpoint: string, hsUrl?: string): Promise<void> {
const controller = new AbortController();
const id = window.setTimeout(() => controller.abort(), 10 * 1000); // 10s
const res = await fetch(endpoint + "/client/server.json", {
signal: controller.signal,
});
clearTimeout(id);
if (res.status != 200) {
throw new Error(`proxyHealthCheck: proxy server returned HTTP ${res.status}`);
}
const body = await res.json();
if (body.server !== hsUrl) {
throw new Error(`proxyHealthCheck: client using ${hsUrl} but server is as ${body.server}`);
}
logger.info("sliding sync proxy is OK");
}
export const SlidingSyncOptionsDialog: React.FC<{ onFinished(enabled: boolean): void }> = ({ onFinished }) => {
const cli = MatrixClientPeg.safeGet();
const currentProxy = SettingsStore.getValue("feature_sliding_sync_proxy_url");
const hasNativeSupport = useAsyncMemo(
() =>
syncHealthCheck(cli).then(
() => true,
() => false,
),
[],
null,
);
let nativeSupport: string;
if (hasNativeSupport === null) {
nativeSupport = _t("labs|sliding_sync_checking");
} else {
nativeSupport = hasNativeSupport
? _t("labs|sliding_sync_server_support")
: _t("labs|sliding_sync_server_no_support");
}
const validProxy = withValidation<undefined, { error?: unknown }>({
async deriveData({ value }): Promise<{ error?: unknown }> {
if (!value) return {};
try {
await proxyHealthCheck(value, MatrixClientPeg.safeGet().baseUrl);
return {};
} catch (error) {
return { error };
}
},
rules: [
{
key: "required",
test: async ({ value }) => !!value || !!hasNativeSupport,
invalid: () => _t("labs|sliding_sync_server_specify_proxy"),
},
{
key: "working",
final: true,
test: async (_, { error }) => !error,
valid: () => _t("spotlight|public_rooms|network_dropdown_available_valid"),
invalid: ({ error }) => (error instanceof Error ? error.message : null),
},
],
});
return (
<TextInputDialog
title={_t("labs|sliding_sync_configuration")}
description={
<div>
<div>
<b>{_t("labs|sliding_sync_disable_warning")}</b>
</div>
{nativeSupport}
</div>
}
placeholder={
hasNativeSupport
? _t("labs|sliding_sync_proxy_url_optional_label")
: _t("labs|sliding_sync_proxy_url_label")
}
value={currentProxy}
button={_t("action|enable")}
validator={validProxy}
onFinished={(enable, proxyUrl) => {
if (enable) {
SettingsStore.setValue("feature_sliding_sync_proxy_url", null, SettingLevel.DEVICE, proxyUrl);
onFinished(true);
} else {
onFinished(false);
}
}}
/>
);
};

View File

@ -1460,16 +1460,9 @@
"rust_crypto_optin_warning": "Switching to the Rust cryptography requires a migration process that may take several minutes. To disable you will need to log out and back in; use with caution!", "rust_crypto_optin_warning": "Switching to the Rust cryptography requires a migration process that may take several minutes. To disable you will need to log out and back in; use with caution!",
"rust_crypto_requires_logout": "Once enabled, Rust cryptography can only be disabled by logging out and in again", "rust_crypto_requires_logout": "Once enabled, Rust cryptography can only be disabled by logging out and in again",
"sliding_sync": "Sliding Sync mode", "sliding_sync": "Sliding Sync mode",
"sliding_sync_checking": "Checking…",
"sliding_sync_configuration": "Sliding Sync configuration",
"sliding_sync_description": "Under active development, cannot be disabled.", "sliding_sync_description": "Under active development, cannot be disabled.",
"sliding_sync_disable_warning": "To disable you will need to log out and back in, use with caution!",
"sliding_sync_disabled_notice": "Log out and back in to disable", "sliding_sync_disabled_notice": "Log out and back in to disable",
"sliding_sync_proxy_url_label": "Proxy URL", "sliding_sync_server_no_support": "Your server lacks support",
"sliding_sync_proxy_url_optional_label": "Proxy URL (optional)",
"sliding_sync_server_no_support": "Your server lacks native support",
"sliding_sync_server_specify_proxy": "Your server lacks native support, you must specify a proxy",
"sliding_sync_server_support": "Your server has native support",
"under_active_development": "Under active development.", "under_active_development": "Under active development.",
"unrealiable_e2e": "Unreliable in encrypted rooms", "unrealiable_e2e": "Unreliable in encrypted rooms",
"video_rooms": "Video rooms", "video_rooms": "Video rooms",

View File

@ -407,7 +407,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
controller: new SlidingSyncController(), controller: new SlidingSyncController(),
}, },
"feature_sliding_sync_proxy_url": { "feature_sliding_sync_proxy_url": {
// This is not a distinct feature, it is a setting for feature_sliding_sync above // This is not a distinct feature, it is a legacy setting for feature_sliding_sync above
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: "", default: "",
}, },

View File

@ -1,5 +1,6 @@
/* /*
Copyright 2022 The Matrix.org Foundation C.I.C. Copyright 2022 The Matrix.org Foundation C.I.C.
Copyright 2024 Ed Geraghty <ed@geraghty.family>
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -16,18 +17,11 @@ limitations under the License.
import SettingController from "./SettingController"; import SettingController from "./SettingController";
import PlatformPeg from "../../PlatformPeg"; import PlatformPeg from "../../PlatformPeg";
import { SettingLevel } from "../SettingLevel";
import { SlidingSyncOptionsDialog } from "../../components/views/dialogs/SlidingSyncOptionsDialog";
import Modal from "../../Modal";
import SettingsStore from "../SettingsStore"; import SettingsStore from "../SettingsStore";
import { _t } from "../../languageHandler"; import { _t } from "../../languageHandler";
export default class SlidingSyncController extends SettingController { export default class SlidingSyncController extends SettingController {
public async beforeChange(level: SettingLevel, roomId: string, newValue: any): Promise<boolean> { public static serverSupportsSlidingSync: boolean;
const { finished } = Modal.createDialog(SlidingSyncOptionsDialog);
const [value] = await finished;
return newValue === value; // abort the operation if we're already in the state the user chose via modal
}
public async onChange(): Promise<void> { public async onChange(): Promise<void> {
PlatformPeg.get()?.reload(); PlatformPeg.get()?.reload();
@ -38,6 +32,9 @@ export default class SlidingSyncController extends SettingController {
if (SettingsStore.getValue("feature_sliding_sync")) { if (SettingsStore.getValue("feature_sliding_sync")) {
return _t("labs|sliding_sync_disabled_notice"); return _t("labs|sliding_sync_disabled_notice");
} }
if (!SlidingSyncController.serverSupportsSlidingSync) {
return _t("labs|sliding_sync_server_no_support");
}
return false; return false;
} }

View File

@ -20,6 +20,8 @@ import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import { SlidingSyncManager } from "../src/SlidingSyncManager"; import { SlidingSyncManager } from "../src/SlidingSyncManager";
import { stubClient } from "./test-utils"; import { stubClient } from "./test-utils";
import SlidingSyncController from "../src/settings/controllers/SlidingSyncController";
import SettingsStore from "../src/settings/SettingsStore";
jest.mock("matrix-js-sdk/src/sliding-sync"); jest.mock("matrix-js-sdk/src/sliding-sync");
const MockSlidingSync = <jest.Mock<SlidingSync>>(<unknown>SlidingSync); const MockSlidingSync = <jest.Mock<SlidingSync>>(<unknown>SlidingSync);
@ -231,4 +233,53 @@ describe("SlidingSyncManager", () => {
); );
}); });
}); });
describe("checkSupport", () => {
beforeEach(() => {
SlidingSyncController.serverSupportsSlidingSync = false;
jest.spyOn(manager, "getProxyFromWellKnown").mockResolvedValue("proxy");
});
it("shorts out if the server has 'native' sliding sync support", async () => {
jest.spyOn(manager, "nativeSlidingSyncSupport").mockResolvedValue(true);
expect(SlidingSyncController.serverSupportsSlidingSync).toBeFalsy();
await manager.checkSupport(client);
expect(manager.getProxyFromWellKnown).not.toHaveBeenCalled(); // We return earlier
expect(SlidingSyncController.serverSupportsSlidingSync).toBeTruthy();
});
it("tries to find a sliding sync proxy url from the client well-known if there's no 'native' support", async () => {
jest.spyOn(manager, "nativeSlidingSyncSupport").mockResolvedValue(false);
expect(SlidingSyncController.serverSupportsSlidingSync).toBeFalsy();
await manager.checkSupport(client);
expect(manager.getProxyFromWellKnown).toHaveBeenCalled();
expect(SlidingSyncController.serverSupportsSlidingSync).toBeTruthy();
});
});
describe("setup", () => {
beforeEach(() => {
jest.spyOn(manager, "configure");
jest.spyOn(manager, "startSpidering");
});
it("uses the baseUrl as a proxy if no proxy is set in the client well-known and the server has no native support", async () => {
await manager.setup(client);
expect(manager.configure).toHaveBeenCalled();
expect(manager.configure).toHaveBeenCalledWith(client, client.baseUrl);
expect(manager.startSpidering).toHaveBeenCalled();
});
it("uses the proxy declared in the client well-known", async () => {
jest.spyOn(manager, "getProxyFromWellKnown").mockResolvedValue("proxy");
await manager.setup(client);
expect(manager.configure).toHaveBeenCalled();
expect(manager.configure).toHaveBeenCalledWith(client, "proxy");
expect(manager.startSpidering).toHaveBeenCalled();
});
it("uses the legacy `feature_sliding_sync_proxy_url` if it was set", async () => {
jest.spyOn(manager, "getProxyFromWellKnown").mockResolvedValue("proxy");
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
if (name === "feature_sliding_sync_proxy_url") return "legacy-proxy";
});
await manager.setup(client);
expect(manager.configure).toHaveBeenCalled();
expect(manager.configure).toHaveBeenCalledWith(client, "legacy-proxy");
expect(manager.startSpidering).toHaveBeenCalled();
});
});
}); });