Add configurable default homeserver
This commit is contained in:
parent
34d0483c99
commit
39d28a0488
8 changed files with 71 additions and 88 deletions
3
.env
3
.env
|
@ -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
|
||||||
|
|
||||||
|
|
63
src/App.jsx
63
src/App.jsx
|
@ -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,50 +86,20 @@ 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("/")) {
|
||||||
roomId = roomId.substr(1, roomId.length);
|
roomId = roomId.substr(1, roomId.length);
|
||||||
}
|
|
||||||
|
|
||||||
if (!roomId.startsWith("#") && !roomId.startsWith("!")) {
|
|
||||||
let loginHomeserverUrl = homeserverUrl.trim();
|
|
||||||
|
|
||||||
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}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect().catch(setError);
|
if (!roomId.startsWith("#") && !roomId.startsWith("!")) {
|
||||||
}, [history, pathname]);
|
roomId = `#${roomId}:${defaultHomeserverHost}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (error) {
|
history.replace(`/room/${roomId}`);
|
||||||
return <ErrorView error={error} />;
|
}, [pathname, history]);
|
||||||
}
|
|
||||||
|
|
||||||
return <LoadingView />;
|
return <LoadingView />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}`;
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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"
|
||||||
>
|
>
|
||||||
|
|
|
@ -14,22 +14,26 @@ 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 }) => {
|
||||||
plugins: [svgrPlugin()],
|
const env = loadEnv(mode, process.cwd());
|
||||||
server: {
|
|
||||||
proxy: {
|
return {
|
||||||
"/_matrix": "http://localhost:8008",
|
plugins: [svgrPlugin()],
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
"/_matrix": env.VITE_DEFAULT_HOMESERVER || "http://localhost:8008",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
resolve: {
|
||||||
resolve: {
|
alias: {
|
||||||
alias: {
|
"$(res)": path.resolve(__dirname, "node_modules/matrix-react-sdk/res"),
|
||||||
"$(res)": path.resolve(__dirname, "node_modules/matrix-react-sdk/res"),
|
},
|
||||||
|
dedupe: ["react", "react-dom", "matrix-js-sdk"],
|
||||||
},
|
},
|
||||||
dedupe: ["react", "react-dom", "matrix-js-sdk"],
|
};
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue