Matrix protocol in OCaml, Eio specialised
1(** Room preview operations.
2
3 Get information about a room before joining it. *)
4
5(** Room preview information *)
6type room_preview = {
7 room_id : Matrix_proto.Id.Room_id.t;
8 name : string option;
9 topic : string option;
10 avatar_url : string option;
11 canonical_alias : Matrix_proto.Id.Room_alias.t option;
12 join_rule : Matrix_proto.Event.Join_rule.t option;
13 num_joined_members : int;
14 room_type : string option;
15 world_readable : bool;
16 guest_can_join : bool;
17 membership : Matrix_proto.Event.Membership.t option;
18}
19
20(** Summary returned by room summary endpoint (MSC3266) *)
21type room_summary = {
22 room_id : string;
23 membership : Matrix_proto.Event.Membership.t option;
24 is_encrypted : bool option;
25 room_name : string option;
26 topic : string option;
27 avatar_url : string option;
28 canonical_alias : string option;
29 joined_members_count : int option;
30 invited_members_count : int option;
31 room_version : string option;
32 room_type : string option;
33 join_rule : Matrix_proto.Event.Join_rule.t option;
34 guest_can_join : bool option;
35 world_readable : bool option;
36}
37
38let room_summary_jsont =
39 Jsont.Object.(
40 map (fun room_id membership is_encrypted room_name topic avatar_url
41 canonical_alias joined_members_count invited_members_count
42 room_version room_type join_rule guest_can_join world_readable ->
43 { room_id; membership; is_encrypted; room_name; topic; avatar_url;
44 canonical_alias; joined_members_count; invited_members_count;
45 room_version; room_type; join_rule; guest_can_join; world_readable })
46 |> mem "room_id" Jsont.string ~enc:(fun t -> t.room_id)
47 |> opt_mem "membership" Matrix_proto.Event.Membership.jsont ~enc:(fun t -> t.membership)
48 |> opt_mem "is_encrypted" Jsont.bool ~enc:(fun t -> t.is_encrypted)
49 |> opt_mem "room_name" Jsont.string ~enc:(fun t -> t.room_name)
50 |> opt_mem "topic" Jsont.string ~enc:(fun t -> t.topic)
51 |> opt_mem "avatar_url" Jsont.string ~enc:(fun t -> t.avatar_url)
52 |> opt_mem "canonical_alias" Jsont.string ~enc:(fun t -> t.canonical_alias)
53 |> opt_mem "joined_members_count" Jsont.int ~enc:(fun t -> t.joined_members_count)
54 |> opt_mem "invited_members_count" Jsont.int ~enc:(fun t -> t.invited_members_count)
55 |> opt_mem "room_version" Jsont.string ~enc:(fun t -> t.room_version)
56 |> opt_mem "room_type" Jsont.string ~enc:(fun t -> t.room_type)
57 |> opt_mem "join_rule" Matrix_proto.Event.Join_rule.jsont ~enc:(fun t -> t.join_rule)
58 |> opt_mem "guest_can_join" Jsont.bool ~enc:(fun t -> t.guest_can_join)
59 |> opt_mem "world_readable" Jsont.bool ~enc:(fun t -> t.world_readable)
60 |> finish)
61
62(** Get room summary (MSC3266).
63
64 This is the preferred way to get room information before joining. *)
65let get_summary client ~room_id_or_alias ?via () =
66 let id_str = match room_id_or_alias with
67 | `Room_id id -> Matrix_proto.Id.Room_id.to_string id
68 | `Room_alias alias -> Matrix_proto.Id.Room_alias.to_string alias
69 in
70 let path = Printf.sprintf "/rooms/%s/summary" (Uri.pct_encode id_str) in
71 let query = match via with
72 | Some servers -> Some (List.map (fun s -> ("via", s)) servers)
73 | None -> None
74 in
75 match Client.get client ~path ?query () with
76 | Error e -> Error e
77 | Ok body -> Client.decode_response room_summary_jsont body
78
79(** Public room from directory listing *)
80type public_room = {
81 room_id : Matrix_proto.Id.Room_id.t;
82 name : string option;
83 topic : string option;
84 avatar_url : string option;
85 canonical_alias : Matrix_proto.Id.Room_alias.t option;
86 num_joined_members : int;
87 world_readable : bool;
88 guest_can_join : bool;
89 join_rule : Matrix_proto.Event.Join_rule.t option;
90 room_type : string option;
91}
92
93let public_room_jsont =
94 Jsont.Object.(
95 map (fun room_id name topic avatar_url canonical_alias num_joined_members
96 world_readable guest_can_join join_rule room_type ->
97 { room_id; name; topic; avatar_url; canonical_alias; num_joined_members;
98 world_readable; guest_can_join; join_rule; room_type })
99 |> mem "room_id" Matrix_proto.Id.Room_id.jsont ~enc:(fun t -> t.room_id)
100 |> opt_mem "name" Jsont.string ~enc:(fun t -> t.name)
101 |> opt_mem "topic" Jsont.string ~enc:(fun t -> t.topic)
102 |> opt_mem "avatar_url" Jsont.string ~enc:(fun t -> t.avatar_url)
103 |> opt_mem "canonical_alias" Matrix_proto.Id.Room_alias.jsont ~enc:(fun t -> t.canonical_alias)
104 |> mem "num_joined_members" Jsont.int ~dec_absent:0 ~enc:(fun t -> t.num_joined_members)
105 |> mem "world_readable" Jsont.bool ~dec_absent:false ~enc:(fun t -> t.world_readable)
106 |> mem "guest_can_join" Jsont.bool ~dec_absent:false ~enc:(fun t -> t.guest_can_join)
107 |> opt_mem "join_rule" Matrix_proto.Event.Join_rule.jsont ~enc:(fun t -> t.join_rule)
108 |> opt_mem "room_type" Jsont.string ~enc:(fun t -> t.room_type)
109 |> finish)
110
111type public_rooms_response = {
112 chunk : public_room list;
113 next_batch : string option;
114 prev_batch : string option;
115 total_room_count_estimate : int option;
116}
117
118let public_rooms_response_jsont =
119 Jsont.Object.(
120 map (fun chunk next_batch prev_batch total_room_count_estimate ->
121 { chunk; next_batch; prev_batch; total_room_count_estimate })
122 |> mem "chunk" (Jsont.list public_room_jsont) ~dec_absent:[]
123 ~enc:(fun t -> t.chunk)
124 |> opt_mem "next_batch" Jsont.string ~enc:(fun t -> t.next_batch)
125 |> opt_mem "prev_batch" Jsont.string ~enc:(fun t -> t.prev_batch)
126 |> opt_mem "total_room_count_estimate" Jsont.int
127 ~enc:(fun t -> t.total_room_count_estimate)
128 |> finish)
129
130(** Get list of public rooms.
131
132 @param limit Maximum number of rooms to return
133 @param since Pagination token
134 @param server Server to query for rooms *)
135let get_public_rooms client ?limit ?since ?server () =
136 let path = "/publicRooms" in
137 let query =
138 []
139 |> (fun q -> match limit with Some l -> ("limit", string_of_int l) :: q | None -> q)
140 |> (fun q -> match since with Some s -> ("since", s) :: q | None -> q)
141 |> (fun q -> match server with Some s -> ("server", s) :: q | None -> q)
142 in
143 let query = if query = [] then None else Some query in
144 match Client.get client ~path ?query () with
145 | Error e -> Error e
146 | Ok body -> Client.decode_response public_rooms_response_jsont body
147
148(** Search filter for public rooms *)
149type public_rooms_filter = {
150 generic_search_term : string option;
151 room_types : string list option;
152}
153
154let public_rooms_filter_jsont =
155 Jsont.Object.(
156 map (fun generic_search_term room_types ->
157 { generic_search_term; room_types })
158 |> opt_mem "generic_search_term" Jsont.string ~enc:(fun t -> t.generic_search_term)
159 |> opt_mem "room_types" (Jsont.list Jsont.string) ~enc:(fun t -> t.room_types)
160 |> finish)
161
162type search_public_rooms_request = {
163 limit : int option;
164 since : string option;
165 filter : public_rooms_filter option;
166 include_all_networks : bool option;
167 third_party_instance_id : string option;
168} [@@warning "-69"]
169
170let search_public_rooms_request_jsont =
171 Jsont.Object.(
172 map (fun limit since filter include_all_networks third_party_instance_id ->
173 { limit; since; filter; include_all_networks; third_party_instance_id })
174 |> opt_mem "limit" Jsont.int ~enc:(fun t -> t.limit)
175 |> opt_mem "since" Jsont.string ~enc:(fun t -> t.since)
176 |> opt_mem "filter" public_rooms_filter_jsont ~enc:(fun t -> t.filter)
177 |> opt_mem "include_all_networks" Jsont.bool ~enc:(fun t -> t.include_all_networks)
178 |> opt_mem "third_party_instance_id" Jsont.string ~enc:(fun t -> t.third_party_instance_id)
179 |> finish)
180
181(** Search public rooms with filters.
182
183 @param search_term Text to search for
184 @param limit Maximum number of rooms
185 @param since Pagination token
186 @param room_types Filter by room type
187 @param server Server to query *)
188let search_public_rooms client ?search_term ?limit ?since ?room_types ?server () =
189 let path = "/publicRooms" in
190 let query = match server with
191 | Some s -> Some [("server", s)]
192 | None -> None
193 in
194 let filter = match search_term, room_types with
195 | None, None -> None
196 | _ -> Some { generic_search_term = search_term; room_types }
197 in
198 let request = {
199 limit;
200 since;
201 filter;
202 include_all_networks = None;
203 third_party_instance_id = None;
204 } in
205 match Client.encode_body search_public_rooms_request_jsont request with
206 | Error e -> Error e
207 | Ok body ->
208 match Client.post client ~path ~body ?query () with
209 | Error e -> Error e
210 | Ok resp_body -> Client.decode_response public_rooms_response_jsont resp_body
211
212(** Resolve a room alias to a room ID and servers.
213
214 @param room_alias The room alias to resolve *)
215let resolve_alias client ~room_alias =
216 let alias_str = Matrix_proto.Id.Room_alias.to_string room_alias in
217 let path = Printf.sprintf "/directory/room/%s" (Uri.pct_encode alias_str) in
218 let response_jsont = Jsont.Object.(
219 map (fun room_id servers -> (room_id, servers))
220 |> mem "room_id" Matrix_proto.Id.Room_id.jsont
221 |> mem "servers" (Jsont.list Jsont.string) ~dec_absent:[]
222 |> finish)
223 in
224 match Client.get client ~path () with
225 | Error e -> Error e
226 | Ok body -> Client.decode_response response_jsont body
227
228(** Knock on a room (MSC2403).
229
230 Request to join a room that has knock join rules.
231
232 @param room_id_or_alias The room to knock on
233 @param reason Optional reason for the knock request
234 @param via Servers to try *)
235let knock client ~room_id_or_alias ?reason ?(via = []) () =
236 let id_str = match room_id_or_alias with
237 | `Room_id id -> Matrix_proto.Id.Room_id.to_string id
238 | `Room_alias alias -> Matrix_proto.Id.Room_alias.to_string alias
239 in
240 let path = Printf.sprintf "/knock/%s" (Uri.pct_encode id_str) in
241 let query = if via = [] then None else Some (List.map (fun s -> ("server_name", s)) via) in
242 let request_jsont = Jsont.Object.(
243 map (fun reason -> reason)
244 |> opt_mem "reason" Jsont.string ~enc:Fun.id
245 |> finish)
246 in
247 let response_jsont = Jsont.Object.(
248 map (fun room_id -> room_id)
249 |> mem "room_id" Matrix_proto.Id.Room_id.jsont
250 |> finish)
251 in
252 match Client.encode_body request_jsont reason with
253 | Error e -> Error e
254 | Ok body ->
255 match Client.post client ~path ~body ?query () with
256 | Error e -> Error e
257 | Ok resp_body -> Client.decode_response response_jsont resp_body