Matrix protocol in OCaml, Eio specialised
at main 329 lines 11 kB view raw
1(** Account management operations. *) 2 3(* Account data *) 4let get_account_data client ~event_type = 5 match Client.user_id client with 6 | None -> Error (Error.Network_error "Not logged in") 7 | Some user_id -> 8 let user_id_str = Matrix_proto.Id.User_id.to_string user_id in 9 let path = Printf.sprintf "/user/%s/account_data/%s" 10 (Uri.pct_encode user_id_str) 11 (Uri.pct_encode event_type) 12 in 13 match Client.get client ~path () with 14 | Error e -> Error e 15 | Ok body -> Client.decode_response Jsont.json body 16 17let set_account_data client ~event_type ~content = 18 match Client.user_id client with 19 | None -> Error (Error.Network_error "Not logged in") 20 | Some user_id -> 21 let user_id_str = Matrix_proto.Id.User_id.to_string user_id in 22 let path = Printf.sprintf "/user/%s/account_data/%s" 23 (Uri.pct_encode user_id_str) 24 (Uri.pct_encode event_type) 25 in 26 match Client.encode_body Jsont.json content with 27 | Error e -> Error e 28 | Ok body -> 29 match Client.put client ~path ~body () with 30 | Error e -> Error e 31 | Ok _ -> Ok () 32 33let get_room_account_data client ~room_id ~event_type = 34 match Client.user_id client with 35 | None -> Error (Error.Network_error "Not logged in") 36 | Some user_id -> 37 let user_id_str = Matrix_proto.Id.User_id.to_string user_id in 38 let room_id_str = Matrix_proto.Id.Room_id.to_string room_id in 39 let path = Printf.sprintf "/user/%s/rooms/%s/account_data/%s" 40 (Uri.pct_encode user_id_str) 41 (Uri.pct_encode room_id_str) 42 (Uri.pct_encode event_type) 43 in 44 match Client.get client ~path () with 45 | Error e -> Error e 46 | Ok body -> Client.decode_response Jsont.json body 47 48let set_room_account_data client ~room_id ~event_type ~content = 49 match Client.user_id client with 50 | None -> Error (Error.Network_error "Not logged in") 51 | Some user_id -> 52 let user_id_str = Matrix_proto.Id.User_id.to_string user_id in 53 let room_id_str = Matrix_proto.Id.Room_id.to_string room_id in 54 let path = Printf.sprintf "/user/%s/rooms/%s/account_data/%s" 55 (Uri.pct_encode user_id_str) 56 (Uri.pct_encode room_id_str) 57 (Uri.pct_encode event_type) 58 in 59 match Client.encode_body Jsont.json content with 60 | Error e -> Error e 61 | Ok body -> 62 match Client.put client ~path ~body () with 63 | Error e -> Error e 64 | Ok _ -> Ok () 65 66(* Third-party identifiers *) 67type threepid = { 68 medium : string; 69 address : string; 70 validated_at : int64; 71 added_at : int64; 72} 73 74let threepid_jsont = 75 Jsont.Object.( 76 map (fun medium address validated_at added_at -> 77 { medium; address; validated_at; added_at }) 78 |> mem "medium" Jsont.string 79 |> mem "address" Jsont.string 80 |> mem "validated_at" Jsont.int64 81 |> mem "added_at" Jsont.int64 82 |> finish) 83 84type threepids_response = { 85 threepids : threepid list; 86} 87 88let threepids_response_jsont = 89 Jsont.Object.( 90 map (fun threepids -> { threepids }) 91 |> mem "threepids" (Jsont.list threepid_jsont) ~dec_absent:[] 92 |> finish) 93 94let get_3pids client = 95 match Client.get client ~path:"/account/3pid" () with 96 | Error e -> Error e 97 | Ok body -> 98 match Client.decode_response threepids_response_jsont body with 99 | Error e -> Error e 100 | Ok resp -> Ok resp.threepids 101 102(* Email token request *) 103type email_token_request = { 104 email : string; 105 client_secret : string; 106 send_attempt : int; 107} [@@warning "-69"] 108 109let email_token_request_jsont = 110 Jsont.Object.( 111 map (fun email client_secret send_attempt -> 112 { email; client_secret; send_attempt }) 113 |> mem "email" Jsont.string 114 |> mem "client_secret" Jsont.string 115 |> mem "send_attempt" Jsont.int 116 |> finish) 117 118type token_response = { 119 sid : string; 120} 121 122let token_response_jsont = 123 Jsont.Object.( 124 map (fun sid -> { sid }) 125 |> mem "sid" Jsont.string 126 |> finish) 127 128let request_email_token client ~email ~client_secret ~send_attempt = 129 let request = { email; client_secret; send_attempt } in 130 match Client.encode_body email_token_request_jsont request with 131 | Error e -> Error e 132 | Ok body -> 133 match Client.post client ~path:"/account/3pid/email/requestToken" ~body () with 134 | Error e -> Error e 135 | Ok body -> 136 match Client.decode_response token_response_jsont body with 137 | Error e -> Error e 138 | Ok resp -> Ok resp.sid 139 140(* MSISDN token request *) 141type msisdn_token_request = { 142 country : string; 143 phone_number : string; 144 client_secret : string; 145 send_attempt : int; 146} [@@warning "-69"] 147 148let msisdn_token_request_jsont = 149 Jsont.Object.( 150 map (fun country phone_number client_secret send_attempt -> 151 { country; phone_number; client_secret; send_attempt }) 152 |> mem "country" Jsont.string 153 |> mem "phone_number" Jsont.string 154 |> mem "client_secret" Jsont.string 155 |> mem "send_attempt" Jsont.int 156 |> finish) 157 158let request_msisdn_token client ~country ~phone_number ~client_secret ~send_attempt = 159 let request = { country; phone_number; client_secret; send_attempt } in 160 match Client.encode_body msisdn_token_request_jsont request with 161 | Error e -> Error e 162 | Ok body -> 163 match Client.post client ~path:"/account/3pid/msisdn/requestToken" ~body () with 164 | Error e -> Error e 165 | Ok body -> 166 match Client.decode_response token_response_jsont body with 167 | Error e -> Error e 168 | Ok resp -> Ok resp.sid 169 170(* Add 3pid *) 171type add_3pid_request = { 172 client_secret : string; 173 sid : string; 174} [@@warning "-69"] 175 176let add_3pid_request_jsont = 177 Jsont.Object.( 178 map (fun client_secret sid -> { client_secret; sid }) 179 |> mem "client_secret" Jsont.string 180 |> mem "sid" Jsont.string 181 |> finish) 182 183let add_3pid client ~client_secret ~sid = 184 let request = { client_secret; sid } in 185 match Client.encode_body add_3pid_request_jsont request with 186 | Error e -> Error e 187 | Ok body -> 188 match Client.post client ~path:"/account/3pid/add" ~body () with 189 | Error e -> Error e 190 | Ok _ -> Ok () 191 192(* Delete 3pid *) 193type delete_3pid_request = { 194 medium : string; 195 address : string; 196} [@@warning "-69"] 197 198let delete_3pid_request_jsont = 199 Jsont.Object.( 200 map (fun medium address -> { medium; address }) 201 |> mem "medium" Jsont.string 202 |> mem "address" Jsont.string 203 |> finish) 204 205let delete_3pid client ~medium ~address = 206 let request = { medium; address } in 207 match Client.encode_body delete_3pid_request_jsont request with 208 | Error e -> Error e 209 | Ok body -> 210 match Client.post client ~path:"/account/3pid/delete" ~body () with 211 | Error e -> Error e 212 | Ok _ -> Ok () 213 214(* Password change - simplified without UIAA *) 215type change_password_request = { 216 new_password : string; 217 logout_devices : bool; 218} [@@warning "-69"] 219 220let change_password_request_jsont = 221 Jsont.Object.( 222 map (fun new_password logout_devices -> { new_password; logout_devices }) 223 |> mem "new_password" Jsont.string 224 |> mem "logout_devices" Jsont.bool ~dec_absent:false 225 |> finish) 226 227let change_password client ~new_password ?(logout_devices = false) () = 228 let request = { new_password; logout_devices } in 229 match Client.encode_body change_password_request_jsont request with 230 | Error e -> Error e 231 | Ok body -> 232 match Client.post client ~path:"/account/password" ~body () with 233 | Error e -> Error e 234 | Ok _ -> Ok () 235 236(* Account deactivation - simplified without UIAA *) 237type deactivate_request = { 238 erase : bool; 239} [@@warning "-69"] 240 241let deactivate_request_jsont = 242 Jsont.Object.( 243 map (fun erase -> { erase }) 244 |> mem "erase" Jsont.bool ~dec_absent:false 245 |> finish) 246 247let deactivate client ?(erase = false) () = 248 let request = { erase } in 249 match Client.encode_body deactivate_request_jsont request with 250 | Error e -> Error e 251 | Ok body -> 252 match Client.post client ~path:"/account/deactivate" ~body () with 253 | Error e -> Error e 254 | Ok _ -> Ok () 255 256(* Ignored users - stored in account data *) 257type ignored_users_content = { 258 ignored_users : (string * Jsont.json) list; 259} 260 261let ignored_users_content_jsont = 262 let module StringMap = Map.Make(String) in 263 let map_jsont = 264 Jsont.Object.as_string_map Jsont.json 265 |> Jsont.map 266 ~dec:(fun m -> StringMap.bindings m) 267 ~enc:(fun l -> List.to_seq l |> StringMap.of_seq) 268 in 269 Jsont.Object.( 270 map (fun ignored_users -> { ignored_users }) 271 |> mem "ignored_users" map_jsont ~dec_absent:[] 272 |> finish) 273 274let get_ignored_users client = 275 match get_account_data client ~event_type:"m.ignored_user_list" with 276 | Error (Error.Matrix_error { errcode = Error.M_NOT_FOUND; _ }) -> Ok [] 277 | Error e -> Error e 278 | Ok json -> 279 match Jsont_bytesrw.decode_string ignored_users_content_jsont 280 (Result.get_ok (Jsont_bytesrw.encode_string Jsont.json json)) with 281 | Error _ -> Ok [] 282 | Ok content -> 283 let user_ids = List.filter_map (fun (uid, _) -> 284 match Matrix_proto.Id.User_id.of_string uid with 285 | Ok id -> Some id 286 | Error _ -> None 287 ) content.ignored_users in 288 Ok user_ids 289 290let ignore_user client ~user_id = 291 match get_ignored_users client with 292 | Error e -> Error e 293 | Ok current -> 294 let user_id_str = Matrix_proto.Id.User_id.to_string user_id in 295 if List.exists (fun u -> Matrix_proto.Id.User_id.to_string u = user_id_str) current then 296 Ok () (* Already ignored *) 297 else 298 let new_list = user_id :: current in 299 let ignored_map = List.map (fun u -> 300 (Matrix_proto.Id.User_id.to_string u, Jsont.Json.object' []) 301 ) new_list in 302 let content = { ignored_users = ignored_map } in 303 match Client.encode_body ignored_users_content_jsont content with 304 | Error e -> Error e 305 | Ok body -> 306 match Client.decode_response Jsont.json body with 307 | Error e -> Error e 308 | Ok json -> 309 set_account_data client ~event_type:"m.ignored_user_list" ~content:json 310 311let unignore_user client ~user_id = 312 match get_ignored_users client with 313 | Error e -> Error e 314 | Ok current -> 315 let user_id_str = Matrix_proto.Id.User_id.to_string user_id in 316 let new_list = List.filter (fun u -> 317 Matrix_proto.Id.User_id.to_string u <> user_id_str 318 ) current in 319 let ignored_map = List.map (fun u -> 320 (Matrix_proto.Id.User_id.to_string u, Jsont.Json.object' []) 321 ) new_list in 322 let content = { ignored_users = ignored_map } in 323 match Client.encode_body ignored_users_content_jsont content with 324 | Error e -> Error e 325 | Ok body -> 326 match Client.decode_response Jsont.json body with 327 | Error e -> Error e 328 | Ok json -> 329 set_account_data client ~event_type:"m.ignored_user_list" ~content:json