Add configurable default homeserver

This commit is contained in:
Robert Long 2021-12-17 16:30:10 -08:00
parent 34d0483c99
commit 39d28a0488
8 changed files with 71 additions and 88 deletions

3
.env
View File

@ -4,6 +4,9 @@
# https://vitejs.dev/guide/env-and-mode.html#env-files # https://vitejs.dev/guide/env-and-mode.html#env-files
#### ####
# Used for determining the homeserver to use for short urls etc.
# VITE_DEFAULT_HOMESERVER=http://localhost:8008
# The room id for the space to use for listing public group call rooms # The room id for the space to use for listing public group call rooms
# VITE_PUBLIC_SPACE_ROOM_ID=!hjdfshkdskjdsk:myhomeserver.com # VITE_PUBLIC_SPACE_ROOM_ID=!hjdfshkdskjdsk:myhomeserver.com

View File

@ -28,18 +28,17 @@ import { Home } from "./Home";
import { LoginPage } from "./LoginPage"; import { LoginPage } from "./LoginPage";
import { RegisterPage } from "./RegisterPage"; import { RegisterPage } from "./RegisterPage";
import { Room } from "./Room"; import { Room } from "./Room";
import { ClientProvider } from "./ConferenceCallManagerHooks"; import {
ClientProvider,
defaultHomeserverHost,
} from "./ConferenceCallManagerHooks";
import { useFocusVisible } from "@react-aria/interactions"; import { useFocusVisible } from "@react-aria/interactions";
import styles from "./App.module.css"; import styles from "./App.module.css";
import { ErrorView, LoadingView } from "./FullScreenView"; import { LoadingView } from "./FullScreenView";
const SentryRoute = Sentry.withSentryRouting(Route); const SentryRoute = Sentry.withSentryRouting(Route);
const { protocol, host } = window.location; export default function App({ history }) {
// Assume homeserver is hosted on same domain (proxied in development by vite)
const homeserverUrl = `${protocol}//${host}`;
export default function App() {
const { isFocusVisible } = useFocusVisible(); const { isFocusVisible } = useFocusVisible();
useEffect(() => { useEffect(() => {
@ -58,8 +57,8 @@ export default function App() {
}, [isFocusVisible]); }, [isFocusVisible]);
return ( return (
<Router> <Router history={history}>
<ClientProvider homeserverUrl={homeserverUrl}> <ClientProvider>
<OverlayProvider> <OverlayProvider>
<Switch> <Switch>
<SentryRoute exact path="/"> <SentryRoute exact path="/">
@ -87,10 +86,8 @@ export default function App() {
function RoomRedirect() { function RoomRedirect() {
const { pathname } = useLocation(); const { pathname } = useLocation();
const history = useHistory(); const history = useHistory();
const [error, setError] = useState();
useEffect(() => { useEffect(() => {
async function redirect() {
let roomId = pathname; let roomId = pathname;
if (pathname.startsWith("/")) { if (pathname.startsWith("/")) {
@ -98,39 +95,11 @@ function RoomRedirect() {
} }
if (!roomId.startsWith("#") && !roomId.startsWith("!")) { if (!roomId.startsWith("#") && !roomId.startsWith("!")) {
let loginHomeserverUrl = homeserverUrl.trim(); roomId = `#${roomId}:${defaultHomeserverHost}`;
if (!loginHomeserverUrl.includes("://")) {
loginHomeserverUrl = "https://" + loginHomeserverUrl;
}
try {
const wellKnownUrl = new URL(
"/.well-known/matrix/client",
window.location
);
const response = await fetch(wellKnownUrl);
const config = await response.json();
if (config["m.homeserver"]) {
loginHomeserverUrl = config["m.homeserver"];
}
} catch (error) {}
const { host } = new URL(loginHomeserverUrl);
roomId = `#${roomId}:${host}`;
} }
history.replace(`/room/${roomId}`); history.replace(`/room/${roomId}`);
} }, [pathname, history]);
redirect().catch(setError);
}, [history, pathname]);
if (error) {
return <ErrorView error={error} />;
}
return <LoadingView />; return <LoadingView />;
} }

View File

@ -29,6 +29,12 @@ import {
} from "matrix-js-sdk/src/browser-index"; } from "matrix-js-sdk/src/browser-index";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
export const defaultHomeserver =
import.meta.env.VITE_DEFAULT_HOMESERVER ||
`${window.location.protocol}//${window.location.host}`;
export const defaultHomeserverHost = new URL(defaultHomeserver).host;
const ClientContext = createContext(); const ClientContext = createContext();
function waitForSync(client) { function waitForSync(client) {
@ -100,18 +106,10 @@ export async function fetchGroupCall(
}); });
} }
export function ClientProvider({ homeserverUrl, children }) { export function ClientProvider({ children }) {
const history = useHistory(); const history = useHistory();
const [ const [
{ { loading, isAuthenticated, isPasswordlessUser, isGuest, client, userName },
loading,
isAuthenticated,
isPasswordlessUser,
isGuest,
client,
userName,
displayName,
},
setState, setState,
] = useState({ ] = useState({
loading: true, loading: true,
@ -120,7 +118,6 @@ export function ClientProvider({ homeserverUrl, children }) {
isGuest: false, isGuest: false,
client: undefined, client: undefined,
userName: null, userName: null,
displayName: null,
}); });
useEffect(() => { useEffect(() => {
@ -140,7 +137,7 @@ export function ClientProvider({ homeserverUrl, children }) {
const client = await initClient( const client = await initClient(
{ {
baseUrl: homeserverUrl, baseUrl: defaultHomeserver,
accessToken: access_token, accessToken: access_token,
userId: user_id, userId: user_id,
deviceId: device_id, deviceId: device_id,
@ -255,14 +252,14 @@ export function ClientProvider({ homeserverUrl, children }) {
const registerGuest = useCallback(async () => { const registerGuest = useCallback(async () => {
try { try {
const registrationClient = matrix.createClient(homeserverUrl); const registrationClient = matrix.createClient(defaultHomeserver);
const { user_id, device_id, access_token } = const { user_id, device_id, access_token } =
await registrationClient.registerGuest({}); await registrationClient.registerGuest({});
const client = await initClient( const client = await initClient(
{ {
baseUrl: homeserverUrl, baseUrl: defaultHomeserver,
accessToken: access_token, accessToken: access_token,
userId: user_id, userId: user_id,
deviceId: device_id, deviceId: device_id,
@ -303,7 +300,7 @@ export function ClientProvider({ homeserverUrl, children }) {
const register = useCallback(async (username, password, passwordlessUser) => { const register = useCallback(async (username, password, passwordlessUser) => {
try { try {
const registrationClient = matrix.createClient(homeserverUrl); const registrationClient = matrix.createClient(defaultHomeserver);
const { user_id, device_id, access_token } = const { user_id, device_id, access_token } =
await registrationClient.register(username, password, null, { await registrationClient.register(username, password, null, {
@ -311,7 +308,7 @@ export function ClientProvider({ homeserverUrl, children }) {
}); });
const client = await initClient({ const client = await initClient({
baseUrl: homeserverUrl, baseUrl: defaultHomeserver,
accessToken: access_token, accessToken: access_token,
userId: user_id, userId: user_id,
deviceId: device_id, deviceId: device_id,
@ -617,7 +614,7 @@ export function getRoomUrl(roomId) {
if (roomId.startsWith("#")) { if (roomId.startsWith("#")) {
const [localPart, host] = roomId.replace("#", "").split(":"); const [localPart, host] = roomId.replace("#", "").split(":");
if (host !== window.location.host) { if (host !== defaultHomeserverHost) {
return `${window.location.host}/room/${roomId}`; return `${window.location.host}/room/${roomId}`;
} else { } else {
return `${window.location.host}/${localPart}`; return `${window.location.host}/${localPart}`;

View File

@ -62,7 +62,7 @@ export function Home() {
async function onCreateRoom() { async function onCreateRoom() {
let _client = client; let _client = client;
if (!_client) { if (!_client || isGuest) {
_client = await register(userName, randomString(16), true); _client = await register(userName, randomString(16), true);
} }
@ -88,7 +88,7 @@ export function Home() {
setCreatingRoom(false); setCreatingRoom(false);
}); });
}, },
[client, history, register] [client, history, register, isGuest]
); );
const onJoinRoom = useCallback( const onJoinRoom = useCallback(

View File

@ -14,19 +14,21 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { useCallback, useRef, useState } from "react"; import React, { useCallback, useRef, useState, useMemo } from "react";
import { useHistory, useLocation, Link } from "react-router-dom"; import { useHistory, useLocation, Link } from "react-router-dom";
import { ReactComponent as Logo } from "./icons/LogoLarge.svg"; import { ReactComponent as Logo } from "./icons/LogoLarge.svg";
import { FieldRow, InputField, ErrorMessage } from "./Input"; import { FieldRow, InputField, ErrorMessage } from "./Input";
import { Button } from "./button"; import { Button } from "./button";
import { useClient } from "./ConferenceCallManagerHooks"; import {
useClient,
defaultHomeserver,
defaultHomeserverHost,
} from "./ConferenceCallManagerHooks";
import styles from "./LoginPage.module.css"; import styles from "./LoginPage.module.css";
export function LoginPage() { export function LoginPage() {
const { login } = useClient(); const { login } = useClient();
const [homeserver, setHomeServer] = useState( const [homeserver, setHomeServer] = useState(defaultHomeserver);
`${window.location.protocol}//${window.location.host}`
);
const usernameRef = useRef(); const usernameRef = useRef();
const passwordRef = useRef(); const passwordRef = useRef();
const history = useHistory(); const history = useHistory();
@ -57,6 +59,14 @@ export function LoginPage() {
[login, location, history, homeserver] [login, location, history, homeserver]
); );
const homeserverHost = useMemo(() => {
try {
return new URL(homeserver).host;
} catch (_error) {
return defaultHomeserverHost;
}
}, [homeserver]);
return ( return (
<> <>
<div className={styles.container}> <div className={styles.container}>
@ -76,7 +86,7 @@ export function LoginPage() {
autoCorrect="off" autoCorrect="off"
autoCapitalize="none" autoCapitalize="none"
prefix="@" prefix="@"
suffix={`:${window.location.host}`} suffix={`:${homeserverHost}`}
/> />
</FieldRow> </FieldRow>
<FieldRow> <FieldRow>

View File

@ -18,7 +18,7 @@ import React, { useCallback, useEffect, useRef, useState } from "react";
import { useHistory, useLocation, Link } from "react-router-dom"; import { useHistory, useLocation, Link } from "react-router-dom";
import { FieldRow, InputField, ErrorMessage } from "./Input"; import { FieldRow, InputField, ErrorMessage } from "./Input";
import { Button } from "./button"; import { Button } from "./button";
import { useClient } from "./ConferenceCallManagerHooks"; import { useClient, defaultHomeserverHost } from "./ConferenceCallManagerHooks";
import styles from "./LoginPage.module.css"; import styles from "./LoginPage.module.css";
import { ReactComponent as Logo } from "./icons/LogoLarge.svg"; import { ReactComponent as Logo } from "./icons/LogoLarge.svg";
import { LoadingView } from "./FullScreenView"; import { LoadingView } from "./FullScreenView";
@ -126,7 +126,7 @@ export function RegisterPage() {
autoCorrect="off" autoCorrect="off"
autoCapitalize="none" autoCapitalize="none"
prefix="@" prefix="@"
suffix={`:${window.location.host}`} suffix={`:${defaultHomeserverHost}`}
value={ value={
isAuthenticated && isPasswordlessUser isAuthenticated && isPasswordlessUser
? client.getUserIdLocalpart() ? client.getUserIdLocalpart()

View File

@ -37,6 +37,7 @@ import { useGroupCall } from "matrix-react-sdk/src/hooks/useGroupCall";
import { useCallFeed } from "matrix-react-sdk/src/hooks/useCallFeed"; import { useCallFeed } from "matrix-react-sdk/src/hooks/useCallFeed";
import { useMediaStream } from "matrix-react-sdk/src/hooks/useMediaStream"; import { useMediaStream } from "matrix-react-sdk/src/hooks/useMediaStream";
import { import {
getRoomUrl,
useClient, useClient,
useLoadGroupCall, useLoadGroupCall,
useProfile, useProfile,
@ -294,7 +295,6 @@ function RoomSetupView({
}) { }) {
const { stream } = useCallFeed(localCallFeed); const { stream } = useCallFeed(localCallFeed);
const videoRef = useMediaStream(stream, true); const videoRef = useMediaStream(stream, true);
const location = useLocation();
useEffect(() => { useEffect(() => {
onInitLocalCallFeed(); onInitLocalCallFeed();
@ -354,7 +354,7 @@ function RoomSetupView({
</div> </div>
<p>Or</p> <p>Or</p>
<CopyButton <CopyButton
value={window.location.href} value={getRoomUrl(roomId)}
className={styles.copyButton} className={styles.copyButton}
copiedMessage="Call link copied" copiedMessage="Call link copied"
> >

View File

@ -14,16 +14,19 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { defineConfig } from "vite"; import { defineConfig, loadEnv } from "vite";
import svgrPlugin from "vite-plugin-svgr"; import svgrPlugin from "vite-plugin-svgr";
import path from "path"; import path from "path";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd());
return {
plugins: [svgrPlugin()], plugins: [svgrPlugin()],
server: { server: {
proxy: { proxy: {
"/_matrix": "http://localhost:8008", "/_matrix": env.VITE_DEFAULT_HOMESERVER || "http://localhost:8008",
}, },
}, },
resolve: { resolve: {
@ -32,4 +35,5 @@ export default defineConfig({
}, },
dedupe: ["react", "react-dom", "matrix-js-sdk"], dedupe: ["react", "react-dom", "matrix-js-sdk"],
}, },
};
}); });