Skip to content

Commit 68db660

Browse files
Add mx_send_event() and mx_set_state() generic senders (#13)
mx_send hardcodes m.room.message and mx_react hardcodes m.reaction, with no way to send other event types. Add mx_send_event() (arbitrary room event, e.g. m.room.encrypted for E2EE) and mx_set_state() (arbitrary state event, e.g. m.room.encryption). Both thin PUTs mirroring mx_send. Needed by mx.client's end-to-end encryption transport.
1 parent 7e637d6 commit 68db660

7 files changed

Lines changed: 142 additions & 11 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: mx.api
22
Type: Package
33
Title: Minimal Matrix Client-Server API
4-
Version: 0.2.0
4+
Version: 0.2.0.1
55
Date: 2026-05-13
66
Authors@R: c(
77
person("Troy", "Hernandez", role = c("aut", "cre"),

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ export(mx_room_name)
1919
export(mx_room_topic)
2020
export(mx_rooms)
2121
export(mx_send)
22+
export(mx_send_event)
2223
export(mx_send_to_device)
2324
export(mx_session)
25+
export(mx_set_state)
2426
export(mx_sync)
2527
export(mx_upload)
2628
export(mx_whoami)

R/messages.R

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,73 @@ mx_send <- function(session, room_id, body, msgtype = "m.text", extra = NULL) {
3232
resp$event_id
3333
}
3434

35+
#' Send an arbitrary room event
36+
#'
37+
#' Generic counterpart to \code{\link{mx_send}} for event types other than
38+
#' \code{m.room.message}, such as \code{m.room.encrypted}. The content is
39+
#' sent verbatim.
40+
#'
41+
#' @param session An "mx_session" object.
42+
#' @param room_id Character. The room ID.
43+
#' @param event_type Character. The event type, e.g.
44+
#' \code{"m.room.encrypted"}.
45+
#' @param content List. The event content, sent as-is.
46+
#' @param txn_id Character or NULL. Transaction id (generated if NULL).
47+
#' @return The event ID of the sent event.
48+
#' @examples
49+
#' \dontrun{
50+
#' mx_send_event(s, "!abc:example", "m.room.encrypted", encrypted_content)
51+
#' }
52+
#' @export
53+
mx_send_event <- function(session, room_id, event_type, content,
54+
txn_id = NULL) {
55+
if (is.null(txn_id)) {
56+
txn_id <- mx_txn_id()
57+
}
58+
path <- sprintf(
59+
"/_matrix/client/v3/rooms/%s/send/%s/%s",
60+
mx_encode_id(room_id), mx_encode_id(event_type),
61+
mx_encode_id(txn_id)
62+
)
63+
resp <- mx_http(
64+
session$server, "PUT", path,
65+
body = content, token = session$token
66+
)
67+
resp$event_id
68+
}
69+
70+
#' Set a room state event
71+
#'
72+
#' Generic state setter, e.g. to mark a room encrypted by putting an
73+
#' \code{m.room.encryption} event.
74+
#'
75+
#' @param session An "mx_session" object.
76+
#' @param room_id Character. The room ID.
77+
#' @param event_type Character. State event type, e.g.
78+
#' \code{"m.room.encryption"}.
79+
#' @param content List. The state content, sent as-is.
80+
#' @param state_key Character. State key (default empty string).
81+
#' @return The event ID of the state event.
82+
#' @examples
83+
#' \dontrun{
84+
#' mx_set_state(s, "!abc:example", "m.room.encryption",
85+
#' list(algorithm = "m.megolm.v1.aes-sha2"))
86+
#' }
87+
#' @export
88+
mx_set_state <- function(session, room_id, event_type, content,
89+
state_key = "") {
90+
path <- sprintf(
91+
"/_matrix/client/v3/rooms/%s/state/%s/%s",
92+
mx_encode_id(room_id), mx_encode_id(event_type),
93+
mx_encode_id(state_key)
94+
)
95+
resp <- mx_http(
96+
session$server, "PUT", path,
97+
body = content, token = session$token
98+
)
99+
resp$event_id
100+
}
101+
35102
#' Fetch historical messages from a room
36103
#'
37104
#' Thin wrapper over the /rooms/{id}/messages endpoint.

man/mx.api-package.Rd

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,8 @@
33
\name{mx.api-package}
44
\alias{mx.api}
55
\alias{mx.api-package}
6-
\title{mx.api: Minimal Matrix Client-Server API}
7-
\description{
8-
Base-R bindings for the Matrix Client-Server HTTP API, suitable for
9-
talking to a Synapse homeserver. Two dependencies: curl and jsonlite.
10-
End-to-end encryption is out of scope; use unencrypted rooms or a
11-
separate crypto package.
12-
}
13-
\author{
14-
\strong{Maintainer}: Troy Hernandez \email{troy@cornball.ai}
15-
}
6+
\title{\packageTitle{mx.api}}
7+
\description{\packageDescription{mx.api}}
8+
\section{Package Content}{\packageIndices{mx.api}}
9+
\author{\packageAuthor{mx.api}}
10+
\section{Maintainer}{\packageMaintainer{mx.api}}

man/mx_canonical_json.Rd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ strings, integers only (no floats, no exponents, no decimal places,
2222
within \code{[-(2^53)+1, (2^53)-1]}), and rejection of NaN, Inf,
2323
NA values, and NA or duplicate object keys. The output is the exact
2424
byte sequence to feed into an ed25519 signer.
25+
}
26+
\details{
2527
R named lists become JSON objects; unnamed lists and length > 1
2628
atomic vectors become arrays. Length-1 atomics become scalars. To
2729
force a length-1 value to encode as an array, wrap it in a
2830
single-element \code{list(...)} or in \code{I()} (AsIs values are
2931
always encoded as arrays, names dropped, mirroring jsonlite).
32+
3033
}
3134
\examples{
3235
mx_canonical_json(list(b = 2, a = 1))

man/mx_send_event.Rd

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
% tinyrox says don't edit this manually, but it can't stop you!
2+
\name{mx_send_event}
3+
\alias{mx_send_event}
4+
\title{Send an arbitrary room event}
5+
\usage{
6+
mx_send_event(session, room_id, event_type, content, txn_id = NULL)
7+
}
8+
\arguments{
9+
\item{session}{An "mx_session" object.}
10+
11+
\item{room_id}{Character. The room ID.}
12+
13+
\item{event_type}{Character. The event type, e.g.
14+
\code{"m.room.encrypted"}.}
15+
16+
\item{content}{List. The event content, sent as-is.}
17+
18+
\item{txn_id}{Character or NULL. Transaction id (generated if NULL).}
19+
}
20+
\value{
21+
The event ID of the sent event.
22+
}
23+
\description{
24+
Generic counterpart to \code{\link{mx_send}} for event types other than
25+
\code{m.room.message}, such as \code{m.room.encrypted}. The content is
26+
sent verbatim.
27+
}
28+
\examples{
29+
\dontrun{
30+
mx_send_event(s, "!abc:example", "m.room.encrypted", encrypted_content)
31+
}
32+
}

man/mx_set_state.Rd

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
% tinyrox says don't edit this manually, but it can't stop you!
2+
\name{mx_set_state}
3+
\alias{mx_set_state}
4+
\title{Set a room state event}
5+
\usage{
6+
mx_set_state(session, room_id, event_type, content, state_key = "")
7+
}
8+
\arguments{
9+
\item{session}{An "mx_session" object.}
10+
11+
\item{room_id}{Character. The room ID.}
12+
13+
\item{event_type}{Character. State event type, e.g.
14+
\code{"m.room.encryption"}.}
15+
16+
\item{content}{List. The state content, sent as-is.}
17+
18+
\item{state_key}{Character. State key (default empty string).}
19+
}
20+
\value{
21+
The event ID of the state event.
22+
}
23+
\description{
24+
Generic state setter, e.g. to mark a room encrypted by putting an
25+
\code{m.room.encryption} event.
26+
}
27+
\examples{
28+
\dontrun{
29+
mx_set_state(s, "!abc:example", "m.room.encryption",
30+
list(algorithm = "m.megolm.v1.aes-sha2"))
31+
}
32+
}

0 commit comments

Comments
 (0)