mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-19 18:13:41 -05:00
Implement knocking on rooms
This commit is contained in:
parent
c2b12b1a88
commit
17e2b91230
8 changed files with 66 additions and 20 deletions
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -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=
|
||||
|
|
4
go.mod
4
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
|
||||
)
|
||||
|
|
8
go.sum
8
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=
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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<RespRoomJoin> {
|
||||
return this.request("knock_room", { room_id_or_alias, via, reason })
|
||||
}
|
||||
|
||||
leaveRoom(room_id: RoomID, reason?: string): Promise<Record<string, never>> {
|
||||
return this.request("leave_room", { room_id, reason })
|
||||
}
|
||||
|
|
|
@ -316,6 +316,7 @@ export interface RoomSummary {
|
|||
room_type: RoomType
|
||||
topic?: string
|
||||
world_readable: boolean
|
||||
allowed_room_ids?: RoomID[]
|
||||
}
|
||||
|
||||
export interface RespRoomJoin {
|
||||
|
|
|
@ -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<string | null>(null)
|
||||
const [knockRequest, setKnockRequest] = useState<string | null>(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 <div className="room-view preview">
|
||||
<div className="preview-inner">
|
||||
{invite?.invited_by && !invite.dm_user_id ? <div className="inviter-info">
|
||||
|
@ -152,6 +180,12 @@ const RoomPreview = ({ roomID, via, alias, invite }: RoomPreviewProps) => {
|
|||
</table>
|
||||
</details>}
|
||||
{invite?.invited_by && <MutualRooms client={client} userID={invite.invited_by}/>}
|
||||
{requiresKnock && <div className="knock-input">
|
||||
<textarea
|
||||
onChange={event => setKnockRequest(event.currentTarget.value)}
|
||||
placeholder="Why do you want to join this room?">
|
||||
</textarea>
|
||||
</div>}
|
||||
<div className="buttons">
|
||||
{invite && <button
|
||||
disabled={buttonClicked}
|
||||
|
@ -162,7 +196,7 @@ const RoomPreview = ({ roomID, via, alias, invite }: RoomPreviewProps) => {
|
|||
disabled={buttonClicked}
|
||||
className="primary-color-button"
|
||||
onClick={doJoinRoom}
|
||||
>{invite ? "Accept" : "Join room"}</button>
|
||||
>{acceptAction}</button>
|
||||
</div>
|
||||
{error && <div className="error">
|
||||
<ErrorIcon color="var(--error-color)"/>
|
||||
|
|
Loading…
Add table
Reference in a new issue