Merge branch 'fkwp/delegation_of_delayed_events' into fkwp/feature_relax_homeserver_offline
This commit is contained in:
@@ -18,3 +18,7 @@ keys:
|
|||||||
devkey: secret
|
devkey: secret
|
||||||
room:
|
room:
|
||||||
auto_create: false
|
auto_create: false
|
||||||
|
webhook:
|
||||||
|
api_key: devkey
|
||||||
|
urls:
|
||||||
|
- https://matrix-rtc.othersite.m.localhost/livekit/jwt/sfu_webhook
|
||||||
|
|||||||
@@ -18,3 +18,7 @@ keys:
|
|||||||
devkey: secret
|
devkey: secret
|
||||||
room:
|
room:
|
||||||
auto_create: false
|
auto_create: false
|
||||||
|
webhook:
|
||||||
|
api_key: devkey
|
||||||
|
urls:
|
||||||
|
- https://matrix-rtc.m.localhost/livekit/jwt/sfu_webhook
|
||||||
|
|||||||
+183
-175
@@ -1,175 +1,183 @@
|
|||||||
networks:
|
networks:
|
||||||
ecbackend:
|
ecbackend:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
auth-service:
|
auth-service:
|
||||||
image: ghcr.io/element-hq/lk-jwt-service:pr_171
|
image: ghcr.io/element-hq/lk-jwt-service:pr_171
|
||||||
pull_policy: always
|
pull_policy: always
|
||||||
hostname: auth-server
|
hostname: auth-server
|
||||||
environment:
|
environment:
|
||||||
- LIVEKIT_JWT_PORT=6080
|
- LIVEKIT_JWT_PORT=6080
|
||||||
- LIVEKIT_URL=wss://matrix-rtc.m.localhost/livekit/sfu
|
- LIVEKIT_URL=wss://matrix-rtc.m.localhost/livekit/sfu
|
||||||
- LIVEKIT_KEY=devkey
|
- LIVEKIT_KEY=devkey
|
||||||
- LIVEKIT_SECRET=secret
|
- LIVEKIT_SECRET=secret
|
||||||
# If the configured homeserver runs on localhost, it'll probably be using
|
# If the configured homeserver runs on localhost, it'll probably be using
|
||||||
# a self-signed certificate
|
# a self-signed certificate
|
||||||
- LIVEKIT_INSECURE_SKIP_VERIFY_TLS=YES_I_KNOW_WHAT_I_AM_DOING
|
- LIVEKIT_INSECURE_SKIP_VERIFY_TLS=YES_I_KNOW_WHAT_I_AM_DOING
|
||||||
- LIVEKIT_FULL_ACCESS_HOMESERVERS=*
|
- LIVEKIT_FULL_ACCESS_HOMESERVERS=*
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
ports:
|
ports:
|
||||||
# HOST_PORT:CONTAINER_PORT
|
# HOST_PORT:CONTAINER_PORT
|
||||||
- 6080:6080
|
- 6080:6080
|
||||||
networks:
|
networks:
|
||||||
- ecbackend
|
- ecbackend
|
||||||
|
|
||||||
auth-service-1:
|
auth-service-1:
|
||||||
image: ghcr.io/element-hq/lk-jwt-service:pr_171
|
image: ghcr.io/element-hq/lk-jwt-service:pr_171
|
||||||
pull_policy: always
|
pull_policy: always
|
||||||
hostname: auth-server-1
|
hostname: auth-server-1
|
||||||
environment:
|
environment:
|
||||||
- LIVEKIT_JWT_PORT=16080
|
- LIVEKIT_JWT_PORT=16080
|
||||||
- LIVEKIT_URL=wss://matrix-rtc.othersite.m.localhost/livekit/sfu
|
- LIVEKIT_URL=wss://matrix-rtc.othersite.m.localhost/livekit/sfu
|
||||||
- LIVEKIT_KEY=devkey
|
- LIVEKIT_KEY=devkey
|
||||||
- LIVEKIT_SECRET=secret
|
- LIVEKIT_SECRET=secret
|
||||||
# If the configured homeserver runs on localhost, it'll probably be using
|
# If the configured homeserver runs on localhost, it'll probably be using
|
||||||
# a self-signed certificate
|
# a self-signed certificate
|
||||||
- LIVEKIT_INSECURE_SKIP_VERIFY_TLS=YES_I_KNOW_WHAT_I_AM_DOING
|
- LIVEKIT_INSECURE_SKIP_VERIFY_TLS=YES_I_KNOW_WHAT_I_AM_DOING
|
||||||
- LIVEKIT_FULL_ACCESS_HOMESERVERS=*
|
- LIVEKIT_FULL_ACCESS_HOMESERVERS=*
|
||||||
deploy:
|
deploy:
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
ports:
|
ports:
|
||||||
# HOST_PORT:CONTAINER_PORT
|
# HOST_PORT:CONTAINER_PORT
|
||||||
- 16080:16080
|
- 16080:16080
|
||||||
networks:
|
networks:
|
||||||
- ecbackend
|
- ecbackend
|
||||||
|
|
||||||
livekit:
|
livekit:
|
||||||
image: livekit/livekit-server:v1.10.1
|
image: livekit/livekit-server:v1.10.1
|
||||||
pull_policy: always
|
pull_policy: always
|
||||||
hostname: livekit-sfu
|
hostname: livekit-sfu
|
||||||
command: --dev --config /etc/livekit.yaml
|
command: --dev --config /etc/livekit.yaml
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# The SFU seems to work far more reliably when we let it share the host
|
# The SFU seems to work far more reliably when we let it share the host
|
||||||
# network rather than opening specific ports (but why?? we're not missing
|
# network rather than opening specific ports (but why?? we're not missing
|
||||||
# any…)
|
# any…)
|
||||||
ports:
|
ports:
|
||||||
# HOST_PORT:CONTAINER_PORT
|
# HOST_PORT:CONTAINER_PORT
|
||||||
- 7880:7880/tcp
|
- 7880:7880/tcp
|
||||||
- 7881:7881/tcp
|
- 7881:7881/tcp
|
||||||
- 7882:7882/tcp
|
- 7882:7882/tcp
|
||||||
- 50100-50200:50100-50200/udp
|
- 50100-50200:50100-50200/udp
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/dev_livekit.yaml:/etc/livekit.yaml:Z
|
- ./backend/dev_tls_m.localhost.crt:/local_cert.pem:Z
|
||||||
networks:
|
- ./backend/dev_livekit.yaml:/etc/livekit.yaml:Z
|
||||||
- ecbackend
|
environment:
|
||||||
|
- SSL_CERT_FILE=/local_cert.pem
|
||||||
livekit-1:
|
networks:
|
||||||
image: livekit/livekit-server:v1.10.1
|
- ecbackend
|
||||||
pull_policy: always
|
|
||||||
hostname: livekit-sfu-1
|
livekit-1:
|
||||||
command: --dev --config /etc/livekit.yaml
|
image: livekit/livekit-server:v1.10.1
|
||||||
restart: unless-stopped
|
pull_policy: always
|
||||||
# The SFU seems to work far more reliably when we let it share the host
|
hostname: livekit-sfu-1
|
||||||
# network rather than opening specific ports (but why?? we're not missing
|
command: --dev --config /etc/livekit.yaml
|
||||||
# any…)
|
restart: unless-stopped
|
||||||
ports:
|
# The SFU seems to work far more reliably when we let it share the host
|
||||||
# HOST_PORT:CONTAINER_PORT
|
# network rather than opening specific ports (but why?? we're not missing
|
||||||
- 17880:17880/tcp
|
# any…)
|
||||||
- 17881:17881/tcp
|
ports:
|
||||||
- 17882:17882/tcp
|
# HOST_PORT:CONTAINER_PORT
|
||||||
- 50300-50400:50300-50400/udp
|
- 17880:17880/tcp
|
||||||
volumes:
|
- 17881:17881/tcp
|
||||||
- ./backend/dev_livekit-othersite.yaml:/etc/livekit.yaml:Z
|
- 17882:17882/tcp
|
||||||
networks:
|
- 50300-50400:50300-50400/udp
|
||||||
- ecbackend
|
volumes:
|
||||||
|
- ./backend/dev_tls_m.localhost.crt:/local_cert.pem:Z
|
||||||
synapse:
|
- ./backend/dev_livekit-othersite.yaml:/etc/livekit.yaml:Z
|
||||||
hostname: homeserver
|
environment:
|
||||||
image: ghcr.io/element-hq/synapse:latest
|
- SSL_CERT_FILE=/local_cert.pem
|
||||||
pull_policy: always
|
networks:
|
||||||
environment:
|
- ecbackend
|
||||||
- SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml
|
|
||||||
# Needed for rootless podman-compose such that the uid/gid mapping does
|
synapse:
|
||||||
# fit local user uid. If the container runs as root (uid 0) it is fine as
|
hostname: homeserver
|
||||||
# it actually maps to your non-root user on the host (e.g. 1000).
|
image: ghcr.io/element-hq/synapse:latest
|
||||||
# Otherwise uid mapping will not match your non-root user.
|
pull_policy: always
|
||||||
- UID=0
|
environment:
|
||||||
- GID=0
|
- SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml
|
||||||
volumes:
|
# Needed for rootless podman-compose such that the uid/gid mapping does
|
||||||
- ./backend/synapse_tmp:/data:Z
|
# fit local user uid. If the container runs as root (uid 0) it is fine as
|
||||||
- ./backend/dev_homeserver.yaml:/data/cfg/homeserver.yaml:Z
|
# it actually maps to your non-root user on the host (e.g. 1000).
|
||||||
networks:
|
# Otherwise uid mapping will not match your non-root user.
|
||||||
- ecbackend
|
- UID=0
|
||||||
|
- GID=0
|
||||||
synapse-1:
|
volumes:
|
||||||
hostname: homeserver-1
|
- ./backend/synapse_tmp:/data:Z
|
||||||
image: ghcr.io/element-hq/synapse:latest
|
- ./backend/dev_homeserver.yaml:/data/cfg/homeserver.yaml:Z
|
||||||
pull_policy: always
|
networks:
|
||||||
environment:
|
- ecbackend
|
||||||
- SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml
|
|
||||||
# Needed for rootless podman-compose such that the uid/gid mapping does
|
synapse-1:
|
||||||
# fit local user uid. If the container runs as root (uid 0) it is fine as
|
hostname: homeserver-1
|
||||||
# it actually maps to your non-root user on the host (e.g. 1000).
|
image: ghcr.io/element-hq/synapse:latest
|
||||||
# Otherwise uid mapping will not match your non-root user.
|
pull_policy: always
|
||||||
- UID=0
|
environment:
|
||||||
- GID=0
|
- SYNAPSE_CONFIG_PATH=/data/cfg/homeserver.yaml
|
||||||
volumes:
|
# Needed for rootless podman-compose such that the uid/gid mapping does
|
||||||
- ./backend/synapse_tmp_othersite:/data:Z
|
# fit local user uid. If the container runs as root (uid 0) it is fine as
|
||||||
- ./backend/dev_homeserver-othersite.yaml:/data/cfg/homeserver.yaml:Z
|
# it actually maps to your non-root user on the host (e.g. 1000).
|
||||||
networks:
|
# Otherwise uid mapping will not match your non-root user.
|
||||||
- ecbackend
|
- UID=0
|
||||||
|
- GID=0
|
||||||
element-web:
|
volumes:
|
||||||
image: ghcr.io/element-hq/element-web:develop
|
- ./backend/synapse_tmp_othersite:/data:Z
|
||||||
pull_policy: always
|
- ./backend/dev_homeserver-othersite.yaml:/data/cfg/homeserver.yaml:Z
|
||||||
volumes:
|
networks:
|
||||||
- ./backend/ew.test.config.json:/app/config.json:Z
|
- ecbackend
|
||||||
environment:
|
|
||||||
ELEMENT_WEB_PORT: 8081
|
element-web:
|
||||||
ports:
|
image: ghcr.io/element-hq/element-web:develop
|
||||||
- "8081:8081"
|
pull_policy: always
|
||||||
networks:
|
volumes:
|
||||||
- ecbackend
|
- ./backend/ew.test.config.json:/app/config.json:Z
|
||||||
|
environment:
|
||||||
element-web-1:
|
ELEMENT_WEB_PORT: 8081
|
||||||
image: ghcr.io/element-hq/element-web:develop
|
ports:
|
||||||
pull_policy: always
|
- "8081:8081"
|
||||||
volumes:
|
networks:
|
||||||
- ./backend/ew.test.othersite.config.json:/app/config.json:Z
|
- ecbackend
|
||||||
environment:
|
|
||||||
ELEMENT_WEB_PORT: 18081
|
element-web-1:
|
||||||
ports:
|
image: ghcr.io/element-hq/element-web:develop
|
||||||
# HOST_PORT:CONTAINER_PORT
|
pull_policy: always
|
||||||
- "18081:18081"
|
volumes:
|
||||||
networks:
|
- ./backend/ew.test.othersite.config.json:/app/config.json:Z
|
||||||
- ecbackend
|
environment:
|
||||||
|
ELEMENT_WEB_PORT: 18081
|
||||||
nginx:
|
ports:
|
||||||
# see backend/dev_tls_setup for how to generate the tls certs
|
# HOST_PORT:CONTAINER_PORT
|
||||||
hostname: synapse.m.localhost
|
- "18081:18081"
|
||||||
image: nginx:latest
|
networks:
|
||||||
pull_policy: always
|
- ecbackend
|
||||||
volumes:
|
|
||||||
- ./backend/dev_nginx.conf:/etc/nginx/conf.d/default.conf:Z
|
nginx:
|
||||||
- ./backend/dev_tls_m.localhost.key:/root/ssl/key.pem:Z
|
# see backend/dev_tls_setup for how to generate the tls certs
|
||||||
- ./backend/dev_tls_m.localhost.crt:/root/ssl/cert.pem:Z
|
hostname: synapse.m.localhost
|
||||||
ports:
|
image: nginx:latest
|
||||||
# HOST_PORT:CONTAINER_PORT
|
pull_policy: always
|
||||||
- "443:443"
|
volumes:
|
||||||
- "8008:80"
|
- ./backend/dev_nginx.conf:/etc/nginx/conf.d/default.conf:Z
|
||||||
- "4443:443"
|
- ./backend/dev_tls_m.localhost.key:/root/ssl/key.pem:Z
|
||||||
- "8448:8448"
|
- ./backend/dev_tls_m.localhost.crt:/root/ssl/cert.pem:Z
|
||||||
extra_hosts:
|
ports:
|
||||||
- "host.docker.internal:host-gateway"
|
# HOST_PORT:CONTAINER_PORT
|
||||||
depends_on:
|
- "443:443"
|
||||||
- synapse
|
- "8008:80"
|
||||||
networks:
|
- "4443:443"
|
||||||
ecbackend:
|
- "8448:8448"
|
||||||
aliases:
|
extra_hosts:
|
||||||
- synapse.m.localhost
|
- "host.docker.internal:host-gateway"
|
||||||
- synapse.othersite.m.localhost
|
- "auth-server:127.0.0.1"
|
||||||
- matrix-rtc.m.localhost
|
- "auth-server-1:127.0.0.1"
|
||||||
- matrix-rtc.othersite.m.localhost
|
depends_on:
|
||||||
|
- synapse
|
||||||
|
networks:
|
||||||
|
ecbackend:
|
||||||
|
aliases:
|
||||||
|
- synapse.m.localhost
|
||||||
|
- synapse.othersite.m.localhost
|
||||||
|
- matrix-rtc.m.localhost
|
||||||
|
- matrix-rtc.othersite.m.localhost
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Please see LICENSE in the repository root for full details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { render } from "@testing-library/react";
|
import { render } from "@testing-library/react";
|
||||||
import { type FC, useRef } from "react";
|
import { type FC, useRef, useState } from "react";
|
||||||
import { expect, test, vi } from "vitest";
|
import { expect, test, vi } from "vitest";
|
||||||
import { Button } from "@vector-im/compound-web";
|
import { Button } from "@vector-im/compound-web";
|
||||||
import userEvent from "@testing-library/user-event";
|
import userEvent from "@testing-library/user-event";
|
||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
ReactionSet,
|
ReactionSet,
|
||||||
ReactionsRowSize,
|
ReactionsRowSize,
|
||||||
} from "./reactions";
|
} from "./reactions";
|
||||||
|
import { type Controls } from "./controls";
|
||||||
|
|
||||||
// Test Explanation:
|
// Test Explanation:
|
||||||
// - The main objective is to test `useCallViewKeyboardShortcuts`.
|
// - The main objective is to test `useCallViewKeyboardShortcuts`.
|
||||||
@@ -27,6 +28,7 @@ interface TestComponentProps {
|
|||||||
onButtonClick?: () => void;
|
onButtonClick?: () => void;
|
||||||
sendReaction?: () => void;
|
sendReaction?: () => void;
|
||||||
toggleHandRaised?: () => void;
|
toggleHandRaised?: () => void;
|
||||||
|
initialModalOpen?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TestComponent: FC<TestComponentProps> = ({
|
const TestComponent: FC<TestComponentProps> = ({
|
||||||
@@ -34,7 +36,9 @@ const TestComponent: FC<TestComponentProps> = ({
|
|||||||
onButtonClick = (): void => {},
|
onButtonClick = (): void => {},
|
||||||
sendReaction = (reaction: ReactionOption): void => {},
|
sendReaction = (reaction: ReactionOption): void => {},
|
||||||
toggleHandRaised = (): void => {},
|
toggleHandRaised = (): void => {},
|
||||||
|
initialModalOpen = false,
|
||||||
}) => {
|
}) => {
|
||||||
|
const [modalOpen, setModalOpen] = useState(initialModalOpen);
|
||||||
const ref = useRef<HTMLDivElement | null>(null);
|
const ref = useRef<HTMLDivElement | null>(null);
|
||||||
useCallViewKeyboardShortcuts(
|
useCallViewKeyboardShortcuts(
|
||||||
ref,
|
ref,
|
||||||
@@ -47,6 +51,19 @@ const TestComponent: FC<TestComponentProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div ref={ref}>
|
<div ref={ref}>
|
||||||
<Button onClick={onButtonClick}>TEST</Button>
|
<Button onClick={onButtonClick}>TEST</Button>
|
||||||
|
{modalOpen && (
|
||||||
|
<dialog
|
||||||
|
open
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Escape") {
|
||||||
|
e.preventDefault();
|
||||||
|
setModalOpen(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button>InModalButton</button>
|
||||||
|
</dialog>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -118,6 +135,27 @@ test("raised hand can be sent via keyboard presses", async () => {
|
|||||||
expect(toggleHandRaised).toHaveBeenCalledOnce();
|
expect(toggleHandRaised).toHaveBeenCalledOnce();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("raised hand cannot be sent via keyboard presses if modal open and focussed", async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
const toggleHandRaised = vi.fn();
|
||||||
|
const { getByRole } = render(
|
||||||
|
<TestComponent
|
||||||
|
toggleHandRaised={toggleHandRaised}
|
||||||
|
initialModalOpen={true}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
getByRole("button", { name: "InModalButton" }).focus();
|
||||||
|
await user.keyboard("h");
|
||||||
|
|
||||||
|
expect(toggleHandRaised).not.toHaveBeenCalledOnce();
|
||||||
|
|
||||||
|
// once we press esc...
|
||||||
|
await user.keyboard("[Escape]");
|
||||||
|
// we can toggle the hand raise...
|
||||||
|
await user.keyboard("h");
|
||||||
|
expect(toggleHandRaised).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
|
||||||
test("unmuting happens in place of the default action", async () => {
|
test("unmuting happens in place of the default action", async () => {
|
||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
const defaultPrevented = vi.fn();
|
const defaultPrevented = vi.fn();
|
||||||
@@ -138,3 +176,35 @@ test("unmuting happens in place of the default action", async () => {
|
|||||||
await user.keyboard("[Space]");
|
await user.keyboard("[Space]");
|
||||||
expect(defaultPrevented).toBeCalledWith(true);
|
expect(defaultPrevented).toBeCalledWith(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("escape button triggers the controls back action", async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
|
||||||
|
window.controls = { onBackButtonPressed: vi.fn() } as unknown as Controls;
|
||||||
|
// In the real application, we mostly just want the spacebar shortcut to avoid
|
||||||
|
// scrolling the page. But to test that here in JSDOM, we need some kind of
|
||||||
|
// container element that can be interactive and receive focus / keydown
|
||||||
|
// events. <video> is kind of a weird choice, but it'll do the job.
|
||||||
|
render(<TestComponent setAudioEnabled={() => {}} />);
|
||||||
|
|
||||||
|
await user.keyboard("[Escape]");
|
||||||
|
expect(window.controls.onBackButtonPressed).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("escape button does not trigger back if sth else is focused", async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
|
||||||
|
window.controls = { onBackButtonPressed: vi.fn() } as unknown as Controls;
|
||||||
|
|
||||||
|
const { getByRole } = render(<TestComponent initialModalOpen={true} />);
|
||||||
|
getByRole("button", { name: "InModalButton" }).focus();
|
||||||
|
|
||||||
|
// First Escape: the dialog's onKeyDown intercepts it and closes the modal.
|
||||||
|
await user.keyboard("[Escape]");
|
||||||
|
expect(window.controls.onBackButtonPressed).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
// Second Escape: modal is gone, focus has fallen back to document.body,
|
||||||
|
// which *does* contain the ref div, so the hook fires and back IS triggered.
|
||||||
|
await user.keyboard("[Escape]");
|
||||||
|
expect(window.controls.onBackButtonPressed).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ export function useCallViewKeyboardShortcuts(
|
|||||||
} else if (KeyToReactionMap[event.key]) {
|
} else if (KeyToReactionMap[event.key]) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
sendReaction(KeyToReactionMap[event.key]);
|
sendReaction(KeyToReactionMap[event.key]);
|
||||||
|
} else if (event.key === "Escape") {
|
||||||
|
window.controls.onBackButtonPressed?.();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in New Issue
Block a user