7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 1 | // Copyright 2024 The Matrix.org Foundation C.I.C. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 2 | // Copyright 2024 Hanadi Tamimi |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 3 | // |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 5 | // you may not use this file except in compliance with the License. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 6 | // You may obtain a copy of the License at |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 7 | // |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 8 | // http://www.apache.org/licenses/LICENSE-2.0 |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 9 | // |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 10 | // Unless required by applicable law or agreed to in writing, software |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 11 | // distributed under the License is distributed on an "AS IS" BASIS, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 13 | // See the License for the specific language governing permissions and |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 14 | // limitations under the License. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 15 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 16 | //! High-level pusher API. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 17 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 18 | use ruma::api::client::push::{PusherIds, set_pusher}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 19 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 20 | use crate::{Client, Result}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 21 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 22 | /// A high-level API to interact with the pusher API. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 23 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 24 | /// All the methods in this struct send a request to the homeserver. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 25 | #[derive(Debug, Clone)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 26 | pub struct Pusher { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 27 | /// The underlying HTTP client. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 28 | client: Client, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 29 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 30 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 31 | impl Pusher { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 32 | pub(crate) fn new(client: Client) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 33 | Self { client } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 34 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 35 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 36 | /// Sets a given pusher. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 37 | pub async fn set(&self, pusher: ruma::api::client::push::Pusher, append: bool) -> Result<()> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 38 | let mut request = set_pusher::v3::Request::post(pusher); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 39 | if let set_pusher::v3::PusherAction::Post(data) = &mut request.action { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 40 | data.append = append; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 41 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 42 | self.client.send(request).await?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 43 | Ok(()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 44 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 45 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 46 | /// Deletes a pusher by its ids |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 47 | pub async fn delete(&self, pusher_ids: PusherIds) -> Result<()> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 48 | let request = set_pusher::v3::Request::delete(pusher_ids); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 49 | self.client.send(request).await?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 50 | Ok(()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 51 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 52 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 53 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 54 | // The http mocking library is not supported for wasm32 |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 55 | #[cfg(all(test, not(target_family = "wasm")))] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 56 | mod tests { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 57 | use matrix_sdk_test::{async_test, test_json}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 58 | use ruma::{ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 59 | api::client::push::{PusherIds, PusherInit, PusherKind}, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 60 | push::HttpPusherData, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 61 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 62 | use serde_json::json; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 63 | use wiremock::{ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 64 | Mock, MockServer, ResponseTemplate, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 65 | matchers::{body_partial_json, method, path}, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 66 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 67 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 68 | use crate::test_utils::logged_in_client; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 69 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 70 | async fn mock_api(server: MockServer) { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 71 | Mock::given(method("POST")) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 72 | .and(path("_matrix/client/r0/pushers/set")) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 73 | .respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::EMPTY)) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 74 | .mount(&server) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 75 | .await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 76 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 77 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 78 | fn dummy_pusher() -> PusherInit { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 79 | PusherInit { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 80 | ids: PusherIds::new("pushKey".to_owned(), "app_id".to_owned()), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 81 | app_display_name: "name".to_owned(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 82 | kind: PusherKind::Http(HttpPusherData::new("dummy".to_owned())), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 83 | lang: "EN".to_owned(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 84 | device_display_name: "name".to_owned(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 85 | profile_tag: None, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 86 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 87 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 88 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 89 | #[async_test] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 90 | async fn test_set_pusher() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 91 | let server = MockServer::start().await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 92 | let client = logged_in_client(Some(server.uri())).await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 93 | mock_api(server).await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 94 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 95 | let response = client.pusher().set(dummy_pusher().into(), false).await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 96 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 97 | assert!(response.is_ok()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 98 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 99 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 100 | #[async_test] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 101 | async fn test_set_pusher_forwards_append_flag() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 102 | let server = MockServer::start().await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 103 | let client = logged_in_client(Some(server.uri())).await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 104 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 105 | Mock::given(method("POST")) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 106 | .and(path("_matrix/client/r0/pushers/set")) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 107 | .and(body_partial_json(json!({ "append": true }))) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 108 | .respond_with(ResponseTemplate::new(200).set_body_json(&*test_json::EMPTY)) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 109 | .expect(1) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 110 | .mount(&server) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 111 | .await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 112 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 113 | let response = client.pusher().set(dummy_pusher().into(), true).await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 114 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 115 | assert!(response.is_ok()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 116 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 117 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 118 | #[async_test] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 119 | async fn test_delete_pusher() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 120 | let server = MockServer::start().await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 121 | let client = logged_in_client(Some(server.uri())).await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 122 | mock_api(server).await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 123 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 124 | // prepare pusher ids |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 125 | let pusher_ids = PusherIds::new("pushKey".to_owned(), "app_id".to_owned()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 126 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 127 | let response = client.pusher().delete(pusher_ids).await; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 128 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 129 | assert!(response.is_ok()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 130 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 131 | } |