From 17e2b912300bec42242880cbe02ca88ba31e7255 Mon Sep 17 00:00:00 2001 From: nexy7574 Date: Sun, 6 Apr 2025 01:03:57 +0100 Subject: [PATCH] Implement knocking on rooms --- desktop/go.mod | 4 +-- desktop/go.sum | 8 ++--- go.mod | 4 +-- go.sum | 8 ++--- pkg/hicli/json-commands.go | 7 ++++ web/src/api/rpc.ts | 4 +++ web/src/api/types/mxtypes.ts | 1 + web/src/ui/roomview/RoomPreview.tsx | 50 ++++++++++++++++++++++++----- 8 files changed, 66 insertions(+), 20 deletions(-) diff --git a/desktop/go.mod b/desktop/go.mod index 2803b72..286207d 100644 --- a/desktop/go.mod +++ b/desktop/go.mod @@ -72,14 +72,14 @@ require ( golang.org/x/mod v0.24.0 // indirect golang.org/x/net v0.38.0 // indirect golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect + golang.org/x/sys v0.32.0 // indirect golang.org/x/text v0.23.0 // indirect golang.org/x/tools v0.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - maunium.net/go/mautrix v0.23.2 // indirect + maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38 // indirect mvdan.cc/xurls/v2 v2.6.0 // indirect ) diff --git a/desktop/go.sum b/desktop/go.sum index eb9678a..beb49be 100644 --- a/desktop/go.sum +++ b/desktop/go.sum @@ -221,8 +221,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -260,7 +260,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -maunium.net/go/mautrix v0.23.2 h1:Bo3tPrQJwkxyL7aMmy/T+d2tqIrypZjHqeHe8fyeAOg= -maunium.net/go/mautrix v0.23.2/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE= +maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38 h1:fIe2+kYndm3Mm/DwQ4FsODk2DjrLeEeW7tKtZjyERqM= +maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE= mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI= mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk= diff --git a/go.mod b/go.mod index 92387ee..0e05d53 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( golang.org/x/text v0.23.0 gopkg.in/yaml.v3 v3.0.1 maunium.net/go/mauflag v1.0.0 - maunium.net/go/mautrix v0.23.2 + maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38 mvdan.cc/xurls/v2 v2.6.0 ) @@ -42,6 +42,6 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect - golang.org/x/sys v0.31.0 // indirect + golang.org/x/sys v0.32.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect ) diff --git a/go.sum b/go.sum index d91aa96..d69b2e9 100644 --- a/go.sum +++ b/go.sum @@ -86,8 +86,8 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= @@ -99,7 +99,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.23.2 h1:Bo3tPrQJwkxyL7aMmy/T+d2tqIrypZjHqeHe8fyeAOg= -maunium.net/go/mautrix v0.23.2/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE= +maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38 h1:fIe2+kYndm3Mm/DwQ4FsODk2DjrLeEeW7tKtZjyERqM= +maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE= mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI= mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk= diff --git a/pkg/hicli/json-commands.go b/pkg/hicli/json-commands.go index 49bf4e1..bddbb44 100644 --- a/pkg/hicli/json-commands.go +++ b/pkg/hicli/json-commands.go @@ -173,6 +173,13 @@ func (h *HiClient) handleJSONCommand(ctx context.Context, req *JSONCommand) (any Reason: params.Reason, }) }) + case "knock_room": + return unmarshalAndCall(req.Data, func(params *joinRoomParams) (*mautrix.RespKnockRoom, error) { + return h.Client.KnockRoom(ctx, params.RoomIDOrAlias, &mautrix.ReqKnockRoom{ + Via: params.Via, + Reason: params.Reason, + }) + }) case "leave_room": return unmarshalAndCall(req.Data, func(params *leaveRoomParams) (*mautrix.RespLeaveRoom, error) { return h.Client.LeaveRoom(ctx, params.RoomID, &mautrix.ReqLeave{Reason: params.Reason}) diff --git a/web/src/api/rpc.ts b/web/src/api/rpc.ts index 737b8de..d5a6888 100644 --- a/web/src/api/rpc.ts +++ b/web/src/api/rpc.ts @@ -265,6 +265,10 @@ export default abstract class RPCClient { return this.request("join_room", { room_id_or_alias, via, reason }) } + knockRoom(room_id_or_alias: RoomID | RoomAlias, via?: string[], reason?: string): Promise { + return this.request("knock_room", { room_id_or_alias, via, reason }) + } + leaveRoom(room_id: RoomID, reason?: string): Promise> { return this.request("leave_room", { room_id, reason }) } diff --git a/web/src/api/types/mxtypes.ts b/web/src/api/types/mxtypes.ts index 6f72b70..f90bbc4 100644 --- a/web/src/api/types/mxtypes.ts +++ b/web/src/api/types/mxtypes.ts @@ -316,6 +316,7 @@ export interface RoomSummary { room_type: RoomType topic?: string world_readable: boolean + allowed_room_ids?: RoomID[] } export interface RespRoomJoin { diff --git a/web/src/ui/roomview/RoomPreview.tsx b/web/src/ui/roomview/RoomPreview.tsx index 71682f0..0f0e0a7 100644 --- a/web/src/ui/roomview/RoomPreview.tsx +++ b/web/src/ui/roomview/RoomPreview.tsx @@ -42,19 +42,34 @@ const RoomPreview = ({ roomID, via, alias, invite }: RoomPreviewProps) => { const [loading, setLoading] = useState(false) const [buttonClicked, setButtonClicked] = useState(false) const [error, setError] = useState(null) + const [knockRequest, setKnockRequest] = useState(null) const doJoinRoom = () => { let realVia = via if (!via?.length && invite?.invited_by) { realVia = [getServerName(invite.invited_by)] } setButtonClicked(true) - client.rpc.joinRoom(alias || roomID, alias ? undefined : realVia).then( - () => console.info("Successfully joined", roomID), - err => { - setError(`Failed to join room: ${err}`) - setButtonClicked(false) - }, - ) + if (requiresKnock) { + client.rpc.knockRoom(alias || roomID, alias ? undefined : realVia, knockRequest || undefined).then( + () => { + setButtonClicked(false) + mainScreen.clearActiveRoom() + }, + err => { + setError(`Failed to knock: ${err}`) + setButtonClicked(false) + }, + ) + return + } else { + client.rpc.joinRoom(alias || roomID, alias ? undefined : realVia).then( + () => console.info("Successfully joined", roomID), + err => { + setError(`Failed to join room: ${err}`) + setButtonClicked(false) + }, + ) + } } const doRejectInvite = () => { setButtonClicked(true) @@ -87,6 +102,19 @@ const RoomPreview = ({ roomID, via, alias, invite }: RoomPreviewProps) => { const topic = summary?.topic ?? invite?.topic ?? "" const showInviteAvatars = usePreference(client.store, null, "show_invite_avatars") const noAvatarPreview = invite && !showInviteAvatars + const joinRule = summary?.join_rule ?? invite?.join_rule ?? "invite" + let requiresKnock = ["knock", "knock_restricted"].includes(joinRule) && !invite + if (joinRule === "knock_restricted" && !invite) { + for (const roomID of summary?.allowed_room_ids ?? []) { + if (client.store.rooms.has(roomID)) { + console.log("RoomPreview: allowed room ID is already joined", roomID) + requiresKnock = false + break + } + } + } + const acceptAction = invite ? "Accept" : (requiresKnock ? "Ask to join" : "Join room") + return
{invite?.invited_by && !invite.dm_user_id ?
@@ -152,6 +180,12 @@ const RoomPreview = ({ roomID, via, alias, invite }: RoomPreviewProps) => { } {invite?.invited_by && } + {requiresKnock &&
+ +
}
{invite && + >{acceptAction}
{error &&