Fix redactions not working because they pick up events in transit.

This commit is contained in:
Half-Shot
2024-10-31 16:04:37 +00:00
parent 7229f4bf1b
commit a354a4013d
2 changed files with 61 additions and 68 deletions

View File

@@ -22,10 +22,11 @@ import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { useReactions } from "../useReactions"; import { useReactions } from "../useReactions";
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships"; import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
interface InnerButtonButtonProps extends ComponentPropsWithoutRef<"button"> { interface InnerButtonProps extends ComponentPropsWithoutRef<"button"> {
raised: boolean; raised: boolean;
} }
const InnerButton: FC<InnerButtonButtonProps> = ({ raised, ...props }) => {
const InnerButton: FC<InnerButtonProps> = ({ raised, ...props }) => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
@@ -37,7 +38,7 @@ const InnerButton: FC<InnerButtonButtonProps> = ({ raised, ...props }) => {
> >
<p <p
role="img" role="img"
aria-label="raised hand" aria-hidden
style={{ style={{
width: "30px", width: "30px",
height: "0px", height: "0px",
@@ -52,7 +53,7 @@ const InnerButton: FC<InnerButtonButtonProps> = ({ raised, ...props }) => {
); );
}; };
interface RaisedHandToggleButton { interface RaisedHandToggleButtonProps {
rtcSession: MatrixRTCSession; rtcSession: MatrixRTCSession;
client: MatrixClient; client: MatrixClient;
} }
@@ -60,30 +61,27 @@ interface RaisedHandToggleButton {
export function RaiseHandToggleButton({ export function RaiseHandToggleButton({
client, client,
rtcSession, rtcSession,
}: RaisedHandToggleButton): ReactNode { }: RaisedHandToggleButtonProps): ReactNode {
const { raisedHands, removeRaisedHand, addRaisedHand, myReactionId } = const { raisedHands, myReactionId } = useReactions();
useReactions();
const [busy, setBusy] = useState(false); const [busy, setBusy] = useState(false);
const userId = client.getUserId()!; const userId = client.getUserId()!;
const isHandRaised = !!raisedHands[userId]; const isHandRaised = !!raisedHands[userId];
const memberships = useMatrixRTCSessionMemberships(rtcSession); const memberships = useMatrixRTCSessionMemberships(rtcSession);
const toggleRaisedHand = useCallback(() => { const toggleRaisedHand = useCallback(async () => {
if (isHandRaised) { if (isHandRaised) {
if (myReactionId) { if (!myReactionId) {
logger.warn(`Hand raised but no reaction event to redact!`);
return;
}
try {
setBusy(true); setBusy(true);
client await client.redactEvent(rtcSession.room.roomId, myReactionId);
.redactEvent(rtcSession.room.roomId, myReactionId) logger.debug("Redacted raise hand event");
.then(() => { } catch (ex) {
logger.debug("Redacted raise hand event"); logger.error("Failed to redact reaction event", myReactionId, ex);
removeRaisedHand(userId); } finally {
}) setBusy(false);
.catch((e) => {
logger.error("Failed to redact reaction event", e);
})
.finally(() => {
setBusy(false);
});
} }
} else { } else {
const myMembership = memberships.find((m) => m.sender === userId); const myMembership = memberships.find((m) => m.sender === userId);
@@ -92,29 +90,25 @@ export function RaiseHandToggleButton({
return; return;
} }
const parentEventId = myMembership.eventId; const parentEventId = myMembership.eventId;
setBusy(true); try {
client setBusy(true);
.sendEvent(rtcSession.room.roomId, EventType.Reaction, { const reaction = await client.sendEvent(
"m.relates_to": { rtcSession.room.roomId,
rel_type: RelationType.Annotation, EventType.Reaction,
event_id: parentEventId, {
key: "🖐️", "m.relates_to": {
rel_type: RelationType.Annotation,
event_id: parentEventId,
key: "🖐️",
},
}, },
}) );
.then((reaction) => { logger.debug("Sent raise hand event", reaction.event_id);
logger.debug("Sent raise hand event", reaction.event_id); } catch (ex) {
addRaisedHand(userId, { logger.error("Failed to send reaction event", ex);
membershipEventId: parentEventId, } finally {
reactionEventId: reaction.event_id, setBusy(false);
time: new Date(), }
});
})
.catch((e) => {
logger.error("Failed to send reaction event", e);
})
.finally(() => {
setBusy(false);
});
} }
}, [ }, [
client, client,
@@ -122,8 +116,6 @@ export function RaiseHandToggleButton({
memberships, memberships,
myReactionId, myReactionId,
rtcSession.room.roomId, rtcSession.room.roomId,
addRaisedHand,
removeRaisedHand,
userId, userId,
]); ]);

View File

@@ -29,8 +29,6 @@ import { useClientState } from "./ClientContext";
interface ReactionsContextType { interface ReactionsContextType {
raisedHands: Record<string, Date>; raisedHands: Record<string, Date>;
addRaisedHand: (userId: string, info: RaisedHandInfo) => void;
removeRaisedHand: (userId: string) => void;
supportsReactions: boolean; supportsReactions: boolean;
myReactionId: string | null; myReactionId: string | null;
} }
@@ -99,23 +97,20 @@ export const ReactionsProvider = ({
[raisedHands], [raisedHands],
); );
const addRaisedHand = useCallback( const addRaisedHand = useCallback((userId: string, info: RaisedHandInfo) => {
(userId: string, info: RaisedHandInfo) => { setRaisedHands((prevRaisedHands) => ({
setRaisedHands({ ...prevRaisedHands,
...raisedHands, [userId]: info,
[userId]: info, }));
}); }, []);
},
[raisedHands],
);
const removeRaisedHand = useCallback( const removeRaisedHand = useCallback((userId: string) => {
(userId: string) => { delete raisedHands[userId];
delete raisedHands[userId]; setRaisedHands((prevRaisedHands) => {
setRaisedHands({ ...raisedHands }); delete prevRaisedHands[userId];
}, return { ...prevRaisedHands };
[raisedHands], });
); }, []);
// This effect will check the state whenever the membership of the session changes. // This effect will check the state whenever the membership of the session changes.
useEffect(() => { useEffect(() => {
@@ -168,13 +163,16 @@ export const ReactionsProvider = ({
} }
} }
} }
// Deliberately ignoring addRaisedHand, raisedHands which was causing looping. }, [room, memberships, addRaisedHand, removeRaisedHand]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [room, memberships]);
// This effect handles any *live* reaction/redactions in the room. // This effect handles any *live* reaction/redactions in the room.
useEffect(() => { useEffect(() => {
const handleReactionEvent = (event: MatrixEvent): void => { const handleReactionEvent = (event: MatrixEvent): void => {
if (event.isSending()) {
// Skip any events that are still sending.
return;
}
const sender = event.getSender(); const sender = event.getSender();
const reactionEventId = event.getId(); const reactionEventId = event.getId();
if (!sender || !reactionEventId) { if (!sender || !reactionEventId) {
@@ -222,9 +220,14 @@ export const ReactionsProvider = ({
room.on(MatrixRoomEvent.Timeline, handleReactionEvent); room.on(MatrixRoomEvent.Timeline, handleReactionEvent);
room.on(MatrixRoomEvent.Redaction, handleReactionEvent); room.on(MatrixRoomEvent.Redaction, handleReactionEvent);
// We listen for a local echo to get the real event ID, as timeline events
// may still be sending.
room.on(MatrixRoomEvent.LocalEchoUpdated, handleReactionEvent);
return (): void => { return (): void => {
room.off(MatrixRoomEvent.Timeline, handleReactionEvent); room.off(MatrixRoomEvent.Timeline, handleReactionEvent);
room.off(MatrixRoomEvent.Redaction, handleReactionEvent); room.off(MatrixRoomEvent.Redaction, handleReactionEvent);
room.off(MatrixRoomEvent.LocalEchoUpdated, handleReactionEvent);
}; };
}, [room, addRaisedHand, removeRaisedHand, memberships, raisedHands]); }, [room, addRaisedHand, removeRaisedHand, memberships, raisedHands]);
@@ -232,8 +235,6 @@ export const ReactionsProvider = ({
<ReactionsContext.Provider <ReactionsContext.Provider
value={{ value={{
raisedHands: resultRaisedHands, raisedHands: resultRaisedHands,
addRaisedHand,
removeRaisedHand,
supportsReactions, supportsReactions,
myReactionId, myReactionId,
}} }}