Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.
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
2 changes: 2 additions & 0 deletions src/integrations/IntegrationManagerInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import url from 'url';

export const KIND_ACCOUNT = "account";
export const KIND_CONFIG = "config";
export const KIND_HOMESERVER = "homeserver";

export class IntegrationManagerInstance {
apiUrl: string;
uiUrl: string;
kind: string;
id: string; // only applicable in some cases

constructor(kind: string, apiUrl: string, uiUrl: string) {
this.kind = kind;
Expand Down
78 changes: 75 additions & 3 deletions src/integrations/IntegrationManagers.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,19 @@ limitations under the License.
import SdkConfig from '../SdkConfig';
import sdk from "../index";
import Modal from '../Modal';
import {IntegrationManagerInstance, KIND_ACCOUNT, KIND_CONFIG} from "./IntegrationManagerInstance";
import {IntegrationManagerInstance, KIND_ACCOUNT, KIND_CONFIG, KIND_HOMESERVER} from "./IntegrationManagerInstance";
import type {MatrixClient, MatrixEvent} from "matrix-js-sdk";
import WidgetUtils from "../utils/WidgetUtils";
import MatrixClientPeg from "../MatrixClientPeg";
import {AutoDiscovery} from "matrix-js-sdk";

const HS_MANAGERS_REFRESH_INTERVAL = 8 * 60 * 60 * 1000; // 8 hours
const KIND_PREFERENCE = [
// Ordered: first is most preferred, last is least preferred.
KIND_ACCOUNT,
KIND_HOMESERVER,
KIND_CONFIG,
];

export class IntegrationManagers {
static _instance;
Expand All @@ -34,6 +43,8 @@ export class IntegrationManagers {

_managers: IntegrationManagerInstance[] = [];
_client: MatrixClient;
_wellknownRefreshTimerId: number = null;
_primaryManager: IntegrationManagerInstance;

constructor() {
this._compileManagers();
Expand All @@ -44,16 +55,19 @@ export class IntegrationManagers {
this._client = MatrixClientPeg.get();
this._client.on("accountData", this._onAccountData.bind(this));
this._compileManagers();
setInterval(() => this._setupHomeserverManagers(), HS_MANAGERS_REFRESH_INTERVAL);
}

stopWatching(): void {
if (!this._client) return;
this._client.removeListener("accountData", this._onAccountData.bind(this));
if (this._wellknownRefreshTimerId !== null) clearInterval(this._wellknownRefreshTimerId);
}

_compileManagers() {
this._managers = [];
this._setupConfiguredManager();
this._setupHomeserverManagers();
this._setupAccountManagers();
}

Expand All @@ -63,6 +77,42 @@ export class IntegrationManagers {

if (apiUrl && uiUrl) {
this._managers.push(new IntegrationManagerInstance(KIND_CONFIG, apiUrl, uiUrl));
this._primaryManager = null; // reset primary
}
}

async _setupHomeserverManagers() {
try {
console.log("Updating homeserver-configured integration managers...");
const homeserverDomain = MatrixClientPeg.getHomeserverName();
const discoveryResponse = await AutoDiscovery.getRawClientConfig(homeserverDomain);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will do it's own .well-known request, right?
Is there no way here to re-use the response of the .well-known response request to determine the homeserver?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does do a .well-known request, and the existing response from the homeserver isn't really able to be reused. The .well-known for the homeserver is done so early in the process that we don't have a clean/reliable way to get it all the way over here, and we need to update this information periodically.

if (discoveryResponse && discoveryResponse['m.integrations']) {
let managers = discoveryResponse['m.integrations']['managers'];
if (!Array.isArray(managers)) managers = []; // make it an array so we can wipe the HS managers

console.log(`Homeserver has ${managers.length} integration managers`);

// Clear out any known managers for the homeserver
// TODO: Log out of the scalar clients
this._managers = this._managers.filter(m => m.kind !== KIND_HOMESERVER);

// Now add all the managers the homeserver wants us to have
for (const hsManager of managers) {
if (!hsManager["api_url"]) continue;
this._managers.push(new IntegrationManagerInstance(
KIND_HOMESERVER,
hsManager["api_url"],
hsManager["ui_url"], // optional
));
}

this._primaryManager = null; // reset primary
} else {
console.log("Homeserver has no integration managers");
}
} catch (e) {
console.error(e);
// Errors during discovery are non-fatal
}
}

Expand All @@ -77,8 +127,11 @@ export class IntegrationManagers {
const apiUrl = data['api_url'];
if (!apiUrl || !uiUrl) return;

this._managers.push(new IntegrationManagerInstance(KIND_ACCOUNT, apiUrl, uiUrl));
const manager = new IntegrationManagerInstance(KIND_ACCOUNT, apiUrl, uiUrl);
manager.id = w['id'] || w['state_key'] || '';
this._managers.push(manager);
});
this._primaryManager = null; // reset primary
}

_onAccountData(ev: MatrixEvent): void {
Expand All @@ -91,9 +144,28 @@ export class IntegrationManagers {
return this._managers.length > 0;
}

getOrderedManagers(): IntegrationManagerInstance[] {
const ordered = [];
for (const kind of KIND_PREFERENCE) {
const managers = this._managers.filter(m => m.kind === kind);
if (!managers || !managers.length) continue;

if (kind === KIND_ACCOUNT) {
// Order by state_keys (IDs)
managers.sort((a, b) => a.id.localeCompare(b.id));
}

ordered.push(...managers);
}
return ordered;
}

getPrimaryManager(): IntegrationManagerInstance {
if (this.hasManager()) {
return this._managers[this._managers.length - 1];
if (this._primaryManager) return this._primaryManager;

this._primaryManager = this.getOrderedManagers()[0];
return this._primaryManager;
} else {
return null;
}
Expand Down